From cbc70c5d0fe7e67e03df633ab3ceef649d2e8f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E8=81=AA?= Date: Fri, 21 Nov 2025 19:49:02 +0800 Subject: [PATCH] =?UTF-8?q?=E9=92=89=E9=92=89=E5=AF=B9=E6=8E=A5=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=AE=A1=E6=89=B9=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entity/DingTalkDept.cs | 45 ++++++++ .../Entity/DingTalkWokerflowConfig.cs | 23 ++++ .../Entity/DingTalkWokerflowLog.cs | 86 ++++++++++++++ .../Job/SyncDingTalkDeptJob.cs | 95 ++++++++++++++++ .../Job/SyncWokerflowLogJob.cs | 98 ++++++++++++++++ .../Service/DingTalkService.cs | 75 +++++++++++-- .../Service/Dto/DingTalkDeptOutput.cs | 30 +++++ .../Dto/DingTalkGetProcessInstancesOutput.cs | 73 ++++++++++++ .../DingTalkWorkflowProcessInstancesInput.cs | 105 ++++++++++++++++++ .../DingTalkWorkflowProcessInstancesOutput.cs | 27 +++++ .../Service/Dto/GetDingTalkDeptInput.cs | 12 ++ .../Service/IDingTalkApi.cs | 81 ++++++++++++-- 12 files changed, 731 insertions(+), 19 deletions(-) create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkDept.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowConfig.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowLog.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncDingTalkDeptJob.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncWokerflowLogJob.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkDeptOutput.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkGetProcessInstancesOutput.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesInput.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesOutput.cs create mode 100644 Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/GetDingTalkDeptInput.cs diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkDept.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkDept.cs new file mode 100644 index 000000000..1ef7949ca --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkDept.cs @@ -0,0 +1,45 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Plugin.DingTalk; + +/// +/// 钉钉部门信息 +/// +[SugarTable("ding_talk_dept", "钉钉部门表")] +public class DingTalkDept +{ + /// + /// 部门id + /// + [SugarColumn(ColumnName = "Id", ColumnDescription = "部门id", IsPrimaryKey = true, IsIdentity = false)] + [Required] + public long dept_id { get; set; } + /// + /// 上级部门id + /// + [SugarColumn(ColumnDescription = "上级部门id")] + [Required] + public virtual long parent_id { get; set; } + + /// + /// 部门名 + /// + [SugarColumn(ColumnDescription = "部门名", Length = 64)] + [MaxLength(64)] + public string? name { get; set; } + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间", IsNullable = true, IsOnlyIgnoreUpdate = true)] + public virtual DateTime CreateTime { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnDescription = "更新时间")] + public virtual DateTime? UpdateTime { get; set; } +} \ No newline at end of file diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowConfig.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowConfig.cs new file mode 100644 index 000000000..a363b05da --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowConfig.cs @@ -0,0 +1,23 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Plugin.DingTalk; + +[SugarTable("ding_talk_wokerflow_config", "审批配置表")] +public class DingTalkWokerflowConfig +{ + /// + /// 审批名 + /// + [SugarColumn(ColumnDescription = "审批名", IsPrimaryKey = true, IsIdentity = false)] + public string WorkflowName { get; set; } + + /// + /// 审批单Id + /// + [SugarColumn(ColumnDescription = "审批单Id")] + public string ProcessCode { get; set; } +} \ No newline at end of file diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowLog.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowLog.cs new file mode 100644 index 000000000..e8f4da204 --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Entity/DingTalkWokerflowLog.cs @@ -0,0 +1,86 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Plugin.DingTalk; + +[SugarTable("ding_talk_wokerflow_log", "钉钉审批日志")] +public class DingTalkWokerflowLog +{ + /// + /// 审批实例ID + /// + [SugarColumn(ColumnDescription = "审批实例ID", IsPrimaryKey = true, IsIdentity = false)] + public string instanceId { get; set; } + + /// + /// 审批单号 + /// + [SugarColumn(ColumnDescription = "审批单号")] + public string? WorkflowId { get; set; } + + /// + /// 来源单据 + /// + [SugarColumn(ColumnDescription = "来源单据")] + public string SourceDocument { get; set; } + + /// + /// 审批完成时间 + /// + [SugarColumn(ColumnDescription = "审批完成时间")] + public DateTime? EndTime { get; set; } + + /// + /// 其他信息 + /// + [SugarColumn(ColumnDescription = "其他信息", IsJson = true)] + public Dictionary? other_info { get; set; } + + /// + /// 是否回传结果给第三方 + /// + [SugarColumn(ColumnDescription = "是否回传结果")] + public bool? isReturn { get; set; } + + /// + /// 审批状态 + /// + /// + /// RUNNING:审批中 TERMINATED:已撤销 COMPLETED:审批完成 + /// /// + [SugarColumn(ColumnDescription = "审批状态")] + public string Status { get; set; } + + /// + /// 任务ID + /// + [SugarColumn(ColumnDescription = "任务ID")] + public long? taskId { get; set; } + + /// + /// 审批结果 agree:同意 refuse:拒绝 + /// + [SugarColumn(ColumnDescription = "审批结果")] + public string? Result { get; set; } + + /// + /// 创建者姓名 + /// + [SugarColumn(ColumnDescription = "创建者姓名", Length = 64, IsOnlyIgnoreUpdate = true)] + public string? CreateUserName { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间", IsNullable = true, IsOnlyIgnoreUpdate = true)] + public DateTime CreateTime { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnDescription = "更新时间")] + public virtual DateTime? UpdateTime { get; set; } +} diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncDingTalkDeptJob.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncDingTalkDeptJob.cs new file mode 100644 index 000000000..160aef84e --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncDingTalkDeptJob.cs @@ -0,0 +1,95 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +using Admin.NET.Plugin.DingTalk; +using Furion.Schedule; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Admin.NET.Plugin.Job; + +/// +/// 同步钉钉角色job,自动同步触发器请在web页面按需求设置 +/// +[JobDetail("SyncDingTalkDeptJob", Description = "同步钉钉部门", GroupName = "default", Concurrent = false)] +[Daily(TriggerId = "SyncDingTalkDeptTrigger", Description = "同步钉钉部门")] +public class SyncDingTalkDeptJob : IJob +{ + private readonly IServiceScopeFactory _scopeFactory; + private readonly IDingTalkApi _dingTalkApi; + private readonly ILogger _logger; + private readonly SqlSugarRepository 部门信息; + + public SyncDingTalkDeptJob( + IServiceScopeFactory scopeFactory, + IDingTalkApi dingTalkApi, + SqlSugarRepository _部门信息, + ILoggerFactory loggerFactory) + { + _scopeFactory = scopeFactory; + _dingTalkApi = dingTalkApi; + 部门信息 = _部门信息; + _logger = loggerFactory.CreateLogger(CommonConst.SysLogCategoryName); + } + + public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken) + { + using var serviceScope = _scopeFactory.CreateScope(); + var _dingTalkOptions = serviceScope.ServiceProvider.GetRequiredService>(); + + // 获取Token + var tokenRes = await _dingTalkApi.GetDingTalkToken(_dingTalkOptions.Value.ClientId, _dingTalkOptions.Value.ClientSecret); + if (tokenRes.ErrCode != 0) + throw Oops.Oh(tokenRes.ErrMsg); + + var dingTalkDeptList = new List(); + // 获取部门列表 + var deptIdsRes = await _dingTalkApi.GetDingTalkDept(tokenRes.AccessToken, new GetDingTalkDeptInput + { dept_id = 1 }); + if (deptIdsRes.ErrCode != 0) + { + _logger.LogError(deptIdsRes.ErrMsg); + throw Oops.Oh(deptIdsRes.ErrMsg); + } + dingTalkDeptList.AddRange(deptIdsRes.Result.Select(d => new DingTalkDept + { + dept_id = d.dept_id, + name = d.name, + parent_id = d.parent_id + })); + foreach (var item in deptIdsRes.Result) + { + dingTalkDeptList.AddRange(await 获取部门列表(tokenRes.AccessToken, item.dept_id)); + } + 部门信息.InsertOrUpdateAsync(dingTalkDeptList); + var originColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Blue; + Console.WriteLine("【" + DateTime.Now + "】同步钉钉部门"); + Console.ForegroundColor = originColor; + } + + private async Task> 获取部门列表(string token, long dept_id) + { + List listTemp = new List(); + var deptIdsRes = await _dingTalkApi.GetDingTalkDept(token, new GetDingTalkDeptInput + {dept_id= dept_id }); + if (deptIdsRes.ErrCode != 0) + { + return null; + } + listTemp.AddRange(deptIdsRes.Result.Select(x => new DingTalkDept + { + dept_id = x.dept_id, + name = x.name, + parent_id = x.parent_id + })); + foreach (var item in deptIdsRes.Result) + { + listTemp.AddRange(await 获取部门列表(token, item.dept_id)); + } + return listTemp; + } +} \ No newline at end of file diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncWokerflowLogJob.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncWokerflowLogJob.cs new file mode 100644 index 000000000..e45fd1988 --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Job/SyncWokerflowLogJob.cs @@ -0,0 +1,98 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +using Admin.NET.Plugin.DingTalk; +using Furion.Schedule; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Admin.NET.Plugin.Job; + +/// +/// 同步钉钉角色job,自动同步触发器请在web页面按需求设置 +/// +[JobDetail( + "SyncWokerflowLogJob", + Description = "同步钉钉审批状态", + GroupName = "default", + Concurrent = false +)] +[Daily(TriggerId = "SyncWokerflowLogTrigger", Description = "同步钉钉审批状态")] +public class SyncWokerflowLogJob : IJob +{ + private readonly IServiceScopeFactory _scopeFactory; + private readonly IDingTalkApi _dingTalkApi; + private readonly ILogger _logger; + private readonly SqlSugarRepository 部门信息; + private readonly SqlSugarRepository 钉钉审批记录; + + public SyncWokerflowLogJob( + IServiceScopeFactory scopeFactory, + IDingTalkApi dingTalkApi, + SqlSugarRepository _部门信息, + SqlSugarRepository _钉钉审批记录, + ILoggerFactory loggerFactory + ) + { + _scopeFactory = scopeFactory; + _dingTalkApi = dingTalkApi; + 部门信息 = _部门信息; + 钉钉审批记录 = _钉钉审批记录; + _logger = loggerFactory.CreateLogger(CommonConst.SysLogCategoryName); + } + + public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken) + { + using var serviceScope = _scopeFactory.CreateScope(); + var _dingTalkOptions = serviceScope.ServiceProvider.GetRequiredService< + IOptions + >(); + + // 获取Token + var tokenRes = await _dingTalkApi.GetDingTalkToken( + _dingTalkOptions.Value.ClientId, + _dingTalkOptions.Value.ClientSecret + ); + if (tokenRes.ErrCode != 0) + throw Oops.Oh(tokenRes.ErrMsg); + + var dingTalkDeptList = new List(); + // 获取未完成审批列表 + List flow_list = await 钉钉审批记录.GetListAsync(t => + t.Status == "RUNNING" + ); + List update_list = new List(); + if (flow_list?.Count > 0) + { + foreach (var item in flow_list) + { + var flow = await _dingTalkApi.GetProcessInstances( + tokenRes.AccessToken, + item.instanceId + ); + if (flow.Result.Status != item.Status) + { + item.Status = flow.Result.Status; + item.UpdateTime = DateTime.Now; + item.WorkflowId = flow.Result.BusinessId; + item.taskId = flow + .Result.Tasks.FirstOrDefault(t => t.Status == "RUNNING") + ?.TaskId; + update_list.Add(item); + } + } + + if (update_list.Count > 0) + { + 钉钉审批记录.UpdateRangeAsync(update_list); + } + var originColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Blue; + Console.WriteLine("【" + DateTime.Now + "】同步钉钉审批记录状态"); + Console.ForegroundColor = originColor; + } + } +} \ No newline at end of file diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs index 2d362f38b..e0f2df097 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/DingTalkService.cs @@ -4,6 +4,8 @@ // // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! +using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinExpressIntracityQueryFlowResponse.Types; + namespace Admin.NET.Plugin.DingTalk.Service; /// @@ -14,12 +16,17 @@ public class DingTalkService : IDynamicApiController, IScoped { private readonly IDingTalkApi _dingTalkApi; private readonly DingTalkOptions _dingTalkOptions; + private readonly SqlSugarRepository 钉钉审批记录; - public DingTalkService(IDingTalkApi dingTalkApi, - IOptions dingTalkOptions) + public DingTalkService( + IDingTalkApi dingTalkApi, + IOptions dingTalkOptions, + SqlSugarRepository _钉钉审批记录 + ) { _dingTalkApi = dingTalkApi; _dingTalkOptions = dingTalkOptions.Value; + 钉钉审批记录 = _钉钉审批记录; } /// @@ -29,7 +36,10 @@ public class DingTalkService : IDynamicApiController, IScoped [DisplayName("获取企业内部应用的access_token")] public async Task GetDingTalkToken() { - var tokenRes = await _dingTalkApi.GetDingTalkToken(_dingTalkOptions.ClientId, _dingTalkOptions.ClientSecret); + var tokenRes = await _dingTalkApi.GetDingTalkToken( + _dingTalkOptions.ClientId, + _dingTalkOptions.ClientSecret + ); if (tokenRes.ErrCode != 0) { throw Oops.Oh(tokenRes.ErrMsg); @@ -44,7 +54,12 @@ public class DingTalkService : IDynamicApiController, IScoped /// /// [HttpPost, DisplayName("获取在职员工列表")] - public async Task> GetDingTalkCurrentEmployeesList(string access_token, [Required] GetDingTalkCurrentEmployeesListInput input) + public async Task< + DingTalkBaseResponse + > GetDingTalkCurrentEmployeesList( + string access_token, + [Required] GetDingTalkCurrentEmployeesListInput input + ) { return await _dingTalkApi.GetDingTalkCurrentEmployeesList(access_token, input); } @@ -56,7 +71,12 @@ public class DingTalkService : IDynamicApiController, IScoped /// /// [HttpPost, DisplayName("获取员工花名册字段信息")] - public async Task>> GetDingTalkCurrentEmployeesRosterList(string access_token, [Required] GetDingTalkCurrentEmployeesRosterListInput input) + public async Task< + DingTalkBaseResponse> + > GetDingTalkCurrentEmployeesRosterList( + string access_token, + [Required] GetDingTalkCurrentEmployeesRosterListInput input + ) { return await _dingTalkApi.GetDingTalkCurrentEmployeesRosterList(access_token, input); } @@ -68,7 +88,10 @@ public class DingTalkService : IDynamicApiController, IScoped /// /// [DisplayName("给指定用户发送钉钉互动卡片")] - public async Task DingTalkSendInteractiveCards(string token, DingTalkSendInteractiveCardsInput input) + public async Task DingTalkSendInteractiveCards( + string token, + DingTalkSendInteractiveCardsInput input + ) { return await _dingTalkApi.DingTalkSendInteractiveCards(token, input); } @@ -80,8 +103,44 @@ public class DingTalkService : IDynamicApiController, IScoped /// /// [DisplayName("给指定用户发送钉钉消息卡片")] - public async Task DingTalkCreateAndDeliver(string token, DingTalkCreateAndDeliverInput input) + public async Task DingTalkCreateAndDeliver( + string token, + DingTalkCreateAndDeliverInput input + ) { return await _dingTalkApi.DingTalkCreateAndDeliver(token, input); } -} \ No newline at end of file + + [DisplayName("用于发起OA审批实例")] + public async Task DingTalkWorkflowProcessInstances( + string token, + DingTalkWorkflowProcessInstancesInput input + ) + { + var temp = await _dingTalkApi.DingTalkWorkflowProcessInstances(token, input); + return temp; + } + + [DisplayName("查询审批实例")] + public async Task DingTalkWorkflowProcessInstances( + string token, + string input + ) + { + var temp = await _dingTalkApi.GetProcessInstances(token, input); + DingTalkWokerflowLog flow = await 钉钉审批记录.GetFirstAsync(t => + t.Status == "RUNNING" && t.instanceId == input + ); + + if ((flow != null) && (temp.Result.Status != flow.Status)) + { + flow.Status = temp.Result.Status; + flow.UpdateTime = DateTime.Now; + flow.WorkflowId = temp.Result.BusinessId; + flow.Result = temp.Result.Result; + flow.taskId = temp.Result.Tasks.FirstOrDefault(t => t.Status == "RUNNING")?.TaskId; + 钉钉审批记录.UpdateAsync(flow); + } + return temp; + } +} diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkDeptOutput.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkDeptOutput.cs new file mode 100644 index 000000000..775318a1f --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkDeptOutput.cs @@ -0,0 +1,30 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + + +namespace Admin.NET.Plugin.DingTalk; +public class DingTalkDeptOutput +{ + + /// + /// 上级部门Id + /// + [JsonProperty("parent_id")] + [System.Text.Json.Serialization.JsonPropertyName("parent_id")] + public long parent_id { get; set; } + /// + /// 部门名 + /// + [JsonProperty("name")] + [System.Text.Json.Serialization.JsonPropertyName("name")] + public string name { get; set; } + /// + /// 部门Id + /// + [JsonProperty("dept_id")] + [System.Text.Json.Serialization.JsonPropertyName("dept_id")] + public long dept_id { get; set; } +} diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkGetProcessInstancesOutput.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkGetProcessInstancesOutput.cs new file mode 100644 index 000000000..bf50ec12d --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkGetProcessInstancesOutput.cs @@ -0,0 +1,73 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Plugin.DingTalk; + +public class DingTalkGetProcessInstancesOutput +{ + public ResultData Result { get; set; } + public bool Success { get; set; } +} + +public class OperationRecord +{ + public DateTime? Date { get; set; } + public string Result { get; set; } + public List Images { get; set; } // 图片可能是字符串 URL 或对象 + public string ShowName { get; set; } + public string Type { get; set; } + public string UserId { get; set; } +} + +// 表格行中的子项(用于 TableField 的解析) +public class TableRowItem +{ + public string BizAlias { get; set; } + public string Label { get; set; } + public string Value { get; set; } + public string Key { get; set; } + public bool Mask { get; set; } +} + +// 完整的一行表格数据 +public class TableRow +{ + public List RowValue { get; set; } + public string RowNumber { get; set; } +} + +public class TaskItem +{ + public string Result { get; set; } + public string ActivityId { get; set; } + public string PcUrl { get; set; } + public DateTime? CreateTime { get; set; } + public string MobileUrl { get; set; } + public string UserId { get; set; } + public long TaskId { get; set; } + public string Status { get; set; } +} + +public class ResultData +{ + public List AttachedProcessInstanceIds { get; set; } + public string BusinessId { get; set; } + public string Title { get; set; } + public string OriginatorDeptId { get; set; } + public List OperationRecords { get; set; } + public List FormComponentValues { get; set; } + + /// + /// 审批结果 agree:同意 refuse:拒绝 + /// + public string Result { get; set; } + public string BizAction { get; set; } + public DateTime? CreateTime { get; set; } + public string OriginatorUserId { get; set; } + public List Tasks { get; set; } + public string OriginatorDeptName { get; set; } + public string Status { get; set; } +} diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesInput.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesInput.cs new file mode 100644 index 000000000..829e80294 --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesInput.cs @@ -0,0 +1,105 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Plugin.DingTalk; + +public class DingTalkWorkflowProcessInstancesInput +{ + /// + /// 发起人用户ID + /// + public string OriginatorUserId { get; set; } + + /// + /// 审批模板的流程编码 + /// + public string ProcessCode { get; set; } + + /// + /// 部门ID + /// + public long DeptId { get; set; } + + /// + /// 微应用AgentId + /// + public long MicroappAgentId { get; set; } + + /// + /// 审批人列表(支持多节点) + /// + public List Approvers { get; set; } + + /// + /// 抄送人列表 + /// + public List CcList { get; set; } + + /// + /// 抄送位置:START(开始),MIDDLE(中间),END(结束) + /// + public string CcPosition { get; set; } + + /// + /// 目标动态选择办理人(用于会签或或签等场景) + /// + public List TargetSelectActioners { get; set; } + + /// + /// 表单组件值列表 + /// + public List FormComponentValues { get; set; } + + /// + /// 请求ID,用于幂等控制 + /// + public string RequestId { get; set; } +} + +/// +/// 审批人信息 +/// +public class Approver +{ + /// + /// 节点类型:AGREE(同意),REFUSE(拒绝)等 + /// + public string ActionType { get; set; } + + /// + /// 该节点的审批人用户ID列表 + /// + public List UserIds { get; set; } +} + +/// +/// 动态选择办理人 +/// +public class TargetSelectActioner +{ + /// + /// 办理人Key,对应表单中的人员选择控件的key + /// + public string ActionerKey { get; set; } + + /// + /// 该控件选中的用户ID列表 + /// + public List ActionerUserIds { get; set; } +} + +/// +/// 表单组件值 +/// +public class FormComponentValue +{ + public string ComponentType { get; set; } + public string Name { get; set; } + public string BizAlias { get; set; } + public string Id { get; set; } + public string Value { get; set; } + public string ExtValue { get; set; } +} diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesOutput.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesOutput.cs new file mode 100644 index 000000000..bca716b23 --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/DingTalkWorkflowProcessInstancesOutput.cs @@ -0,0 +1,27 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + +namespace Admin.NET.Plugin.DingTalk; + +public class DingTalkWorkflowProcessInstancesOutput +{ + /// + /// 请求Id + /// + [Newtonsoft.Json.JsonProperty("request_id")] + [System.Text.Json.Serialization.JsonPropertyName("request_id")] + public string RequestId { get; set; } + + public string code { get; set; } + public string message { get; set; } + + /// + /// 是否还有更多数据 + /// + [JsonProperty("instanceId")] + [System.Text.Json.Serialization.JsonPropertyName("instanceId")] + public string instanceId { get; set; } +} \ No newline at end of file diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/GetDingTalkDeptInput.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/GetDingTalkDeptInput.cs new file mode 100644 index 000000000..3482c6948 --- /dev/null +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/Dto/GetDingTalkDeptInput.cs @@ -0,0 +1,12 @@ +// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 +// +// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 +// +// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + + +namespace Admin.NET.Plugin.DingTalk; +public class GetDingTalkDeptInput +{ + public long dept_id { get; set; } +} diff --git a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/IDingTalkApi.cs b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/IDingTalkApi.cs index 4695433e2..aeba716d0 100644 --- a/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/IDingTalkApi.cs +++ b/Admin.NET/Plugins/Admin.NET.Plugin.DingTalk/Service/IDingTalkApi.cs @@ -24,8 +24,13 @@ public interface IDingTalkApi : IHttpDeclarative /// /// [Post("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/queryonjob")] - Task> GetDingTalkCurrentEmployeesList([Query] string access_token, - [Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentEmployeesListInput input); + Task< + DingTalkBaseResponse + > GetDingTalkCurrentEmployeesList( + [Query] string access_token, + [Body(ContentType = "application/json", UseStringContent = true), Required] + GetDingTalkCurrentEmployeesListInput input + ); /// /// 获取员工花名册字段信息 @@ -34,8 +39,13 @@ public interface IDingTalkApi : IHttpDeclarative /// /// [Post("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list")] - Task>> GetDingTalkCurrentEmployeesRosterList([Query] string access_token, - [Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentEmployeesRosterListInput input); + Task< + DingTalkBaseResponse> + > GetDingTalkCurrentEmployeesRosterList( + [Query] string access_token, + [Body(ContentType = "application/json", UseStringContent = true), Required] + GetDingTalkCurrentEmployeesRosterListInput input + ); /// /// 发送钉钉互动卡片 @@ -51,7 +61,9 @@ public interface IDingTalkApi : IHttpDeclarative [Obsolete] Task DingTalkSendInteractiveCards( [Header("x-acs-dingtalk-access-token")] string token, - [Body(ContentType = "application/json", UseStringContent = true)] DingTalkSendInteractiveCardsInput input); + [Body(ContentType = "application/json", UseStringContent = true)] + DingTalkSendInteractiveCardsInput input + ); /// /// 获取钉钉卡片消息读取状态 @@ -62,7 +74,8 @@ public interface IDingTalkApi : IHttpDeclarative [Get("https://api.dingtalk.com/v1.0/robot/oToMessages/readStatus")] Task GetDingTalkCardMessageReadStatus( [Header("x-acs-dingtalk-access-token")] string token, - [Query] GetDingTalkCardMessageReadStatusInput input); + [Query] GetDingTalkCardMessageReadStatusInput input + ); /// /// 获取角色列表 @@ -71,8 +84,11 @@ public interface IDingTalkApi : IHttpDeclarative /// /// [Post("https://oapi.dingtalk.com/topapi/role/list")] - Task> GetDingTalkRoleList([Query] string access_token, - [Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentRoleListInput input); + Task> GetDingTalkRoleList( + [Query] string access_token, + [Body(ContentType = "application/json", UseStringContent = true), Required] + GetDingTalkCurrentRoleListInput input + ); /// /// 获取指定角色的员工列表 @@ -81,8 +97,11 @@ public interface IDingTalkApi : IHttpDeclarative /// /// [Post("https://oapi.dingtalk.com/topapi/role/simplelist")] - Task> GetDingTalkRoleSimplelist([Query] string access_token, - [Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentRoleSimplelistInput input); + Task> GetDingTalkRoleSimplelist( + [Query] string access_token, + [Body(ContentType = "application/json", UseStringContent = true), Required] + GetDingTalkCurrentRoleSimplelistInput input + ); /// /// 创建并投放钉钉消息卡片 @@ -93,5 +112,45 @@ public interface IDingTalkApi : IHttpDeclarative [Post("https://api.dingtalk.com/v1.0/card/instances/createAndDeliver")] Task DingTalkCreateAndDeliver( [Header("x-acs-dingtalk-access-token")] string token, - [Body(ContentType = "application/json", UseStringContent = true)] DingTalkCreateAndDeliverInput input); + [Body(ContentType = "application/json", UseStringContent = true)] + DingTalkCreateAndDeliverInput input + ); + + /// + /// 获取部门列表列表 + /// + /// 调用该接口的应用凭证 + /// + /// + [Post("https://oapi.dingtalk.com/topapi/v2/department/listsub")] + Task>> GetDingTalkDept( + [Query] string access_token, + [Body(ContentType = "application/json", UseStringContent = true), Required] + GetDingTalkDeptInput input + ); + + /// + /// 发起审批实例 + /// + /// 用于发起OA审批实例 + /// + /// + [Post("https://api.dingtalk.com/v1.0/workflow/processInstances")] + Task DingTalkWorkflowProcessInstances( + [Header("x-acs-dingtalk-access-token")] string token, + [Body(ContentType = "application/json", UseStringContent = true), Required] + DingTalkWorkflowProcessInstancesInput input + ); + + /// + /// 查询审批实例 + /// + /// + /// 审批实例Id + /// + [Get("https://api.dingtalk.com/v1.0/workflow/processInstances")] + Task GetProcessInstances( + [Header("x-acs-dingtalk-access-token")] string token, + [Query] string processInstanceId + ); } \ No newline at end of file -- Gitee