😎1、优化钉钉接口服务 2、优化行政区划接口服务 3、增加token黑名单 4、事件消费增加重试 5、优化租户接口服务 6、升级依赖

This commit is contained in:
zuohuaijun 2025-05-29 13:20:28 +08:00
parent f3c49e1f42
commit 50f024644b
23 changed files with 605 additions and 24 deletions

View File

@ -27,7 +27,7 @@
//],
"DbSettings": {
"EnableInitDb": true, //
"EnableInitView": true, //
"EnableInitView": true, //
"EnableDiffLog": false, //
"EnableUnderLine": false, // 线
"EnableConnEncrypt": false // SM2

View File

@ -31,7 +31,7 @@
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.76" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.76" />
<PackageReference Include="Furion.Pure" Version="4.9.7.76" />
<PackageReference Include="Hardware.Info" Version="101.0.1" />
<PackageReference Include="Hardware.Info" Version="101.0.1.1" />
<PackageReference Include="Hashids.net" Version="1.7.0" />
<PackageReference Include="IPTools.China" Version="1.6.0" />
<PackageReference Include="IPTools.International" Version="1.6.0" />
@ -54,9 +54,9 @@
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.12.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.193" />
<PackageReference Include="SSH.NET" Version="2025.0.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.4" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.5" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1249" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1250" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>

View File

@ -16,6 +16,11 @@ public class CacheConst
/// </summary>
public const string KeyUserToken = "sys_user_token:";
/// <summary>
/// Token黑名单
/// </summary>
public const string KeyTokenBlacklist = "sys_token_blacklist:";
/// <summary>
/// 用户接口缓存(接口集合)
/// </summary>

View File

@ -12,7 +12,7 @@ namespace Admin.NET.Core;
[SugarTable(null, "系统行政地区表")]
[SysTable]
[SugarIndex("index_{table}_N", nameof(Name), OrderByType.Asc)]
[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc, IsUnique = true)]
public partial class SysRegion : EntityBaseId
{
/// <summary>

View File

@ -54,13 +54,21 @@ public class EventConsumer<T> : IDisposable
}
_consumerCts = new CancellationTokenSource();
var ct = _consumerCts.Token;
_consumerTask = Task.Factory.StartNew(() =>
_consumerTask = Task.Factory.StartNew(async () =>
{
while (!ct.IsCancellationRequested)
{
var cr = Consumer.TakeOne(10);
if (cr == null) continue;
Received?.Invoke(this, cr);
try
{
var cr = Consumer.TakeOne(10);
if (cr == null) continue;
Received?.Invoke(this, cr);
}
catch (Exception ex)
{
Console.WriteLine($"消息消费异常: {ex.Message}");
await Task.Delay(1000);
}
}
}, ct, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}

View File

@ -343,10 +343,17 @@ public class SysAuthService : IDynamicApiController, ITransient
[DisplayName("退出系统")]
public async void Logout()
{
if (string.IsNullOrWhiteSpace(_userManager.Account))
var httpContext = _httpContextAccessor.HttpContext ?? throw Oops.Oh(ErrorCodeEnum.D1016);
var accessToken = httpContext.Request.Headers.Authorization.ToString();
if (string.IsNullOrWhiteSpace(accessToken) || string.IsNullOrWhiteSpace(_userManager.Account))
throw Oops.Oh(ErrorCodeEnum.D1011);
// 发布系统退出事件
// 写入Token黑名单
var tokenExpire = await _sysConfigService.GetTokenExpire();
_sysCacheService.Set($"{CacheConst.KeyTokenBlacklist}:{accessToken}", _userManager.Account, TimeSpan.FromMinutes(tokenExpire));
// 发布系统退出事件
await _eventPublisher.PublishAsync(UserEventTypeEnum.Logout, _userManager);
// 退出Swagger/设置无效Token响应头

View File

@ -203,7 +203,7 @@ public class SysRegionService : IDynamicApiController, ITransient
Level = 1,
Pid = 0,
};
if (municipalityList.Any(m => province.Name.StartsWith(m))) province.Name += "(省)";
//if (municipalityList.Any(u => province.Name.StartsWith(u))) province.Name += "(省)";
list.Add(province);
if (input.Level <= 1) continue;
@ -221,7 +221,11 @@ public class SysRegionService : IDynamicApiController, ITransient
Name = cityName,
Level = 2
};
if (municipalityList.Any(m => city.Name.StartsWith(m))) city.Name += "(地)";
if (municipalityList.Any(u => city.Name.StartsWith(u)))
{
city.Name = "市辖区";
if (province.Code == city.Code) city.Code = province.Code.Substring(0, 2) + "0100";
}
list.Add(city);
if (input.Level <= 2) continue;

View File

@ -76,8 +76,8 @@ public class SysTenantService : IDynamicApiController, ITransient
public async Task<SqlSugarPagedList<TenantOutput>> Page(PageTenantInput input)
{
return await _sysTenantRep.AsQueryable()
.LeftJoin<SysUser>((u, a) => u.UserId == a.Id)
.LeftJoin<SysOrg>((u, a, b) => u.OrgId == b.Id)
.LeftJoin<SysUser>((u, a) => u.UserId == a.Id).ClearFilter()
.LeftJoin<SysOrg>((u, a, b) => u.OrgId == b.Id).ClearFilter()
.WhereIF(!string.IsNullOrWhiteSpace(input.Phone), (u, a) => a.Phone.Contains(input.Phone.Trim()))
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), (u, a, b) => b.Name.Contains(input.Name.Trim()))
.WhereIF(!input.IncludeDefault, u => u.Id.ToString() != SqlSugarConst.MainConfigId) // 排除默认主库/主租户

View File

@ -57,6 +57,15 @@ namespace Admin.NET.Web.Core
return;
}
// 验证Token黑名单
var accessToken = httpContext.Request.Headers.Authorization.ToString();
if (sysCacheService.ExistKey($"{CacheConst.KeyTokenBlacklist}:{accessToken}"))
{
context.Fail(new AuthorizationFailureReason(this, "令牌已失效,请重新登录。"));
context.GetCurrentHttpContext().SignoutToSwagger();
return;
}
// 验证Token版本号
var userId = httpContext.User.FindFirst(ClaimConst.UserId)?.Value;
var tokenVersion1 = httpContext.User.FindFirst(ClaimConst.TokenVersion)?.Value;

View File

@ -72,4 +72,16 @@ public class DingTalkService : IDynamicApiController, IScoped
{
return await _dingTalkApi.DingTalkSendInteractiveCards(token, input);
}
/// <summary>
/// 创建并投放钉钉消息卡片 🔖
/// </summary>
/// <param name="token"></param>
/// <param name="input"></param>
/// <returns></returns>
[DisplayName("给指定用户发送钉钉消息卡片")]
public async Task<DingTalkCreateAndDeliverOutput> DingTalkCreateAndDeliver(string token, DingTalkCreateAndDeliverInput input)
{
return await _dingTalkApi.DingTalkCreateAndDeliver(token, input);
}
}

View File

@ -0,0 +1,316 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class DingTalkCreateAndDeliverInput
{
/// <summary>
/// 卡片创建者的userId
/// </summary>
public string? userId { get; set; }
/// <summary>
/// 卡片内容模板ID
/// </summary>
[Required]
public string cardTemplateId { get; set; }
/// <summary>
/// 外部卡片实例Id
/// </summary>
[Required]
public string outTrackId { get; set; }
/// <summary>
/// 卡片回调的类型STREAMstream模式 HTTPhttp模式
/// </summary>
public string? callbackType { get; set; }
/// <summary>
/// 卡片回调HTTP模式时的路由 Key用于查询注册的 callbackUrl。
/// </summary>
public string? callbackRouteKey { get; set; }
/// <summary>
/// 卡片数据
/// </summary>
[Required]
public DingTalk_CardData cardData { get; set; }
/// <summary>
/// 用户的私有数据
/// </summary>
public PrivateData? crivateData { get; set; }
/// <summary>
/// 动态数据源配置
/// </summary>
public OpenDynamicDataConfig? openDynamicDataConfig { get; set; }
/// <summary>
/// IM单聊酷应用场域信息
/// </summary>
public OpenSpaceModel? imSingleOpenSpaceModel { get; set; }
/// <summary>
/// IM群聊场域信息。
/// </summary>
public OpenSpaceModel? imGroupOpenSpaceModel { get; set; }
/// <summary>
/// IM机器人单聊场域信息。
/// </summary>
public OpenSpaceModel? imRobotOpenSpaceModel { get; set; }
/// <summary>
/// 协作场域信息
/// </summary>
public OpenSpaceModel? coFeedOpenSpaceModel { get; set; }
/// <summary>
/// 吊顶场域信息
/// </summary>
public OpenSpaceModel? topOpenSpaceModel { get; set; }
/// <summary>
/// 表示场域及其场域id
/// </summary>
/// <remarks>
/// 其格式为dtv1.card//spaceType1.spaceId1;spaceType2.spaceId2_1;spaceType2.spaceId2_2;spaceType3.spaceId3
/// </remarks>
[Required]
public string openSpaceId { get; set; }
/// <summary>
/// 单聊酷应用场域投放参数。
/// </summary>
public DingTalkOpenDeliverModel? imSingleOpenDeliverModel { get; set; }
/// <summary>
/// 群聊投放参数。
/// </summary>
public DingTalkOpenDeliverModel? imGroupOpenDeliverModel { get; set; }
/// <summary>
/// IM机器人单聊投放参数。
/// </summary>
public DingTalkOpenDeliverModel? imRobotOpenDeliverModel { get; set; }
/// <summary>
/// 吊顶投放参数。
/// </summary>
public DingTalkOpenDeliverModel? topOpenDeliverModel { get; set; }
/// <summary>
/// 协作投放参数。
/// </summary>
public DingTalkOpenDeliverModel? coFeedOpenDeliverModel { get; set; }
/// <summary>
/// 文档投放参数
/// </summary>
public DingTalkOpenDeliverModel? docOpenDeliverModel { get; set; }
/// <summary>
/// 用户userId类型:1默认userId模式 2unionId模式
/// </summary>
public int UserIdType { get; set; }
}
public class DingTalk_CardData
{
public DingTalk_CardParamMap cardParamMap { get; set; }
}
/// <summary>
/// 卡片模板内容替换参数
/// </summary>
public class DingTalk_CardParamMap
{
/// <summary>
/// 片模板内容替换参数
/// </summary>
[Newtonsoft.Json.JsonProperty("sys_full_json_obj")]
[System.Text.Json.Serialization.JsonPropertyName("sys_full_json_obj")]
public string sysFullJsonObj { get; set; }
}
public class PrivateData
{
public Dictionary<string, DingTalk_CardParamMap> key { get; set; } = new Dictionary<string, DingTalk_CardParamMap>();
}
public class OpenDynamicDataConfig
{
/// <summary>
/// 动态数据源配置列表。
/// </summary>
public List<DynamicDataSourceConfig>? dynamicDataSourceConfigs { get; set; }
}
public class DynamicDataSourceConfig
{
/// <summary>
/// 数据源的唯一 ID, 调用方指定。
/// </summary>
public string? dynamicDataSourceId { get; set; }
/// <summary>
/// 回调数据源时回传的固定参数。 示例
/// </summary>
public Dictionary<string, string>? constParams { get; set; }
/// <summary>
/// 数据源拉取配置。
/// </summary>
public PullConfig? pullConfig { get; set; }
}
public class PullConfig
{
/// <summary>
/// 拉取策略可选值NONE不拉取无动态数据 INTERVAL间隔拉取ONCE只拉取一次
/// </summary>
public string pullStrategy { get; set; }
/// <summary>
/// 拉取的间隔时间。
/// </summary>
public int interval { get; set; }
/// <summary>
/// 拉取的间隔时间的单位, 可选值SECONDS秒 MINUTES分钟 HOURS小时 DAYS
/// </summary>
public string timeUnit { get; set; }
}
public class OpenSpaceModel
{
/// <summary>
/// 吊顶场域属性通过增加spaeType使卡片支持吊顶场域。
/// </summary>
public string? spaceType { get; set; }
/// <summary>
/// 卡片标题。
/// </summary>
public string? title { get; set; }
/// <summary>
/// 酷应用编码。
/// </summary>
public string? coolAppCode { get; set; }
/// <summary>
/// 是否支持转发, 默认false。
/// </summary>
public bool? supportForward { get; set; }
/// <summary>
/// 支持国际化的LastMessage。
/// </summary>
public Dictionary<string, string>? lastMessageI18n { get; set; }
/// <summary>
/// 支持卡片消息可被搜索字段。
/// </summary>
public SearchSupport? searchSupport { get; set; }
/// <summary>
/// 通知信息。
/// </summary>
public Notification? notification { get; set; }
}
public class SearchSupport
{
/// <summary>
/// 类型的icon供搜索展示使用。
/// </summary>
public string searchIcon { get; set; }
/// <summary>
/// 卡片类型名。
/// </summary>
public string searchTypeName { get; set; }
/// <summary>
/// 供消息展示与搜索的字段。
/// </summary>
public string searchDesc { get; set; }
}
public class Notification
{
/// <summary>
/// 供消息展示与搜索的字段。
/// </summary>
public string alertContent { get; set; }
/// <summary>
/// 是否关闭推送通知true关闭 false不关闭
/// </summary>
public bool notificationOff { get; set; }
}
public class DingTalkOpenDeliverModel
{
/// <summary>
/// 用于发送卡片的机器人编码。
/// </summary>
public string robotCode { get; set; }
/// <summary>
/// 消息@人。格式:{"key":"value"}。key用户的userId value用户名
/// </summary>
public Dictionary<string, string> atUserIds { get; set; }
/// <summary>
/// 指定接收人的userId。
/// </summary>
public List<string> recipients { get; set; }
/// <summary>
/// 扩展字段,示例如下:{"key":"value"}
/// </summary>
public Dictionary<string, string> extension { get; set; }
/// <summary>
/// IM机器人单聊若未设置其他投放属性需设置spaeType为IM_ROBOT。
/// </summary>
public string spaceType { get; set; }
/// <summary>
/// 过期时间戳。若使用topOpenDeliverModel对象则该字段必填。
/// </summary>
public long expiredTimeMillis { get; set; }
/// <summary>
/// 可以查看该吊顶卡片的userId。
/// </summary>
public List<string> userIds { get; set; }
/// <summary>
/// 可以查看该吊顶卡片的设备androidioswinmac。
/// </summary>
public List<string> platforms { get; set; }
/// <summary>
/// 业务标识。
/// </summary>
public string bizTag { get; set; }
/// <summary>
/// 协作场域下的排序时间。
/// </summary>
public long gmtTimeLine { get; set; }
/// <summary>
/// 员工userId信息
/// </summary>
public string userId { get; set; }
}

View File

@ -0,0 +1,32 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class DingTalkCreateAndDeliverOutput
{
/// <summary>
/// 返回结果
/// </summary>
public bool success { get; set; }
/// <summary>
/// 创建卡片结果
/// </summary>
public DingTalkCreateAndDeliverResult result { get; set; }
public string code { get; set; }
public string requestid { get; set; }
public string message { get; set; }
}
public class DingTalkCreateAndDeliverResult
{
/// <summary>
/// 用于业务方后续查看已读列表的查询key
/// </summary>
public string processQueryKey { get; set; }
}

View File

@ -0,0 +1,24 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class DingTalkRoleListOutput
{
/// <summary>
/// 是否还有更多数据
/// </summary>
[JsonProperty("hasMore")]
[System.Text.Json.Serialization.JsonPropertyName("hasMore")]
public bool hasMore { get; set; }
/// <summary>
/// 角色组列表
/// </summary>
[JsonProperty("list")]
[System.Text.Json.Serialization.JsonPropertyName("list")]
public List<DingTalkRoleListResult> list { get; set; }
}

View File

@ -0,0 +1,22 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class DingTalkRoleListResult
{
[JsonProperty("groupId")]
[System.Text.Json.Serialization.JsonPropertyName("groupId")]
public long groupId { get; set; }
[JsonProperty("name")]
[System.Text.Json.Serialization.JsonPropertyName("name")]
public string name { get; set; }
[JsonProperty("roles")]
[System.Text.Json.Serialization.JsonPropertyName("roles")]
public List<DingTalkRoleResult> roles { get; set; }
}

View File

@ -0,0 +1,18 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class DingTalkRoleResult
{
[JsonProperty("id")]
[System.Text.Json.Serialization.JsonPropertyName("id")]
public long id { get; set; }
[JsonProperty("name")]
[System.Text.Json.Serialization.JsonPropertyName("name")]
public string name { get; set; }
}

View File

@ -0,0 +1,24 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class DingTalkRoleSimplelistOutput
{
/// <summary>
/// 是否还有更多数据
/// </summary>
[JsonProperty("hasMore")]
[System.Text.Json.Serialization.JsonPropertyName("hasMore")]
public bool hasMore { get; set; }
/// <summary>
/// 角色组列表
/// </summary>
[JsonProperty("list")]
[System.Text.Json.Serialization.JsonPropertyName("list")]
public List<DingTalkRoleSimplelistResult> list { get; set; }
}

View File

@ -0,0 +1,18 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class DingTalkRoleSimplelistResult
{
[JsonProperty("userid")]
[System.Text.Json.Serialization.JsonPropertyName("userid")]
public string userid { get; set; }
[JsonProperty("name")]
[System.Text.Json.Serialization.JsonPropertyName("name")]
public string name { get; set; }
}

View File

@ -0,0 +1,20 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class GetDingTalkCurrentRoleListInput
{
/// <summary>
/// 分页游标从0开始。根据返回结果里的next_cursor是否为空来判断是否还有下一页且再次调用时offset设置成next_cursor的值。
/// </summary>
public int? Offset { get; set; }
/// <summary>
/// 分页大小最大50。
/// </summary>
public int? Size { get; set; }
}

View File

@ -0,0 +1,25 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Plugin.DingTalk;
public class GetDingTalkCurrentRoleSimplelistInput
{
/// <summary>
/// 角色id
/// </summary>
public long role_id { get; set; }
/// <summary>
/// 分页游标从0开始。根据返回结果里的next_cursor是否为空来判断是否还有下一页且再次调用时offset设置成next_cursor的值。
/// </summary>
public int? Offset { get; set; }
/// <summary>
/// 分页大小最大50。
/// </summary>
public int? Size { get; set; }
}

View File

@ -25,7 +25,7 @@ public interface IDingTalkApi : IHttpDeclarative
/// <returns></returns>
[Post("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/queryonjob")]
Task<DingTalkBaseResponse<GetDingTalkCurrentEmployeesListOutput>> GetDingTalkCurrentEmployeesList([Query] string access_token,
[Body, Required] GetDingTalkCurrentEmployeesListInput input);
[Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentEmployeesListInput input);
/// <summary>
/// 获取员工花名册字段信息
@ -35,7 +35,7 @@ public interface IDingTalkApi : IHttpDeclarative
/// <returns></returns>
[Post("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list")]
Task<DingTalkBaseResponse<List<DingTalkEmpRosterFieldVo>>> GetDingTalkCurrentEmployeesRosterList([Query] string access_token,
[Body, Required] GetDingTalkCurrentEmployeesRosterListInput input);
[Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentEmployeesRosterListInput input);
/// <summary>
/// 发送钉钉互动卡片
@ -43,10 +43,15 @@ public interface IDingTalkApi : IHttpDeclarative
/// <param name="token">调用该接口的访问凭证</param>
/// <param name="input"></param>
/// <returns></returns>
/// <remarks>
/// 钉钉官方文档显示接口不再支持新应用接入, 已接入的应用可继续调用
/// 推荐更新接口https://open.dingtalk.com/document/orgapp/create-and-deliver-cards?spm=ding_open_doc.document.0.0.67fc50988Pf0mc
/// </remarks>
[Post("https://api.dingtalk.com/v1.0/im/interactiveCards/send")]
[Obsolete]
Task<DingTalkSendInteractiveCardsOutput> DingTalkSendInteractiveCards(
[Header("x-acs-dingtalk-access-token")] string token,
[Body] DingTalkSendInteractiveCardsInput input);
[Body(ContentType = "application/json", UseStringContent = true)] DingTalkSendInteractiveCardsInput input);
/// <summary>
/// 获取钉钉卡片消息读取状态
@ -58,4 +63,35 @@ public interface IDingTalkApi : IHttpDeclarative
Task<GetDingTalkCardMessageReadStatusOutput> GetDingTalkCardMessageReadStatus(
[Header("x-acs-dingtalk-access-token")] string token,
[Query] GetDingTalkCardMessageReadStatusInput input);
/// <summary>
/// 获取角色列表
/// </summary>
/// <param name="access_token">调用该接口的应用凭证</param>
/// <param name="input"></param>
/// <returns></returns>
[Post("https://oapi.dingtalk.com/topapi/role/list")]
Task<DingTalkBaseResponse<DingTalkRoleListOutput>> GetDingTalkRoleList([Query] string access_token,
[Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentRoleListInput input);
/// <summary>
/// 获取指定角色的员工列表
/// </summary>
/// <param name="access_token">调用该接口的应用凭证</param>
/// <param name="input"></param>
/// <returns></returns>
[Post("https://oapi.dingtalk.com/topapi/role/simplelist")]
Task<DingTalkBaseResponse<DingTalkRoleSimplelistOutput>> GetDingTalkRoleSimplelist([Query] string access_token,
[Body(ContentType = "application/json", UseStringContent = true), Required] GetDingTalkCurrentRoleSimplelistInput input);
/// <summary>
/// 创建并投放钉钉消息卡片
/// </summary>
/// <param name="token"></param>
/// <param name="input"></param>
/// <returns></returns>
[Post("https://api.dingtalk.com/v1.0/card/instances/createAndDeliver")]
Task<DingTalkCreateAndDeliverOutput> DingTalkCreateAndDeliver(
[Header("x-acs-dingtalk-access-token")] string token,
[Body(ContentType = "application/json", UseStringContent = true)] DingTalkCreateAndDeliverInput input);
}

View File

@ -89,6 +89,7 @@
23. ES 日志:通过 NEST 组件实现日志存取到 Elasticsearch 日志系统。
24. 开放授权支持OAuth 2.0开放标准授权登录,比如微信。
25. APIJSON适配腾讯APIJSON协议支持后端0代码[使用文档](https://github.com/liaozb/APIJSON.NET)。
26. 数据库视图基于SqlSugar生成查询SQL + 表实体维护视图,可维护性更强。
## 🎀捐赠支持
```

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro",
"type": "module",
"version": "2.4.33",
"lastBuildTime": "2025.05.28",
"lastBuildTime": "2025.05.29",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun",
"license": "MIT",
@ -68,7 +68,7 @@
"splitpanes": "^4.0.4",
"vcrontab-3": "^3.3.22",
"vform3-builds": "^3.0.10",
"vue": "^3.5.15",
"vue": "^3.5.16",
"vue-clipboard3": "^2.0.0",
"vue-demi": "0.14.10",
"vue-draggable-plus": "^0.6.0",
@ -89,14 +89,14 @@
"@iconify/vue": "^5.0.0",
"@plugin-web-update-notification/vite": "^2.0.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.15.23",
"@types/node": "^22.15.24",
"@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^8.33.0",
"@typescript-eslint/parser": "^8.33.0",
"@vitejs/plugin-vue": "^5.2.4",
"@vitejs/plugin-vue-jsx": "^4.2.0",
"@vue/compiler-sfc": "^3.5.15",
"@vue/compiler-sfc": "^3.5.16",
"code-inspector-plugin": "^0.20.11",
"eslint": "^9.27.0",
"eslint-plugin-vue": "^10.1.0",
@ -104,7 +104,7 @@
"less": "^4.3.0",
"openapi-ts-request": "^1.5.0",
"prettier": "^3.5.3",
"rollup-plugin-visualizer": "^6.0.0",
"rollup-plugin-visualizer": "^6.0.1",
"sass": "^1.89.0",
"terser": "^5.40.0",
"typescript": "^5.8.3",

View File

@ -199,7 +199,7 @@ const resetQuery = async () => {
//
const handleAdd = () => {
state.title = '添加租户';
editTenantRef.value?.openDialog({ tenantType: 0, orderNo: 100 });
editTenantRef.value?.openDialog({ tenantType: 0, orderNo: 100, host: '' });
};
//