diff --git a/Src/Dlhis.Message.Api/Dlhis.Message.Api.csproj b/Src/Dlhis.Message.Api/Dlhis.Message.Api.csproj new file mode 100644 index 00000000..4100a696 --- /dev/null +++ b/Src/Dlhis.Message.Api/Dlhis.Message.Api.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/Src/Dlhis.Message.Api/IDingTalkApi.cs b/Src/Dlhis.Message.Api/IDingTalkApi.cs new file mode 100644 index 00000000..7b7c7f17 --- /dev/null +++ b/Src/Dlhis.Message.Api/IDingTalkApi.cs @@ -0,0 +1,13 @@ +using Dlhis.Message.Api.Requests; +using Kurisu.RemoteCall.Attributes; + +namespace Dlhis.Message.Api; + +[RequestLog] +[RequestResultHandler] +[EnableRemoteClient(Name = "message-service", BaseUrl = "${InternalRequest:MessageRequestUrl}")] +public interface IDingTalkApi +{ + [Post("/api/messages/dingtalk/workmessage")] + Task SendWorkMessageAsync(JinkoSendWorkMessageRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Message.Api/Requests/JinkoSendWorkMessageRequest.cs b/Src/Dlhis.Message.Api/Requests/JinkoSendWorkMessageRequest.cs new file mode 100644 index 00000000..794621a5 --- /dev/null +++ b/Src/Dlhis.Message.Api/Requests/JinkoSendWorkMessageRequest.cs @@ -0,0 +1,14 @@ +namespace Dlhis.Message.Api.Requests; + +public class JinkoSendWorkMessageRequest +{ + /// + /// 发送内容 + /// + public string Content { get; set; } + + /// + /// 工号 + /// + public List WorkCodes { get; set; } +} \ No newline at end of file diff --git a/Src/Dlhis.Message/Controllers/MessagesController.cs b/Src/Dlhis.Message/Controllers/MessagesController.cs new file mode 100644 index 00000000..e56529b1 --- /dev/null +++ b/Src/Dlhis.Message/Controllers/MessagesController.cs @@ -0,0 +1,24 @@ +using Dlhis.Message.Services; +using Microsoft.AspNetCore.Mvc; + +namespace Dlhis.Message.Controllers; + + +[Route("api/[controller]")] +[ApiController] +public class MessagesController : ControllerBase +{ + private readonly IJinkoApiService _jinkoApiService; + + public MessagesController(IJinkoApiService jinkoApiService) + { + _jinkoApiService = jinkoApiService; + } + + + [HttpPost("dingtalk/workmessage")] + public async Task SendWorkMessageAsync(JinkoSendWorkMessageRequest request) + { + await _jinkoApiService.SendWorkMessageAsync(request); + } +} \ No newline at end of file diff --git a/Src/Dlhis.Message/Dlhis.Message.csproj b/Src/Dlhis.Message/Dlhis.Message.csproj index 4b57436f..2ebfed6c 100644 --- a/Src/Dlhis.Message/Dlhis.Message.csproj +++ b/Src/Dlhis.Message/Dlhis.Message.csproj @@ -2,7 +2,7 @@ net6.0 - enable + disable enable Linux ..\.. @@ -16,4 +16,10 @@ + + + appsettings.json + + + diff --git a/Src/Dlhis.Message/Program.cs b/Src/Dlhis.Message/Program.cs index 3c574499..36d1a96b 100644 --- a/Src/Dlhis.Message/Program.cs +++ b/Src/Dlhis.Message/Program.cs @@ -15,4 +15,51 @@ public class Startup : DefaultStartup { IdentityModelEventSource.ShowPII = true; } + + /// + public override void ConfigureServices(IServiceCollection services) + { + base.ConfigureServices(services); + + services.AddHttpClient("jinko.oa", (_, _) => { }) + .ConfigurePrimaryHttpMessageHandler(() => + { + var handler = new HttpClientHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + ServerCertificateCustomValidationCallback = (_, _, _, _) => true + }; + + return handler; + }); + + services.AddHttpClient("jinko.httpclient", (sp, httpClient) => + { + // "BaseUrl": "https://oapi.dingtalk.com", + // "AgentId": "2768073678", + // "AppId": "dingumelppews6rah7x9", + // "AppSecret": "nsWfJTVjYesHVzrLiP-t1TQqMQvC1L_kZNfXfnIyzcXK4pCTfKprkjZcxAbsDR_l", + + httpClient.BaseAddress = new Uri("https://oapi.dingtalk.com"); + httpClient.Timeout = TimeSpan.FromSeconds(30); + }) + // .SetHandlerLifetime(TimeSpan.FromMinutes(5)) + // .addd((res) => + // { + // return HttpPolicyExtensions + // .HandleTransientHttpError() + // .OrResult(msg => msg.StatusCode != HttpStatusCode.OK) + // .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + // }) + .ConfigurePrimaryHttpMessageHandler(() => + { + var handler = new HttpClientHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + ServerCertificateCustomValidationCallback = (_, _, _, _) => true + }; + + return handler; + }); + } } \ No newline at end of file diff --git a/Src/Dlhis.Message/Services/IJinkoApiService.cs b/Src/Dlhis.Message/Services/IJinkoApiService.cs new file mode 100644 index 00000000..94350ac0 --- /dev/null +++ b/Src/Dlhis.Message/Services/IJinkoApiService.cs @@ -0,0 +1,6 @@ +namespace Dlhis.Message.Services; + +public interface IJinkoApiService : ISingletonDependency +{ + Task SendWorkMessageAsync(JinkoSendWorkMessageRequest request); +} \ No newline at end of file diff --git a/Src/Dlhis.Message/Services/JinkoApiService.cs b/Src/Dlhis.Message/Services/JinkoApiService.cs new file mode 100644 index 00000000..329fcb99 --- /dev/null +++ b/Src/Dlhis.Message/Services/JinkoApiService.cs @@ -0,0 +1,99 @@ +using System.Text; +using Kurisu.AspNetCore.Utils.Extensions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Dlhis.Message.Services; + +public class JinkoApiService : IJinkoApiService +{ + private readonly IHttpClientFactory _httpClientFactory; + + public JinkoApiService(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + } + + public async Task GetTokenAsync() + { + var token = string.Empty; + if (string.IsNullOrEmpty(token)) + { + var httpClient = _httpClientFactory.CreateClient("jinko.httpclient"); + + var form = new FormUrlEncodedContent(new Dictionary + { + { "appkey", "dingumelppews6rah7x9" }, + { "appsecret", "nsWfJTVjYesHVzrLiP-t1TQqMQvC1L_kZNfXfnIyzcXK4pCTfKprkjZcxAbsDR_l" } + }); + + //appkey=dingumelppews6rah7x9&appsecret=nsWfJTVjYesHVzrLiP-t1TQqMQvC1L_kZNfXfnIyzcXK4pCTfKprkjZcxAbsDR_l + var response = await httpClient.GetStringAsync($"/gettoken?{await form.ReadAsStringAsync()}"); + var jObj = JObject.Parse(response); + (jObj.Value("errcode") == "0").ThrowIfFalse(jObj.Value("errmsg")); + + token = jObj.Value("access_token"); + } + + return token; + } + + + public async Task SendWorkMessageAsync(JinkoSendWorkMessageRequest request) + { + request.Content.IsEmpty().ThrowIfTrue("发送内容不能为空"); + var token = await GetTokenAsync(); + + var users = await GetJinkoOaInfoByWorkCodes(request.WorkCodes); + var userStringIds = string.Join(",", users.Select(x => x.Id)); + (userStringIds.Length > 100).ThrowIfTrue("超出消息接受人数,length > 100"); + + var body = new + { + agent_id = "2768073678", + userid_list = userStringIds, + msg = new + { + msgtype = "text", + text = new + { + content = request.Content + }, + }, + }.ToJson(); + + var httpClient = _httpClientFactory.CreateClient("jinko.httpclient"); + var url = $"/topapi/message/corpconversation/asyncsend_v2?access_token={token}"; + var content = new StringContent(body, Encoding.UTF8, "application/json"); + + var response = await httpClient.PostAsync(url, content); + var jsonResponse = await response.Content.ReadAsStringAsync(); + + //_logger.LogInformation("请求参数:{Request} \r\n 钉钉请求参数:{DingTalkRequest} \r\n 钉钉响应:{DingTalkResponse}", JsonConvert.SerializeObject(request), body, jsonResponse); + + var jObj = JObject.Parse(jsonResponse); + (jObj.Value("errcode") == "0").ThrowIfFalse(jObj.Value("errmsg")); + } + + + private async Task> GetJinkoOaInfoByWorkCodes(List codes) + { + var httpClient = _httpClientFactory.CreateClient("jinko.oa"); + + var body = new + { + token = "TTMlaplWIEjmJHiVShWybekyyNnJXDHD", + type = "workCode", + workCode = string.Join(",", codes) + }.ToJson(); + + var content = new StringContent(body, Encoding.UTF8, "application/json"); + var response = await httpClient.PostAsync("http://oa.jinkosolar.com/api/commonRequestService/getUserByWorkCode/v2", content); + var responseJson = await response.Content.ReadAsStringAsync(); + + var oaInfo = JsonConvert.DeserializeObject>>>(responseJson); + (oaInfo.Code == 200).ThrowIfFalse(oaInfo.Message); + + return oaInfo.Result.Data; + } +} \ No newline at end of file diff --git a/Src/Dlhis.Message/Services/JinkoOaResponse.cs b/Src/Dlhis.Message/Services/JinkoOaResponse.cs new file mode 100644 index 00000000..87d59646 --- /dev/null +++ b/Src/Dlhis.Message/Services/JinkoOaResponse.cs @@ -0,0 +1,22 @@ +namespace Dlhis.Message.Services +{ + public class JinkoOaResponse + { + public int Code { get; set; } + public string Message { get; set; } + public T Result { get; set; } + } + + public class JinkoData + { + public T Data { get; set; } + } + + + public class JinkoOaInfo + { + public int Id { get; set; } + public string Email { get; set; } + public string Lastname { get; set; } + } +} diff --git a/Src/Dlhis.Message/Services/JinkoSendWorkMessageRequest.cs b/Src/Dlhis.Message/Services/JinkoSendWorkMessageRequest.cs new file mode 100644 index 00000000..502dc60d --- /dev/null +++ b/Src/Dlhis.Message/Services/JinkoSendWorkMessageRequest.cs @@ -0,0 +1,14 @@ +namespace Dlhis.Message.Services; + +public class JinkoSendWorkMessageRequest +{ + /// + /// 发送内容 + /// + public string Content { get; set; } + + /// + /// 工号 + /// + public List WorkCodes { get; set; } +} \ No newline at end of file