feat: add cronmessage sendNow

This commit is contained in:
engigu
2025-10-12 14:35:49 +08:00
parent 37b05958d5
commit c3e5fa2003
7 changed files with 197 additions and 1 deletions
+37
View File
@@ -161,3 +161,40 @@ func EditCronMsgTask(c *gin.Context) {
cron_msg_service.UpdateCronMsgToCronServer(msg)
appG.CResponse(http.StatusOK, "编辑定时消息成功!", nil)
}
type SendNowCronMsgReq struct {
TaskID string `json:"task_id" validate:"required,max=100,min=1" label:"关联的任务id"`
Title string `json:"title" validate:"required,max=100,min=1" label:"消息标题"`
Content string `json:"content" validate:"required,max=10000,min=1" label:"消息内容"`
Url string `json:"url" validate:"" label:"消息详情地址"`
}
// SendNowCronMsg 立即发送定时消息
func SendNowCronMsg(c *gin.Context) {
var (
appG = app.Gin{C: c}
req SendNowCronMsgReq
)
errCode, errMsg := app.BindJsonAndPlayValid(c, &req)
if errCode != e.SUCCESS {
appG.CResponse(errCode, errMsg, nil)
return
}
CronMsgService := cron_msg_service.CronMsgService{
TaskID: req.TaskID,
Title: req.Title,
Content: req.Content,
Url: req.Url,
}
// 调用立即发送服务
err := CronMsgService.SendNowByParams(c.ClientIP())
if err != nil {
appG.CResponse(http.StatusBadRequest, err.Error(), nil)
return
}
appG.CResponse(http.StatusOK, "发送成功!", nil)
}
+1
View File
@@ -93,6 +93,7 @@ func InitRouter(f embed.FS) *gin.Engine {
apiV1.GET("/cronmessages/list", v1.GetCronMsgList)
apiV1.POST("/cronmessages/delete", v1.DeleteCronMsgTask)
apiV1.POST("/cronmessages/edit", v1.EditCronMsgTask)
apiV1.POST("/cronmessages/sendnow", v1.SendNowCronMsg)
// hostedMessage
apiV1.GET("/hostedmessages/list", v1.GetHostMessageList)
+26
View File
@@ -85,3 +85,29 @@ func GetCronNextTime(cronExpr string) string {
nextTime := schedule.Next(time.Now()).Format("2006-01-02 15:04:05")
return nextTime
}
// SendNow 立即发送定时消息(根据定时消息ID)
func (st *CronMsgService) SendNow(callerIP string) error {
// 获取定时消息详情
msg, err := st.GetByID()
if err != nil {
return err
}
// 调用发送服务
return SendCronMessage(msg, callerIP)
}
// SendNowByParams 立即发送定时消息(根据传入的参数)
func (st *CronMsgService) SendNowByParams(callerIP string) error {
// 直接使用传入的参数构造消息对象
msg := models.CronMessages{
TaskID: st.TaskID,
Title: st.Title,
Content: st.Content,
Url: st.Url,
}
// 调用发送服务
return SendCronMessage(msg, callerIP)
}
@@ -2,6 +2,7 @@ package cron_msg_service
import (
"fmt"
"strings"
"github.com/sirupsen/logrus"
"message-nest/models"
"message-nest/pkg/constant"
@@ -106,3 +107,44 @@ func RemoveCronMsgToCronServer(msg models.CronMessages) {
func StartUpMsgCronTask() {
MsgCronTask{}.Register()
}
// SendCronMessage 发送定时消息(用于立即发送)
func SendCronMessage(msg models.CronMessages, callerIP string) error {
// 查询关联的发信任务
task, err := models.GetTaskByID(msg.TaskID)
if err != nil {
return fmt.Errorf("发信任务不存在: %s", msg.TaskID)
}
// 创建发送服务
sender := send_message_service.SendMessageService{
TaskID: task.ID,
Title: msg.Title,
Text: msg.Content,
URL: msg.Url,
CallerIp: callerIP,
DefaultLogger: logrus.WithFields(logrus.Fields{
"prefix": "[Manual Send Cron Message]",
}),
}
// 预检查
taskData, err := sender.SendPreCheck()
if err != nil {
errMsg := err.Error()
// 如果是没有关联实例的错误,返回更友好的提示
if strings.Contains(errMsg, "没有关联任何实例") {
return fmt.Errorf("该发信任务尚未配置发送实例,请先在【发信任务】页面为任务 [%s] 添加至少一个发送实例", task.Name)
}
return fmt.Errorf("发送预检查失败: %s", errMsg)
}
// 发送消息
_, err = sender.Send(taskData)
if err != nil {
return fmt.Errorf("发送失败: %s", err.Error())
}
logrus.Infof("立即发送定时消息成功,消息id: %s,消息名: %s", msg.ID, msg.Name)
return nil
}
@@ -69,6 +69,44 @@ const handleCancel = () => {
emit('cancel')
emit('update:open', false)
}
// 立即发送(新增模式也支持,可以在创建前测试发送效果)
const handleSendNow = async () => {
// 验证必填字段
if (!formData.task_id) {
toast.error('请先选择关联的发信任务')
return
}
if (!formData.title) {
toast.error('请先填写消息标题')
return
}
if (!formData.content) {
toast.error('请先填写消息内容')
return
}
loading.value = true
try {
const postData = {
task_id: formData.task_id,
title: formData.title,
content: formData.content,
url: formData.url
}
const rsp = await request.post('/cronmessages/sendnow', postData)
if (rsp.data.code === 200) {
toast.success(rsp.data.msg)
} else {
toast.error(rsp.data.msg)
}
} catch (error) {
toast.error('发送失败,请稍后重试')
} finally {
loading.value = false
}
}
</script>
<template>
@@ -82,6 +120,7 @@ const handleCancel = () => {
:loading="loading"
@submit="handleSubmit"
@cancel="handleCancel"
@send-now="handleSendNow"
/>
</template>
@@ -8,7 +8,7 @@ import { Textarea } from '@/components/ui/textarea'
import { request } from '@/api/api'
interface CronMessageFormData {
id?: number
id?: string
name: string
cron_expression: string
title: string
@@ -27,6 +27,7 @@ interface Emits {
(e: 'update:modelValue', value: CronMessageFormData): void
(e: 'submit'): void
(e: 'cancel'): void
(e: 'sendNow'): void
}
const props = withDefaults(defineProps<Props>(), {
@@ -92,6 +93,11 @@ const handleCancel = () => {
emit('cancel')
}
// 立即发送
const handleSendNow = () => {
emit('sendNow')
}
// 组件挂载时加载数据
loadAvailableTasks()
</script>
@@ -117,6 +123,9 @@ loadAvailableTasks()
</SelectGroup>
</SelectContent>
</Select>
<p class="text-xs text-gray-500">
⚠️ 请确保所选任务已配置至少一个发送实例,否则无法发送
</p>
</div>
<div class="space-y-1">
@@ -152,6 +161,9 @@ loadAvailableTasks()
<Button variant="outline" @click="handleCancel" size="sm" :disabled="loading">
取消
</Button>
<Button variant="secondary" @click="handleSendNow" size="sm" :disabled="loading">
立即发送
</Button>
<Button @click="handleSubmit" size="sm" :disabled="loading">
{{ mode === 'add' ? '创建定时消息' : '更新定时消息' }}
</Button>
@@ -89,6 +89,44 @@ const handleCancel = () => {
emit('update:open', false)
}
// 立即发送
const handleSendNow = async () => {
// 验证必填字段
if (!formData.task_id) {
toast.error('请先选择关联的发信任务')
return
}
if (!formData.title) {
toast.error('请先填写消息标题')
return
}
if (!formData.content) {
toast.error('请先填写消息内容')
return
}
loading.value = true
try {
const postData = {
task_id: formData.task_id,
title: formData.title,
content: formData.content,
url: formData.url
}
const rsp = await request.post('/cronmessages/sendnow', postData)
if (rsp.data.code === 200) {
toast.success(rsp.data.msg)
} else {
toast.error(rsp.data.msg)
}
} catch (error) {
toast.error('发送失败,请稍后重试')
} finally {
loading.value = false
}
}
// 监听 cronMessage 变化,更新表单数据
watch(
() => props.cronMessage,
@@ -114,6 +152,7 @@ watch(
:loading="loading"
@submit="handleSubmit"
@cancel="handleCancel"
@send-now="handleSendNow"
/>
</template>