Skip to main content

NotificationHelper

NotificationHelper 提供消息通知和待办事项的管理能力,包括基于消息模板的多渠道通知发送(站内消息 / 待办 / 邮件 / 短信)、手动发送待办、以及待办的关闭与删除。

概述​

在业务流程中,及时的消息通知和待办提醒是提升用户体验的关键。NotificationHelper 封装了平台的消息通知能力:

  • 模板化通知(NotifyAsync):传入消息模板 ID 和接收人,服务端根据模板中勾选的渠道(站内消息、待办、邮件、短信)自动分发。模板勾选了待办渠道时,一次调用即可同时发出待办,无需再单独调用 SendTodoAsync。
  • 手动待办(SendTodoAsync):不依赖消息模板,直接向用户写入待办事项,适合临时性、不想维护模板的场景。
  • 待办管理(CloseTodoAsync / BatchCloseTodoAsync / BatchDeleteTodoAsync):按业务数据 ID 等条件关闭或删除待办。

消息通知(Message Notification / 站内信 / 消息模板)与待办(Todo / To-do)的配置入口参见消息通知模块。

API 方法​

NotifyAsync — 模板化通知发送​

向一个或多个用户发送模板通知。服务端根据模板配置的渠道自动分发到站内消息、待办、邮件、短信。

Task NotifyAsync(params NotificationRequest[] dataList);

必填校验(不满足抛出 ChameleonException):

字段校验
TemplateId必填,且必须为合法 GUID
Receiver必填,且必须为合法 GUID

示例:

// 发送单条模板通知,渠道由模板配置决定
await sdk.NotificationHelper.NotifyAsync(new NotificationRequest
{
TemplateId = "template-guid",
Receiver = "receiver-user-id",
Parameters = new Dictionary<string, string>
{
{ "UserName", "张三" }
},
BizDataId = context.CurrentEntity.Id, // 可选,关联业务数据
MetaObjectCode = "LeaveRequest", // 可选,优先使用;未传时用 MetaObjectId
Scene = "LeaveApproval" // 可选,待办场景标识
});

// 批量发送
await sdk.NotificationHelper.NotifyAsync(
new NotificationRequest { TemplateId = "template-guid", Receiver = "user-1" },
new NotificationRequest { TemplateId = "template-guid", Receiver = "user-2" }
);

NotifyAsync 的渠道分发机制​

服务端读取消息模板的渠道配置,勾选了哪些渠道就发哪些,模板未勾选的渠道不会发送:

模板渠道配置渠道模板内容字段
SystemMessageEnable站内消息SystemMessageSubject / SystemMessageContent
SystemTodoEnable待办SystemTodoSubject / SystemTodoContent
EmailEnable邮件EmailSubject / EmailContent
SmsEnable短信SmsContent

模板内容中的占位符会被替换后发送:

  • {参数名}:替换为 NotificationRequest.Parameters 中同名参数的值
  • {Model.字段编码}:替换为 BizDataId 对应业务数据中该字段的值(需同时传入 MetaObjectCode 或 MetaObjectId 用于定位对象,优先使用 MetaObjectCode)
待办渠道一键发送

如果消息模板勾选了「待办」渠道(SystemTodoEnable = true),调用一次 NotifyAsync 即可同时发出待办,服务端会自动完成待办落库,不需要再单独调用 SendTodoAsync。

只有在不想使用消息模板、希望手动指定标题和内容直接发送待办时,才需要使用 SendTodoAsync。

SendTodoAsync — 手动发送待办​

不使用消息模板,直接向用户发送待办事项,写入 system.todo 集合。

Task SendTodoAsync(params MessageNotificationRequest[] datas);

必填校验:Receiver 必填且必须为合法 GUID;Sender 不传时默认为当前登录用户。

示例:

// 手动发送待办,不依赖消息模板
await sdk.NotificationHelper.SendTodoAsync(new MessageNotificationRequest
{
Receiver = "approver-user-id",
Subject = "审批待办:请假申请",
Content = "张三提交了请假申请,请及时审批",
BizDataId = context.CurrentEntity.Id,
Scene = "LeaveApproval"
});

CloseTodoAsync — 关闭待办​

关闭指定的待办事项(将 ishandled 置为 true,不删除记录)。

Task CloseTodoAsync(string bizDataId, string scene = null, string reciever = null);

参数说明:

参数说明
bizDataId关联的业务数据 ID,必填
scene待办场景标识(可选),用于区分同一数据在不同场景下的待办
reciever待办接收人(可选),不传则关闭该数据的所有待办

示例:

// 审批完成后关闭待办
await sdk.NotificationHelper.CloseTodoAsync(bizDataId: context.CurrentEntity.Id);

BatchCloseTodoAsync — 批量关闭待办​

批量关闭待办事项,支持两种重载:

// 按 bizDataIds 批量关闭
Task BatchCloseTodoAsync(IEnumerable<string> bizDataIds, string scene = null, string reciever = null);

// 按 bizDataId + receivers 批量关闭
Task BatchCloseTodoAsync(string bizDataId, string scene, IEnumerable<string> recievers);

示例:

// 批量关闭多个数据的待办
await sdk.NotificationHelper.BatchCloseTodoAsync(
bizDataIds: new[] { "data-1", "data-2", "data-3" },
scene: "BatchApproval"
);

BatchDeleteTodoAsync — 批量删除待办​

批量删除待办事项(从 system.todo 集合中彻底移除),重载形式与 BatchCloseTodoAsync 相同:

// 按 bizDataIds 批量删除
Task BatchDeleteTodoAsync(IEnumerable<string> bizDataIds, string scene = null, string reciever = null);

// 按 bizDataId + receivers 批量删除
Task BatchDeleteTodoAsync(string bizDataId, string scene, IEnumerable<string> recievers);

典型场景​

模板勾选待办渠道:一次调用发送通知 + 待办​

public async Task<object> ExecuteAsync(ComponentContext context, ChameleonSDK sdk)
{
// 模板勾选了「待办」渠道时,待办随本次调用自动发出
// 模板中的待办内容通过 {参数名} 或 {Model.字段编码} 占位符动态填充
await sdk.NotificationHelper.NotifyAsync(new NotificationRequest
{
TemplateId = "message-template-id", // 已勾选待办渠道的消息模板
Receiver = "approver-id",
Parameters = new Dictionary<string, string>
{
{ "DocName", context.MetaObject.Name }
},
BizDataId = context.CurrentEntity.Id,
MetaObjectCode = context.MetaObject.Code, // 也可传 MetaObjectId
Scene = "MyApproval"
});

return new { success = true };
}

不使用模板:手动发送待办并抄送通知​

需要两个不同模板(待办模板 + 抄送通知模板)分别调用:

public async Task<object> ExecuteAsync(ComponentContext context, ChameleonSDK sdk)
{
var bizDataId = context.CurrentEntity.Id;

// 1. 手动发送待办给审批人(不走模板)
await sdk.NotificationHelper.SendTodoAsync(new MessageNotificationRequest
{
Receiver = "approver-id",
Subject = "新的审批待办",
Content = $"有一条{context.MetaObject.Name}等待您审批",
BizDataId = bizDataId,
Scene = "MyApproval"
});

// 2. 模板化抄送通知给相关人员
await sdk.NotificationHelper.NotifyAsync(new NotificationRequest
{
TemplateId = "cc-notify-template-id",
Receiver = "cc-user-id"
});

return new { success = true };
}

业务完成后清理待办​

public async Task<object> ExecuteAsync(ComponentContext context, ChameleonSDK sdk)
{
// 处理完业务逻辑后...

// 关闭相关的待办
await sdk.NotificationHelper.CloseTodoAsync(
bizDataId: context.CurrentEntity.Id,
scene: "MyBusinessScene"
);

return new { success = true };
}

属性明细​

以下内容面向技术实现与 AI 检索。

NotificationRequest 属性表​

模板化通知请求,发送入口 NotificationOpenApiController(POST api/OpenApi/Notification/Notify)。

属性名类型含义取值/存储值
TemplateIdstring消息模板 ID必填,GUID,对应 system_metamessagetemplate
ParametersIDictionary<string, string>模板占位符参数可空,替换模板内容中的 {参数名}
Receiverstring接收人用户 ID必填,GUID
Senderstring发送者可空,服务端不强制填充
SentTimeDateTime发送时间默认 DateTime.UtcNow
Linkstring消息链接可空,支持占位符替换
BizDataIdstring业务数据 ID可空,用于关联业务数据与待办关闭
MetaObjectIdstring对象 ID可空,GUID;未传 MetaObjectCode 时用于定位对象
MetaObjectCodestring对象编码可空,优先使用;与 MetaObjectId 二选一即可启用 {Model.字段编码} 占位符
Scenestring待办场景可空,建议填写
IsHandledbool是否已处理默认 false
ExtendedParametersDictionary<string, string>额外参数可空,JSON 序列化存储

MessageNotificationRequest 属性表​

手动待办请求,SendTodoAsync 直接写入 system.todo 集合,键名与属性映射如下。

属性名类型含义取值/存储值
Subjectstring消息主题存储键 title
Contentstring消息内容存储键 content
Receiverstring接收人用户 ID必填,GUID,存储键 receiver
Senderstring发送者可空,默认当前登录用户,存储键 sender
SentTimeDateTime发送时间默认 DateTime.UtcNow,存储键 senttime
Linkstring消息链接可空,存储键 link
BizDataIdstring业务数据 ID可空,存储键 bizdataid
MetaObjectIdstring对象 ID可空,存储键 metaobjectid
MetaObjectCodestring对象编码可空,存储键 metaobjectcode
Scenestring待办场景可空,建议填写,存储键 scene
IsHandledbool是否已处理默认 false,存储键 ishandled
ExtendedParametersDictionary<string, string>额外参数可空,JSON 序列化后存储键 extendedparameters

存储示例​

待办数据(system.todo 集合):

{
"sender": "sender-user-id",
"receiver": "approver-user-id",
"senttime": "2026-11-04T08:00:00Z",
"title": "审批待办:请假申请",
"content": "张三提交了请假申请,请及时审批",
"link": null,
"bizdataid": "biz-data-id",
"metaobjectid": "meta-object-id",
"metaobjectcode": "LeaveRequest",
"scene": "LeaveApproval",
"ishandled": false,
"extendedparameters": null
}

服务端执行逻辑​

NotifyAsync 的服务端执行入口为 NotificationService.NotifyAsync:

  1. 校验 TemplateId、Receiver 均为合法 GUID,否则抛出 ChameleonException
  2. 按模板 ID 批量查询消息模板(metaMessageTemplateRepository.GetListByIdsAsync)
  3. 按 MetaObjectCode(优先)或 MetaObjectId 识别对象(ScopedCacheRepository.GetMetaObjectByIdOrCodeAsync,请求内缓存;对象不存在时抛出数据未找到异常),并拉取 BizDataId 对应的业务数据,用于 {Model.字段编码} 占位符替换
  4. 遍历模板与请求,按模板渠道开关(SystemMessageEnable / SystemTodoEnable / EmailEnable / SmsEnable)分别组装各渠道消息
  5. 站内消息调 messageService.SendMessageAsync;待办调 NotificationHelper.SendTodoAsync 落库;邮件、短信异步发送(发送失败仅记日志,不抛出)

SendTodoAsync / CloseTodoAsync 等待办操作直接操作 system.todo 集合(dbContext.BatchAddAsync / BatchUpdateAsync / BatchDeleteAsync)。

异常与校验​

场景行为
TemplateId 为空或非 GUID抛出 ChameleonException("Template ID invalid")
Receiver 为空或非 GUID抛出 ChameleonException("Receiver invalid")
CloseTodoAsync/批量方法的 bizDataId(s) 为空抛出参数校验异常(Ensure.ArgumentNotNullOrEmpty)
邮件/短信发送失败不抛出异常,仅记录 Error 日志
NotifyAsync 服务端异常仅记录 Error 日志,不中断业务脚本

注意事项​

  • 优先使用模板化 NotifyAsync:模板勾选了待办渠道时一次调用即可完成通知 + 待办分发,无需重复调用 SendTodoAsync
  • SendTodoAsync 发送的待办会在用户的待办中心显示,点击可跳转到关联的业务数据
  • BizDataId 通常传入当前业务数据的 ID,用于将待办与具体业务数据关联,也是后续 CloseTodoAsync 的定位条件
  • Scene 参数可用于区分同一业务数据在不同场景下的待办,关闭/删除时可通过 scene 精确匹配
  • 关闭待办不等于删除:关闭仅将 ishandled 置为 true,待办仍可在历史记录中查看;删除则是彻底移除
  • NotifyAsync 的站内消息/待办为同步落库,邮件/短信为异步发送且失败不抛出异常

相关文档​