From a723827b7d99d3074cf8bcfa063f13e2627fbfa6 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 15 Oct 2025 11:34:37 +0800 Subject: [PATCH] feat(wechat): wecom webhook message integrate --- .../WeChatWorkFeatureDefinitionProvider.cs | 23 ++++ .../Work/Features/WeChatWorkFeatureNames.cs | 17 +++ .../Work/Messages/IWeChatWorkMessageSender.cs | 14 +++ .../Messages/Models/TemplateCardAction.cs | 75 +++++++++++ .../Models/TemplateCardEmphasisContent.cs | 35 ++++++ .../Models/TemplateCardHorizontalContent.cs | 111 ++++++++++++++++ .../Work/Messages/Models/TemplateCardImage.cs | 35 ++++++ .../Models/TemplateCardImageTextArea.cs | 119 ++++++++++++++++++ .../Work/Messages/Models/TemplateCardJump.cs | 99 +++++++++++++++ .../Messages/Models/TemplateCardMainTitle.cs | 35 ++++++ .../Messages/Models/TemplateCardQuoteArea.cs | 111 ++++++++++++++++ .../Messages/Models/TemplateCardSource.cs | 81 ++++++++++++ .../Models/TemplateCardVerticalContent.cs | 35 ++++++ .../Work/Messages/Models/TextMessage.cs | 3 +- .../Models/WeChatWorkWebhookFileMessage.cs | 27 ++++ .../Models/WeChatWorkWebhookImageMessage.cs | 27 ++++ .../WeChatWorkWebhookMarkdownMessage.cs | 27 ++++ .../WeChatWorkWebhookMarkdownV2Message.cs | 27 ++++ .../Models/WeChatWorkWebhookNewsMessage.cs | 27 ++++ .../WeChatWorkWebhookTemplateCardMessage.cs | 27 ++++ .../Models/WeChatWorkWebhookTextMessage.cs | 27 ++++ .../Models/WeChatWorkWebhookVoiceMessage.cs | 27 ++++ .../Messages/Models/WebhookFileMessage.cs | 26 ++++ .../Messages/Models/WebhookImageMessage.cs | 35 ++++++ .../Messages/Models/WebhookMarkdownMessage.cs | 29 +++++ .../Models/WebhookMarkdownV2Message.cs | 33 +++++ .../Messages/Models/WebhookNewsMessage.cs | 88 +++++++++++++ .../Models/WebhookNewsNoticeCardMessage.cs | 72 +++++++++++ .../Models/WebhookTemplateCardMessage.cs | 100 +++++++++++++++ .../Messages/Models/WebhookTextMessage.cs | 45 +++++++ .../Models/WebhookTextNoticeCardMessage.cs | 63 ++++++++++ .../Messages/Models/WebhookVoiceMessage.cs | 26 ++++ .../Work/Messages/WeChatWorkMessageSender.cs | 25 +++- .../Work/Messages/WeChatWorkWebhookMessage.cs | 22 ++++ ...ientWeChatWorkRequestExtensions.Message.cs | 20 +++ 35 files changed, 1591 insertions(+), 2 deletions(-) create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardAction.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardEmphasisContent.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardHorizontalContent.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImageTextArea.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardJump.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardMainTitle.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardQuoteArea.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardSource.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardVerticalContent.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookFileMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookImageMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownV2Message.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookNewsMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTemplateCardMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTextMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookVoiceMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookFileMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookImageMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownV2Message.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsNoticeCardMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTemplateCardMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextNoticeCardMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookVoiceMessage.cs create mode 100644 aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkWebhookMessage.cs diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureDefinitionProvider.cs index 7548aab46..afb755c03 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureDefinitionProvider.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureDefinitionProvider.cs @@ -21,6 +21,7 @@ public class WeChatWorkFeatureDefinitionProvider : FeatureDefinitionProvider AddMessageFeature(wechatWorkFeature); AddAppChatFeature(wechatWorkFeature); + AddWebhookFeature(wechatWorkFeature); } protected virtual void AddMessageFeature(FeatureDefinition wechatWorkFeature) @@ -67,6 +68,28 @@ public class WeChatWorkFeatureDefinitionProvider : FeatureDefinitionProvider valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1000))); } + protected virtual void AddWebhookFeature(FeatureDefinition wechatWorkFeature) + { + var messageEnableFeature = wechatWorkFeature.CreateChild( + name: WeChatWorkFeatureNames.Webhook.Enable, + defaultValue: "false", + displayName: L("Features:WebhookMessageEnable"), + description: L("Features:WebhookMessageEnableDesc"), + valueType: new ToggleStringValueType(new BooleanValueValidator())); + messageEnableFeature.CreateChild( + name: WeChatWorkFeatureNames.Webhook.Limit, + defaultValue: "20", + displayName: L("Features:WebhookMessage.Limit"), + description: L("Features:WebhookMessage.LimitDesc"), + valueType: new FreeTextStringValueType(new NumericValueValidator(1, 20000))); + messageEnableFeature.CreateChild( + name: WeChatWorkFeatureNames.Webhook.LimitInterval, + defaultValue: "1", + displayName: L("Features:WebhookMessage.LimitInterval"), + description: L("Features:WebhookMessage.LimitIntervalDesc"), + valueType: new FreeTextStringValueType(new NumericValueValidator(1, 1000))); + } + private static LocalizableString L(string name) { return LocalizableString.Create(name); diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureNames.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureNames.cs index 1a423a6b0..592698ba4 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureNames.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Features/WeChatWorkFeatureNames.cs @@ -44,4 +44,21 @@ public static class WeChatWorkFeatureNames public const string LimitInterval = GroupName + ".LimitInterval"; } } + + public static class Webhook + { + public const string GroupName = WeChatWorkFeatureNames.GroupName + ".Webhook"; + /// + /// 启用消息推送 + /// + public const string Enable = GroupName + ".Enable"; + /// + /// 发送次数上限 + /// + public const string Limit = GroupName + ".Limit"; + /// + /// 发送次数上限时长 + /// + public const string LimitInterval = GroupName + ".LimitInterval"; + } } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageSender.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageSender.cs index 174de9d63..0f133bf67 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageSender.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageSender.cs @@ -32,4 +32,18 @@ public interface IWeChatWorkMessageSender Task SendAsync( WeChatWorkAppChatMessage message, CancellationToken cancellationToken = default); + /// + /// 发送Webhook消息 + /// + /// + /// 参考:https://developer.work.weixin.qq.com/document/path/99110 + /// + /// 消息推送的webhook Key + /// 继承自 的企业微信Webhook消息载体 + /// + /// + Task SendAsync( + string webhookKey, + WeChatWorkWebhookMessage message, + CancellationToken cancellationToken = default); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardAction.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardAction.cs new file mode 100644 index 000000000..cde2e2b6c --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardAction.cs @@ -0,0 +1,75 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 卡片的点击跳转事件 +/// +public class TemplateCardAction +{ + /// + /// 卡片跳转类型,1 代表跳转url,2 代表打开小程序。text_notice模版卡片中该字段取值范围为[1,2] + /// + [NotNull] + [JsonProperty("type")] + [JsonPropertyName("type")] + public int Type { get; set; } + /// + /// 跳转链接的url,type是1时必填 + /// + [CanBeNull] + [JsonProperty("url")] + [JsonPropertyName("url")] + public string Url { get; set; } + /// + /// 点击跳转的小程序的appid,type是2时必填 + /// + [CanBeNull] + [JsonProperty("appid")] + [JsonPropertyName("appid")] + public string AppId { get; set; } + /// + /// 点击跳转的小程序的pagepath,type是2时选填 + /// + [CanBeNull] + [JsonProperty("pagepath")] + [JsonPropertyName("pagepath")] + public string PagePath { get; set; } + private TemplateCardAction( + int type, + string url = null, + string appId = null, + string pagePath = null) + { + Type = type; + Url = url; + AppId = appId; + PagePath = pagePath; + } + /// + /// 创建一个跳转链接卡片事件 + /// + /// 跳转链接的url + /// + public static TemplateCardAction Link(string url) + { + Check.NotNullOrWhiteSpace(url, nameof(url)); + + return new TemplateCardAction(1, url); + } + /// + /// 创建一个跳转小程序卡片事件 + /// + /// 小程序的appid + /// 小程序的pagePath + /// + public static TemplateCardAction MiniProgram(string appId, string pagePath) + { + Check.NotNullOrWhiteSpace(appId, nameof(appId)); + Check.NotNullOrWhiteSpace(pagePath, nameof(pagePath)); + + return new TemplateCardAction(2, appId: appId, pagePath: pagePath); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardEmphasisContent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardEmphasisContent.cs new file mode 100644 index 000000000..2377ce537 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardEmphasisContent.cs @@ -0,0 +1,35 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 关键数据样式 +/// +public class TemplateCardEmphasisContent +{ + /// + /// 关键数据样式的数据内容,建议不超过10个字 + /// + [CanBeNull] + [JsonProperty("title")] + [JsonPropertyName("title")] + public string Title { get; set; } + /// + /// 关键数据样式的数据描述内容,建议不超过15个字 + /// + [CanBeNull] + [JsonProperty("desc")] + [JsonPropertyName("desc")] + public string Description { get; set; } + /// + /// 创建一个关键数据样式 + /// + /// 关键数据样式的数据内容 + /// 关键数据样式的数据描述内容 + public TemplateCardEmphasisContent(string title, string description = null) + { + Title = title; + Description = description; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardHorizontalContent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardHorizontalContent.cs new file mode 100644 index 000000000..f3f58d1fa --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardHorizontalContent.cs @@ -0,0 +1,111 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 二级标题+文本 +/// +public class TemplateCardHorizontalContent +{ + /// + /// 模版卡片的二级标题信息内容支持的类型,1是url,2是文件附件,3 代表点击跳转成员详情 + /// + [CanBeNull] + [JsonProperty("type")] + [JsonPropertyName("type")] + public int? Type { get; set; } + /// + /// 二级标题,建议不超过5个字 + /// + [NotNull] + [JsonProperty("keyname")] + [JsonPropertyName("keyname")] + public string KeyName { get; set; } + /// + /// 二级文本,如果type是2,该字段代表文件名称(要包含文件类型),建议不超过26个字 + /// + [CanBeNull] + [JsonProperty("value")] + [JsonPropertyName("value")] + public string Value { get; set; } + /// + /// 链接跳转的url,type是1时必填 + /// + [CanBeNull] + [JsonProperty("url")] + [JsonPropertyName("url")] + public string Url { get; set; } + /// + /// 附件的media_id,type是2时必填 + /// + [CanBeNull] + [JsonProperty("media_id")] + [JsonPropertyName("media_id")] + public string MediaId { get; set; } + /// + /// 成员详情的userid,type是3时必填 + /// + [CanBeNull] + [JsonProperty("userid")] + [JsonPropertyName("userid")] + public string UserId { get; set; } + private TemplateCardHorizontalContent( + string keyName, + int? type = null, + string value = null, + string url = null, + string mediaId = null, + string userId = null) + { + Type = type; + KeyName = keyName; + Value = value; + Url = url; + MediaId = mediaId; + UserId = userId; + } + /// + /// 创建一个跳转链接的二级标题+文本 + /// + /// 二级标题 + /// 链接跳转的url + /// 二级文本 + /// + public static TemplateCardHorizontalContent Link(string keyName, string url, string value = null) + { + Check.NotNullOrWhiteSpace(keyName, nameof(keyName)); + Check.NotNullOrWhiteSpace(url, nameof(url)); + + return new TemplateCardHorizontalContent(keyName, 1, value: value, url: url); + } + /// + /// 创建一个引用文件的二级标题+文本 + /// + /// 二级标题 + /// 文件名称 + /// 附件的mediaId + /// + public static TemplateCardHorizontalContent File(string keyName, string fileName, string mediaId) + { + Check.NotNullOrWhiteSpace(keyName, nameof(keyName)); + Check.NotNullOrWhiteSpace(fileName, nameof(fileName)); + Check.NotNullOrWhiteSpace(mediaId, nameof(mediaId)); + + return new TemplateCardHorizontalContent(keyName, 2, value: fileName, mediaId: mediaId); + } + /// + /// 创建一个成员详情的二级标题+文本 + /// + /// 二级标题 + /// 成员的userid + /// + public static TemplateCardHorizontalContent UserInfo(string keyName, string userId) + { + Check.NotNullOrWhiteSpace(keyName, nameof(keyName)); + Check.NotNullOrWhiteSpace(userId, nameof(userId)); + + return new TemplateCardHorizontalContent(keyName, 3, userId: userId); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImage.cs new file mode 100644 index 000000000..2a12d353a --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImage.cs @@ -0,0 +1,35 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 图片样式 +/// +public class TemplateCardImage +{ + /// + /// 图片的url + /// + [NotNull] + [JsonProperty("url")] + [JsonPropertyName("url")] + public string Url { get; set; } + /// + /// 图片的宽高比,宽高比要小于2.25,大于1.3,不填该参数默认1.3 + /// + [CanBeNull] + [JsonProperty("aspect_ratio")] + [JsonPropertyName("aspect_ratio")] + public float? AspectRatio { get; set; } + /// + /// 创建一个图片样式 + /// + /// 图片的url + /// 图片的宽高比,不填该参数默认1.3 + public TemplateCardImage(string url, float? aspectRatio = 1.3f) + { + Url = url; + AspectRatio = aspectRatio; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImageTextArea.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImageTextArea.cs new file mode 100644 index 000000000..bcb0d5892 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardImageTextArea.cs @@ -0,0 +1,119 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 左图右文样式 +/// +public class TemplateCardImageTextArea +{ + /// + /// 左图右文样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序 + /// + [CanBeNull] + [JsonProperty("type")] + [JsonPropertyName("type")] + public int? Type { get; set; } + /// + /// 左图右文样式的图片url + /// + [NotNull] + [JsonProperty("image_url")] + [JsonPropertyName("image_url")] + public string ImageUrl { get; set; } + /// + /// 点击跳转的url,type是1时必填 + /// + [NotNull] + [JsonProperty("url")] + [JsonPropertyName("url")] + public string Url { get; set; } + /// + /// 点击跳转的小程序的appid,type是2时必填 + /// + [CanBeNull] + [JsonProperty("appid")] + [JsonPropertyName("appid")] + public string AppId { get; set; } + /// + /// 点击跳转的小程序的pagepath,type是2时选填 + /// + [CanBeNull] + [JsonProperty("pagepath")] + [JsonPropertyName("pagepath")] + public string PagePath { get; set; } + /// + /// 左图右文样式的标题 + /// + [CanBeNull] + [JsonProperty("title")] + [JsonPropertyName("title")] + public string Title { get; set; } + /// + /// 左图右文样式的描述 + /// + [CanBeNull] + [JsonProperty("desc")] + [JsonPropertyName("desc")] + public string Description { get; set; } + private TemplateCardImageTextArea( + string imageUrl, + int? type = null, + string url = null, + string appId = null, + string pagePath = null, + string title = null, + string description = null) + { + Type = type; + ImageUrl = imageUrl; + Url = url; + AppId = appId; + PagePath = pagePath; + Title = title; + Description = description; + } + /// + /// 创建一个跳转链接左图右文样式 + /// + /// 左图右文样式的图片url + /// 点击跳转的url + /// 左图右文样式的标题 + /// 左图右文样式的描述 + /// + public static TemplateCardImageTextArea Link( + string imageUrl, + string url, + string title = null, + string description = null) + { + Check.NotNullOrWhiteSpace(imageUrl, nameof(imageUrl)); + Check.NotNullOrWhiteSpace(url, nameof(url)); + + return new TemplateCardImageTextArea(imageUrl, 1, url: url, title: title, description: description); + } + /// + /// 创建一个跳转小程序左图右文样式 + /// + /// 左图右文样式的图片url + /// 小程序AppId + /// 小程序PagePath + /// 左图右文样式的标题 + /// 左图右文样式的描述 + /// + public static TemplateCardImageTextArea MiniProgram( + string imageUrl, + string appId, + string pagePath, + string title = null, + string description = null) + { + Check.NotNullOrWhiteSpace(imageUrl, nameof(imageUrl)); + Check.NotNullOrWhiteSpace(appId, nameof(appId)); + Check.NotNullOrWhiteSpace(pagePath, nameof(pagePath)); + + return new TemplateCardImageTextArea(imageUrl, 2, appId: appId, pagePath: pagePath, title: title, description: description); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardJump.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardJump.cs new file mode 100644 index 000000000..7418dae52 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardJump.cs @@ -0,0 +1,99 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 跳转指引样式 +/// +public class TemplateCardJump +{ + /// + /// 跳转链接类型,0或不填代表不是链接,1 代表跳转url,2 代表跳转小程序 + /// + [CanBeNull] + [JsonProperty("type")] + [JsonPropertyName("type")] + public int? Type { get; set; } + /// + /// 跳转链接样式的文案内容,建议不超过13个字 + /// + [NotNull] + [JsonProperty("title")] + [JsonPropertyName("title")] + public string Title { get; set; } + /// + /// 跳转链接的url,type是1时必填 + /// + [CanBeNull] + [JsonProperty("url")] + [JsonPropertyName("url")] + public string Url { get; set; } + /// + /// 点击跳转的小程序的appid,type是2时必填 + /// + [CanBeNull] + [JsonProperty("appid")] + [JsonPropertyName("appid")] + public string AppId { get; set; } + /// + /// 点击跳转的小程序的pagepath,type是2时选填 + /// + [CanBeNull] + [JsonProperty("pagepath")] + [JsonPropertyName("pagepath")] + public string PagePath { get; set; } + private TemplateCardJump( + string title, + int? type = null, + string url = null, + string appId = null, + string pagePath = null) + { + Type = type; + Title = title; + Url = url; + AppId = appId; + PagePath = pagePath; + } + /// + /// 创建一个默认指引样式 + /// + /// 跳转链接样式的文案内容 + /// + public static TemplateCardJump Default(string title) + { + Check.NotNullOrWhiteSpace(title, nameof(title)); + + return new TemplateCardJump(title); + } + /// + /// 创建一个跳转链接的指引样式 + /// + /// 跳转链接样式的文案内容 + /// 跳转链接的url + /// + public static TemplateCardJump Link(string title, string url) + { + Check.NotNullOrWhiteSpace(title, nameof(title)); + Check.NotNullOrWhiteSpace(url, nameof(url)); + + return new TemplateCardJump(title, 1, url); + } + /// + /// 创建一个跳转小程序的指引样式 + /// + /// 跳转链接样式的文案内容 + /// 跳转链接的小程序的appid + /// 跳转链接的小程序的pagepath + /// + public static TemplateCardJump MiniProgram(string title, string appId, string pagePath) + { + Check.NotNullOrWhiteSpace(title, nameof(title)); + Check.NotNullOrWhiteSpace(appId, nameof(appId)); + Check.NotNullOrWhiteSpace(pagePath, nameof(pagePath)); + + return new TemplateCardJump(title, 2, appId: appId, pagePath: pagePath); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardMainTitle.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardMainTitle.cs new file mode 100644 index 000000000..b02075126 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardMainTitle.cs @@ -0,0 +1,35 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 模版卡片的主要内容 +/// +public class TemplateCardMainTitle +{ + /// + /// 一级标题,建议不超过26个字。模版卡片主要内容的一级标题main_title.title和二级普通文本sub_title_text必须有一项填写 + /// + [CanBeNull] + [JsonProperty("title")] + [JsonPropertyName("title")] + public string Title { get; set; } + /// + /// 标题辅助信息,建议不超过30个字 + /// + [CanBeNull] + [JsonProperty("desc")] + [JsonPropertyName("desc")] + public string Description { get; set; } + /// + /// 创建一个模版卡片的主要内容 + /// + /// 一级标题 + /// 标题辅助信息 + public TemplateCardMainTitle(string title, string description = null) + { + Title = title; + Description = description; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardQuoteArea.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardQuoteArea.cs new file mode 100644 index 000000000..cb773e501 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardQuoteArea.cs @@ -0,0 +1,111 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 引用文献 +/// +public class TemplateCardQuoteArea +{ + /// + /// 引用文献样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序 + /// + [CanBeNull] + [JsonProperty("type")] + [JsonPropertyName("type")] + public int? Type { get; set; } + /// + /// 点击跳转的url,type是1时必填 + /// + [CanBeNull] + [JsonProperty("url")] + [JsonPropertyName("url")] + public string Url { get; set; } + /// + /// 点击跳转的小程序的appid,type是2时必填 + /// + [CanBeNull] + [JsonProperty("appid")] + [JsonPropertyName("appid")] + public string AppId { get; set; } + /// + /// 点击跳转的小程序的pagepath,type是2时选填 + /// + [CanBeNull] + [JsonProperty("pagepath")] + [JsonPropertyName("pagepath")] + public string PagePath { get; set; } + /// + /// 引用文献样式的标题 + /// + [CanBeNull] + [JsonProperty("title")] + [JsonPropertyName("title")] + public string Title { get; set; } + /// + /// 引用文献样式的引用文案 + /// + [CanBeNull] + [JsonProperty("quote_text")] + [JsonPropertyName("quote_text")] + public string QuoteText { get; set; } + private TemplateCardQuoteArea( + string title, + int? type = null, + string url = null, + string appId = null, + string pagePath = null, + string quoteText = null) + { + Title = title; + QuoteText = quoteText; + Type = type; + Url = url; + AppId = appId; + PagePath = pagePath; + } + /// + /// 创建一个默认引用文献 + /// + /// 引用文献样式的标题 + /// 引用文献样式的引用文案 + /// + public static TemplateCardQuoteArea Default(string title, string quoteText = null) + { + Check.NotNullOrWhiteSpace(title, nameof(title)); + + return new TemplateCardQuoteArea(title, quoteText: quoteText); + } + /// + /// 创建一个跳转链接的引用文献 + /// + /// 引用文献样式的标题 + /// 点击跳转的url + /// 引用文献样式的引用文案 + /// + public static TemplateCardQuoteArea Link(string title, string url, string quoteText = null) + { + Check.NotNullOrWhiteSpace(title, nameof(title)); + Check.NotNullOrWhiteSpace(url, nameof(url)); + + return new TemplateCardQuoteArea(title, 1, url, quoteText: quoteText); + } + /// + /// 创建一个跳转小程序的引用文献 + /// + /// 引用文献样式的标题 + /// 跳转链接的小程序的appid + /// 跳转链接的小程序的pagepath + /// 引用文献样式的引用文案 + /// + public static TemplateCardQuoteArea MiniProgram(string title, string appId, string pagePath, string quoteText = null) + { + Check.NotNullOrWhiteSpace(title, nameof(title)); + Check.NotNullOrWhiteSpace(appId, nameof(appId)); + Check.NotNullOrWhiteSpace(pagePath, nameof(pagePath)); + + return new TemplateCardQuoteArea(title, 2, appId: appId, pagePath: pagePath, quoteText: quoteText); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardSource.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardSource.cs new file mode 100644 index 000000000..d0f5cf0fc --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardSource.cs @@ -0,0 +1,81 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 卡片来源样式信息 +/// +public class TemplateCardSource +{ + /// + /// 来源图片的url + /// + [CanBeNull] + [JsonProperty("icon_url")] + [JsonPropertyName("icon_url")] + public string IconUrl { get; set; } + /// + /// 来源图片的描述,建议不超过13个字 + /// + [CanBeNull] + [JsonProperty("desc")] + [JsonPropertyName("desc")] + public string Description { get; set; } + /// + /// 来源文字的颜色,目前支持:0(默认) 灰色,1 黑色,2 红色,3 绿色 + /// + [CanBeNull] + [JsonProperty("desc_color")] + [JsonPropertyName("desc_color")] + public int? DescriptionColor { get; set; } + private TemplateCardSource( + string iconUrl = null, + string description = null, + int? descriptionColor = 0) + { + IconUrl = iconUrl; + Description = description; + DescriptionColor = descriptionColor; + } + /// + /// 创建一个灰色卡片来源样式 + /// + /// 来源图片的url + /// 来源图片的描述 + /// + public static TemplateCardSource Grey(string iconUrl, string description = null) + { + return new TemplateCardSource(iconUrl, description, 0); + } + /// + /// 创建一个黑色卡片来源样式 + /// + /// 来源图片的url + /// 来源图片的描述 + /// + public static TemplateCardSource Black(string iconUrl, string description = null) + { + return new TemplateCardSource(iconUrl, description, 1); + } + /// + /// 创建一个红色卡片来源样式 + /// + /// 来源图片的url + /// 来源图片的描述 + /// + public static TemplateCardSource Red(string iconUrl, string description = null) + { + return new TemplateCardSource(iconUrl, description, 2); + } + /// + /// 创建一个绿色卡片来源样式 + /// + /// 来源图片的url + /// 来源图片的描述 + /// + public static TemplateCardSource Green(string iconUrl, string description = null) + { + return new TemplateCardSource(iconUrl, description, 3); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardVerticalContent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardVerticalContent.cs new file mode 100644 index 000000000..be8035b28 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TemplateCardVerticalContent.cs @@ -0,0 +1,35 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 卡片二级垂直内容 +/// +public class TemplateCardVerticalContent +{ + /// + /// 卡片二级标题,建议不超过26个字 + /// + [CanBeNull] + [JsonProperty("title")] + [JsonPropertyName("title")] + public string Title { get; set; } + /// + /// 二级普通文本,建议不超过112个字 + /// + [CanBeNull] + [JsonProperty("desc")] + [JsonPropertyName("desc")] + public string Description { get; set; } + /// + /// 创建一个卡片二级垂直内容 + /// + /// 卡片二级标题 + /// 二级普通文本 + public TemplateCardVerticalContent(string title, string description = null) + { + Title = title; + Description = description; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextMessage.cs index fb308af8a..e047ff840 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextMessage.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextMessage.cs @@ -1,6 +1,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; using System.Text.Json.Serialization; +using Volo.Abp; namespace LINGYUN.Abp.WeChat.Work.Messages.Models; /// @@ -10,7 +11,7 @@ public class TextMessage { public TextMessage(string content) { - Content = content; + Content = Check.NotNullOrWhiteSpace(content, nameof(content), 2048); } /// diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookFileMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookFileMessage.cs new file mode 100644 index 000000000..d584188fb --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookFileMessage.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook文件消息 +/// +public class WeChatWorkWebhookFileMessage : WeChatWorkWebhookMessage +{ + /// + /// 文件消息体 + /// + [NotNull] + [JsonProperty("file")] + [JsonPropertyName("file")] + public WebhookFileMessage File { get; set; } + /// + /// 创建一个企业微信Webhook文件消息 + /// + /// 文件消息体 + public WeChatWorkWebhookFileMessage(WebhookFileMessage file) + : base("file") + { + File = file; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookImageMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookImageMessage.cs new file mode 100644 index 000000000..fad686e12 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookImageMessage.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook图片消息 +/// +public class WeChatWorkWebhookImageMessage : WeChatWorkWebhookMessage +{ + /// + /// 图片消息体 + /// + [NotNull] + [JsonProperty("image")] + [JsonPropertyName("image")] + public WebhookImageMessage Image { get; set; } + /// + /// 创建一个企业微信Webhook图片消息 + /// + /// 图片消息体 + public WeChatWorkWebhookImageMessage(WebhookImageMessage image) + : base("image") + { + Image = image; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownMessage.cs new file mode 100644 index 000000000..0824f4f2c --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownMessage.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook Markdown消息 +/// +public class WeChatWorkWebhookMarkdownMessage : WeChatWorkWebhookMessage +{ + /// + /// Markdown消息体 + /// + [NotNull] + [JsonProperty("markdown")] + [JsonPropertyName("markdown")] + public WebhookMarkdownMessage Markdown { get; set; } + /// + /// 创建一个企业微信Webhook Markdown消息 + /// + /// Markdown消息体 + public WeChatWorkWebhookMarkdownMessage(WebhookMarkdownMessage markdown) + : base("markdown") + { + Markdown = markdown; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownV2Message.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownV2Message.cs new file mode 100644 index 000000000..bf3cee876 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookMarkdownV2Message.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook MarkdownV2消息 +/// +public class WeChatWorkWebhookMarkdownV2Message : WeChatWorkWebhookMessage +{ + /// + /// markdown_v2消息体 + /// + [NotNull] + [JsonProperty("markdown_v2")] + [JsonPropertyName("markdown_v2")] + public WebhookMarkdownV2Message Markdown { get; set; } + /// + /// 创建一个企业微信Webhook MarkdownV2消息 + /// + /// markdown_v2消息体 + public WeChatWorkWebhookMarkdownV2Message(WebhookMarkdownV2Message markdown) + : base("markdown_v2") + { + Markdown = markdown; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookNewsMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookNewsMessage.cs new file mode 100644 index 000000000..c0b7a6c83 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookNewsMessage.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook图文消息 +/// +internal class WeChatWorkWebhookNewsMessage : WeChatWorkWebhookMessage +{ + /// + /// 图文消息体 + /// + [NotNull] + [JsonProperty("news")] + [JsonPropertyName("news")] + public WebhookNewsMessage News { get; set; } + /// + /// 创建一个企业微信Webhook图文消息 + /// + /// 图文消息体 + public WeChatWorkWebhookNewsMessage(WebhookNewsMessage news) + : base("news") + { + News = news; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTemplateCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTemplateCardMessage.cs new file mode 100644 index 000000000..3ff3b7231 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTemplateCardMessage.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook模版卡片消息 +/// +public class WeChatWorkWebhookTemplateCardMessage : WeChatWorkWebhookMessage +{ + /// + /// 模版卡片消息体 + /// + [NotNull] + [JsonProperty("template_card")] + [JsonPropertyName("template_card")] + public WebhookTemplateCardMessage TemplateCard { get; set; } + /// + /// 创建一个企业微信Webhook模版卡片消息 + /// + /// 模版卡片消息体 + public WeChatWorkWebhookTemplateCardMessage(WebhookTemplateCardMessage templateCard) + : base("template_card") + { + TemplateCard = templateCard; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTextMessage.cs new file mode 100644 index 000000000..48676d4a1 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookTextMessage.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook文本消息 +/// +public class WeChatWorkWebhookTextMessage : WeChatWorkWebhookMessage +{ + /// + /// 文本消息体 + /// + [NotNull] + [JsonProperty("text")] + [JsonPropertyName("text")] + public WebhookTextMessage Text { get; set; } + /// + /// 创建一个企业微信Webhook文本消息 + /// + /// 文本消息体 + public WeChatWorkWebhookTextMessage(WebhookTextMessage text) + : base("text") + { + Text = text; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookVoiceMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookVoiceMessage.cs new file mode 100644 index 000000000..21eeda107 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkWebhookVoiceMessage.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// 企业微信Webhook语音消息 +/// +public class WeChatWorkWebhookVoiceMessage : WeChatWorkWebhookMessage +{ + /// + /// 语音消息体 + /// + [NotNull] + [JsonProperty("voice")] + [JsonPropertyName("voice")] + public WebhookVoiceMessage Voice { get; set; } + /// + /// 创建一个企业微信Webhook语音消息 + /// + /// 语音消息体 + public WeChatWorkWebhookVoiceMessage(WebhookVoiceMessage voice) + : base("voice") + { + Voice = voice; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookFileMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookFileMessage.cs new file mode 100644 index 000000000..ae4dd53ff --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookFileMessage.cs @@ -0,0 +1,26 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook文件消息体 +/// +public class WebhookFileMessage +{ + /// + /// 文件id,通过下文的文件上传接口获取 + /// + [NotNull] + [JsonProperty("media_id")] + [JsonPropertyName("media_id")] + public string MediaId { get; set; } + /// + /// 创建一个Webhook文件消息体 + /// + /// 文件id,通过下文的文件上传接口获取 + public WebhookFileMessage(string mediaId) + { + MediaId = mediaId; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookImageMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookImageMessage.cs new file mode 100644 index 000000000..58735b604 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookImageMessage.cs @@ -0,0 +1,35 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook图片消息体 +/// +public class WebhookImageMessage +{ + /// + /// 图片内容的base64编码 + /// + [NotNull] + [JsonProperty("base64")] + [JsonPropertyName("base64")] + public string Base64 { get; set; } + /// + /// 图片的md5 + /// + [NotNull] + [JsonProperty("md5")] + [JsonPropertyName("md5")] + public string Md5 { get; set; } + /// + /// 创建一个Webhook图片消息体 + /// + /// 图片内容的base64编码 + /// 图片的md5 + public WebhookImageMessage(string base64, string md5) + { + Base64 = base64; + Md5 = md5; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownMessage.cs new file mode 100644 index 000000000..a65d4b8f5 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownMessage.cs @@ -0,0 +1,29 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook Markdown消息体 +/// +public class WebhookMarkdownMessage +{ + /// + /// markdown内容,最长不超过4096个字节,必须是utf8编码 + /// + [NotNull] + [StringLength(4096)] + [JsonProperty("content")] + [JsonPropertyName("content")] + public string Content { get; set; } + /// + /// 创建一个Webhook Markdown消息体 + /// + /// markdown内容,最长不超过4096个字节,必须是utf8编码 + public WebhookMarkdownMessage(string content) + { + Content = Check.NotNullOrWhiteSpace(content, nameof(content), 4096); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownV2Message.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownV2Message.cs new file mode 100644 index 000000000..7a6f1109b --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookMarkdownV2Message.cs @@ -0,0 +1,33 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook MarkdownV2消息体 +/// +public class WebhookMarkdownV2Message +{ + /// + /// markdown_v2内容,最长不超过4096个字节,必须是utf8编码。 + /// + /// + /// 1. markdown_v2不支持字体颜色、@群成员的语法, 具体支持的语法可参考下面说明
+ /// 2. 消息内容在客户端 4.1.36 版本以下(安卓端为4.1.38以下) 消息表现为纯文本,建议使用最新客户端版本体验 + ///
+ [NotNull] + [StringLength(4096)] + [JsonProperty("content")] + [JsonPropertyName("content")] + public string Content { get; set; } + /// + /// 创建一个Webhook MarkdownV2消息体 + /// + /// markdown_v2内容,最长不超过4096个字节,必须是utf8编码 + public WebhookMarkdownV2Message(string content) + { + Content = Check.NotNullOrWhiteSpace(content, nameof(content), 4096); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsMessage.cs new file mode 100644 index 000000000..920e04067 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsMessage.cs @@ -0,0 +1,88 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook图文消息体 +/// +public class WebhookNewsMessage +{ + /// + /// 图文消息,一个图文消息支持1到8条图文 + /// + [NotNull] + [JsonProperty("articles")] + [JsonPropertyName("articles")] + public List Articles { get; set; } + /// + /// 创建一个Webhook图文消息体 + /// + /// 图文消息列表 + /// + public WebhookNewsMessage(List articles) + { + Articles = Check.NotNull(articles, nameof(articles)); + + if (Articles.Count < 1 || Articles.Count > 8) + { + throw new ArgumentException("One image-text message supports 1 to 8 image-text messages!"); + } + } +} + +public class WebhookArticleMessage +{ + /// + /// 标题,不超过128个字节,超过会自动截断 + /// + [NotNull] + [StringLength(128)] + [JsonProperty("title")] + [JsonPropertyName("title")] + public string Title { get; set; } + /// + /// 描述,不超过512个字节,超过会自动截断 + /// + [CanBeNull] + [StringLength(512)] + [JsonProperty("description")] + [JsonPropertyName("description")] + public string Description { get; set; } + /// + /// 点击后跳转的链接。 + /// + [NotNull] + [JsonProperty("url")] + [JsonPropertyName("url")] + public string Url { get; set; } + /// + /// 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图 1068*455,小图150*150。 + /// + [CanBeNull] + [JsonProperty("picurl")] + [JsonPropertyName("picurl")] + public string PictureUrl { get; set; } + /// + /// 创建一个图文消息 + /// + /// 标题 + /// 点击后跳转的链接 + /// 描述 + /// 图文消息的图片链接 + public WebhookArticleMessage( + string title, + string url, + string description = "", + string pictureUrl = "") + { + Title = Check.NotNullOrWhiteSpace(title, nameof(title), 128); + Url = Check.NotNullOrWhiteSpace(url, nameof(url)); + Description = Check.Length(description, nameof(description), 512); + PictureUrl = pictureUrl; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsNoticeCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsNoticeCardMessage.cs new file mode 100644 index 000000000..73b0e367a --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookNewsNoticeCardMessage.cs @@ -0,0 +1,72 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook 图文展示模版卡片消息体 +/// +public class WebhookNewsNoticeCardMessage : WebhookTemplateCardMessage +{ + /// + /// 创建一个Webhook 图文展示模版卡片消息体 + /// + /// 图片样式 + /// 整体卡片的点击跳转事件 + /// 模版卡片的主要内容 + /// 左图右文样式 + /// 卡片来源样式信息 + /// 引用文献样式 + /// 二级标题+文本列表,列表长度不超过6 + /// 卡片二级垂直内容,列表长度不超过4 + /// 跳转指引样式的列表,列表长度不超过3 + /// + public WebhookNewsNoticeCardMessage( + TemplateCardImage cardImage, + TemplateCardAction action, + TemplateCardMainTitle mainTitle, + TemplateCardImageTextArea imageTextArea = null, + TemplateCardSource source = null, + TemplateCardQuoteArea quoteArea = null, + List horizontalContents = null, + List verticalContents = null, + List jumps = null) + : base("news_notice", action, mainTitle, source, quoteArea, horizontalContents, jumps) + { + Check.NotNull(mainTitle, nameof(mainTitle)); + Check.NotNull(cardImage, nameof(cardImage)); + + CardImage = cardImage; + ImageTextArea = imageTextArea; + VerticalContents = verticalContents; + + if (verticalContents != null && verticalContents.Count > 4) + { + throw new ArgumentException("The length of the secondary vertical content list on the card cannot exceed 4!"); + } + } + /// + /// 图片样式 + /// + [NotNull] + [JsonProperty("aspect_ratio")] + [JsonPropertyName("aspect_ratio")] + public TemplateCardImage CardImage { get; set; } + /// + /// 左图右文样式 + /// + [CanBeNull] + [JsonProperty("image_text_area")] + [JsonPropertyName("image_text_area")] + public TemplateCardImageTextArea ImageTextArea { get; set; } + /// + /// 卡片二级垂直内容,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过4 + /// + [CanBeNull] + [JsonProperty("vertical_content_list")] + [JsonPropertyName("vertical_content_list")] + public List VerticalContents { get; set; } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTemplateCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTemplateCardMessage.cs new file mode 100644 index 000000000..2de22a67a --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTemplateCardMessage.cs @@ -0,0 +1,100 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook模板卡片消息体 +/// +public abstract class WebhookTemplateCardMessage +{ + /// + /// 模版卡片的模版类型 + /// + [CanBeNull] + [JsonProperty("card_type")] + [JsonPropertyName("card_type")] + public string CardType { get; set; } + /// + /// 卡片来源样式信息,不需要来源样式可不填写 + /// + [CanBeNull] + [JsonProperty("source")] + [JsonPropertyName("source")] + public TemplateCardSource Source { get; set; } + /// + /// 模版卡片的主要内容,包括一级标题和标题辅助信息 + /// + [CanBeNull] + [JsonProperty("main_title")] + [JsonPropertyName("main_title")] + public TemplateCardMainTitle MainTitle { get; set; } + /// + /// 引用文献样式,建议不与关键数据共用 + /// + [CanBeNull] + [JsonProperty("quote_area")] + [JsonPropertyName("quote_area")] + public TemplateCardQuoteArea QuoteArea { get; set; } + /// + /// 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6 + /// + [CanBeNull] + [JsonProperty("horizontal_content_list")] + [JsonPropertyName("horizontal_content_list")] + public List HorizontalContents { get; set; } + /// + /// 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3 + /// + [CanBeNull] + [JsonProperty("jump_list")] + [JsonPropertyName("jump_list")] + public List Jumps { get; set; } + /// + /// 整体卡片的点击跳转事件,text_notice模版卡片中该字段为必填项 + /// + [CanBeNull] + [JsonProperty("card_action")] + [JsonPropertyName("card_action")] + public TemplateCardAction Action { get; set; } + /// + /// 创建一个Webhook模板卡片消息体 + /// + /// 整体卡片的点击跳转事件 + /// 模版卡片的主要内容 + /// 卡片来源样式信息 + /// 引用文献样式 + /// 二级标题+文本列表,列表长度不超过6 + /// 跳转指引样式的列表,列表长度不超过3 + /// + protected WebhookTemplateCardMessage( + string cardType, + TemplateCardAction action, + TemplateCardMainTitle mainTitle = null, + TemplateCardSource source = null, + TemplateCardQuoteArea quoteArea = null, + List horizontalContents = null, + List jumps = null) + { + CardType = Check.NotNullOrWhiteSpace(cardType, nameof(cardType)); + Action = Check.NotNull(action, nameof(action)); + + MainTitle = mainTitle; + Source = source; + QuoteArea = quoteArea; + HorizontalContents = horizontalContents; + Jumps = jumps; + + if (horizontalContents != null && horizontalContents.Count > 6) + { + throw new ArgumentException("The length of the secondary title and the text list should not exceed 6!"); + } + if (jumps != null && jumps.Count > 3) + { + throw new ArgumentException("The length of the list in the style of jump guidance should not exceed 3!"); + } + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextMessage.cs new file mode 100644 index 000000000..cba2ec275 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextMessage.cs @@ -0,0 +1,45 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; +using Volo.Abp; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook文本消息体 +/// +public class WebhookTextMessage +{ + /// + /// 消文本内容,最长不超过2048个字节,必须是utf8编码 + /// + [NotNull] + [StringLength(2048)] + [JsonProperty("content")] + [JsonPropertyName("content")] + public string Content { get; set; } + /// + /// userid的列表,提醒群中的指定成员(@某个成员),@all表示提醒所有人,如果开发者获取不到userid,可以使用mentioned_mobile_list + /// + [NotNull] + [JsonProperty("mentioned_list")] + [JsonPropertyName("mentioned_list")] + public List MentionedList { get; set; } + /// + /// 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人 + /// + [NotNull] + [StringLength(2048)] + [JsonProperty("mentioned_mobile_list")] + [JsonPropertyName("mentioned_mobile_list")] + public List MentionedMobileList { get; set; } + /// + /// 创建一个Webhook文本消息体 + /// + /// 消息内容 + public WebhookTextMessage(string content) + { + Content = Check.NotNullOrWhiteSpace(content, nameof(content), 2048); + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextNoticeCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextNoticeCardMessage.cs new file mode 100644 index 000000000..706b6536e --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookTextNoticeCardMessage.cs @@ -0,0 +1,63 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook 文本通知模版卡片消息体 +/// +public class WebhookTextNoticeCardMessage : WebhookTemplateCardMessage +{ + /// + /// 二级普通文本,建议不超过112个字。模版卡片主要内容的一级标题main_title.title和二级普通文本sub_title_text必须有一项填写 + /// + [CanBeNull] + [JsonProperty("sub_title_text")] + [JsonPropertyName("sub_title_text")] + public string SubTitleText { get; set; } + /// + /// 关键数据样式 + /// + [CanBeNull] + [JsonProperty("emphasis_content")] + [JsonPropertyName("emphasis_content")] + public TemplateCardEmphasisContent EmphasisContent { get; set; } + /// + /// 创建一个Webhook 文本通知模版卡片消息体 + /// + /// 整体卡片的点击跳转事件 + /// 模版卡片的主要内容 + /// 二级普通文本 + /// 关键数据样式 + /// 卡片来源样式信息 + /// 引用文献样式 + /// 二级标题+文本列表,列表长度不超过6 + /// 跳转指引样式的列表,列表长度不超过3 + /// + public WebhookTextNoticeCardMessage( + TemplateCardAction action, + TemplateCardMainTitle mainTitle = null, + string subTitleText = null, + TemplateCardEmphasisContent emphasisContent = null, + TemplateCardSource source = null, + TemplateCardQuoteArea quoteArea = null, + List horizontalContents = null, + List jumps = null) + : base("text_notice", action, mainTitle, source, quoteArea, horizontalContents, jumps) + { + MainTitle = mainTitle; + SubTitleText = subTitleText; + EmphasisContent = emphasisContent; + Source = source; + QuoteArea = quoteArea; + HorizontalContents = horizontalContents; + Jumps = jumps; + + if (mainTitle == null && subTitleText.IsNullOrWhiteSpace()) + { + throw new ArgumentException("One of the primary title mainTitle and the secondary ordinary text subTitleText of the main content of the template card must be filled in!"); + } + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookVoiceMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookVoiceMessage.cs new file mode 100644 index 000000000..76c7ab67c --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WebhookVoiceMessage.cs @@ -0,0 +1,26 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages.Models; +/// +/// Webhook语音消息体 +/// +public class WebhookVoiceMessage +{ + /// + /// 语音文件id,通过下文的文件上传接口获取 + /// + [NotNull] + [JsonProperty("media_id")] + [JsonPropertyName("media_id")] + public string MediaId { get; set; } + /// + /// 创建一个Webhook语音消息体 + /// + /// 语音文件id + public WebhookVoiceMessage(string mediaId) + { + MediaId = mediaId; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs index af0c56981..856d83cae 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs @@ -76,7 +76,30 @@ public class WeChatWorkMessageSender : IWeChatWorkMessageSender, ISingletonDepen if (!messageResponse.IsSuccessed) { - Logger.LogWarning("Send wechat work message failed"); + Logger.LogWarning("Send wechat work app chat message failed"); + Logger.LogWarning($"Error code: {messageResponse.ErrorCode}, message: {messageResponse.ErrorMessage}"); + } + + return messageResponse; + } + + [RequiresFeature(WeChatWorkFeatureNames.Webhook.Enable)] + [RequiresLimitFeature( + WeChatWorkFeatureNames.Webhook.Limit, + WeChatWorkFeatureNames.Webhook.LimitInterval, + LimitPolicy.Minute)] + // 消息发送频率限制: https://developer.work.weixin.qq.com/document/path/99110#%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E9%A2%91%E7%8E%87%E9%99%90%E5%88%B6 + public async virtual Task SendAsync(string webhookKey, WeChatWorkWebhookMessage message, CancellationToken cancellationToken = default) + { + var token = await WeChatWorkTokenProvider.GetTokenAsync(cancellationToken); + var client = HttpClientFactory.CreateClient(AbpWeChatWorkGlobalConsts.ApiClient); + + using var response = await client.SendMessageAsync(webhookKey, message, cancellationToken); + var messageResponse = await response.DeserializeObjectAsync(); + + if (!messageResponse.IsSuccessed) + { + Logger.LogWarning("Send wechat work webhook message failed"); Logger.LogWarning($"Error code: {messageResponse.ErrorCode}, message: {messageResponse.ErrorMessage}"); } diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkWebhookMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkWebhookMessage.cs new file mode 100644 index 000000000..79a6dba87 --- /dev/null +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkWebhookMessage.cs @@ -0,0 +1,22 @@ +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace LINGYUN.Abp.WeChat.Work.Messages; +/// +/// 企业微信Webhook消息结构体 +/// +public abstract class WeChatWorkWebhookMessage : WeChatWorkRequest +{ + /// + /// 消息类型 + /// + [NotNull] + [JsonProperty("msgtype")] + [JsonPropertyName("msgtype")] + public string MsgType { get; set; } + protected WeChatWorkWebhookMessage(string msgType) + { + MsgType = msgType; + } +} diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs index 6b354d260..a54c3fa64 100644 --- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs +++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs @@ -64,4 +64,24 @@ internal static partial class HttpClientWeChatWorkRequestExtensions return await client.SendAsync(httpRequest, cancellationToken); } + + public async static Task SendMessageAsync( + this HttpMessageInvoker client, + string webhookKey, + WeChatWorkWebhookMessage request, + CancellationToken cancellationToken = default) + { + var urlBuilder = new StringBuilder(); + urlBuilder.Append("/cgi-bin/webhook/send"); + urlBuilder.AppendFormat("?key={0}", webhookKey); + + var httpRequest = new HttpRequestMessage( + HttpMethod.Post, + urlBuilder.ToString()) + { + Content = new StringContent(request.SerializeToJson()) + }; + + return await client.SendAsync(httpRequest, cancellationToken); + } }