diff --git a/README.md b/README.md index 4fb1643..f91d998 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ _✨ 搭建专属于你的消息推送服务,支持多种消息推送方式, + WebSocket 客户端([官方客户端](https://github.com/songquanpeng/personal-assistant),[接入文档](./docs/API.md#websocket-客户端)), + Telegram 机器人, + Discord 群机器人, + + 群组消息,可以将多个推送通道组合成一个群组,然后向群组发送消息,可以实现一次性推送到多个渠道的功能。 2. 多种用户登录注册方式: + 邮箱登录注册以及通过邮箱进行密码重置。 + [GitHub 开放授权](https://github.com/settings/applications/new)。 @@ -172,7 +173,8 @@ proxy_send_timeout 300s; 9. `telegram`:通过 Telegram 机器人进行推送(`description` 或 `content` 字段二选一,支持 Markdown 的子集)。 10. `discord`:通过 Discord 群机器人进行推送(注意事项同上)。 11. `one_api`:通过 OneAPI 协议推送消息到 QQ。 - 12. `none`:仅保存到数据库,不做推送。 + 12. `group`:通过预先配置的消息推送通道群组进行推送。 + 13. `none`:仅保存到数据库,不做推送。 5. `token`:如果你在后台设置了推送 token,则此项必填。另外可以通过设置 HTTP `Authorization` 头部设置此项。 6. `url`:选填,如果不填则系统自动为消息生成 URL,其内容为消息详情。 7. `to`:选填,推送给指定用户,如果不填则默认推送给自己,受限于具体的消息推送方式,有些推送方式不支持此项。 diff --git a/channel/group.go b/channel/group.go new file mode 100644 index 0000000..5cb1fff --- /dev/null +++ b/channel/group.go @@ -0,0 +1,31 @@ +package channel + +import ( + "errors" + "message-pusher/model" + "strings" +) + +func SendGroupMessage(message *model.Message, user *model.User, channel_ *model.Channel) error { + subChannels := strings.Split(channel_.AppId, "|") + subTargets := strings.Split(channel_.AccountId, "|") + if len(subChannels) != len(subTargets) { + return errors.New("无效的群组消息配置,子通道数量与子目标数量不一致") + } + for i := 0; i < len(subChannels); i++ { + message.To = subTargets[i] + message.Channel = subChannels[i] + subChannel, err := model.GetChannelByName(subChannels[i], user.Id) + if err != nil { + return errors.New("获取群组消息子通道失败:" + err.Error()) + } + if subChannel.Type == model.TypeGroup { + return errors.New("群组消息子通道不能是群组消息") + } + err = SendMessage(message, user, subChannel) + if err != nil { + return errors.New("发送群组消息失败:" + err.Error()) + } + } + return nil +} diff --git a/channel/main.go b/channel/main.go index f155e79..afa409d 100644 --- a/channel/main.go +++ b/channel/main.go @@ -31,6 +31,8 @@ func SendMessage(message *model.Message, user *model.User, channel_ *model.Chann return nil case model.TypeOneBot: return SendOneBotMessage(message, user, channel_) + case model.TypeGroup: + return SendGroupMessage(message, user, channel_) default: return errors.New("不支持的消息通道:" + channel_.Type) } diff --git a/model/channel.go b/model/channel.go index 47a6ea1..185c9e6 100644 --- a/model/channel.go +++ b/model/channel.go @@ -18,6 +18,7 @@ const ( TypeClient = "client" TypeNone = "none" TypeOneBot = "one_bot" + TypeGroup = "group" ) type Channel struct { diff --git a/web/src/constants/channel.constants.js b/web/src/constants/channel.constants.js index e5c25ee..fa62df1 100644 --- a/web/src/constants/channel.constants.js +++ b/web/src/constants/channel.constants.js @@ -33,7 +33,13 @@ export const CHANNEL_OPTIONS = [ key: 'one_bot', text: 'OneBot 协议', value: 'one_bot', - color: '#616cff', + color: '#76FF03', + }, + { + key: 'group', + text: '群组消息', + value: 'group', + color: '#FF9800', }, { key: 'none', diff --git a/web/src/pages/Channel/EditChannel.js b/web/src/pages/Channel/EditChannel.js index 219aa48..da1ea3a 100644 --- a/web/src/pages/Channel/EditChannel.js +++ b/web/src/pages/Channel/EditChannel.js @@ -20,7 +20,7 @@ const EditChannel = () => { url: '', other: '', corp_id: '', // only for corp_app - agent_id: '', // only for corp_app + agent_id: '' // only for corp_app }; const [inputs, setInputs] = useState(originInputs); @@ -70,11 +70,22 @@ const EditChannel = () => { localInputs.url = localInputs.url.slice(0, -1); } break; + case 'group': + let channels = localInputs.app_id.split('|'); + let targets = localInputs.account_id.split('|'); + if (localInputs.account_id === '') { + for (let i = 0; i < channels.length - 1; i++) { + localInputs.account_id += '|'; + } + } else if (channels.length !== targets.length) { + showError('群组通道的子通道数量与目标数量不匹配,对于不需要指定的目标请直接留空'); + return; + } } if (isEditing) { res = await API.put(`/api/channel/`, { ...localInputs, - id: parseInt(channelId), + id: parseInt(channelId) }); } else { res = await API.post(`/api/channel`, localInputs); @@ -247,9 +258,9 @@ const EditChannel = () => { { key: 'plugin', text: '微信中的企业微信插件', - value: 'plugin', + value: 'plugin' }, - { key: 'app', text: '企业微信 APP', value: 'app' }, + { key: 'app', text: '企业微信 APP', value: 'app' } ]} value={inputs.other} onChange={handleInputChange} @@ -465,10 +476,11 @@ const EditChannel = () => { return ( <> - 通过 OneBot 协议进行推送,可以使用 cqhttp 等实现。 + 通过 OneBot 协议进行推送,可以使用 cqhttp 等实现。 利用 OneBot 协议可以实现推送 QQ 消息。 - + { ); + case 'group': + return ( + <> + + 对渠道进行分组,然后在推送时选择分组进行推送,可以实现一次性推送到多个渠道的功能。 +
+
+ 推送目标如若不填,则使用子渠道的默认推送目标。如果填写,请务必全部按顺序填写,对于不需要指定的直接留空即可,例如 123456789||@wechat,两个连续的分隔符表示跳过该渠道。 +
+ + + + + + ); case 'none': return ( <>