Merge branch 'dev'
This commit is contained in:
@@ -17,3 +17,4 @@
|
|||||||
17. 支持数据统计展示
|
17. 支持数据统计展示
|
||||||
18. 支持docker部署,从环境变量启动
|
18. 支持docker部署,从环境变量启动
|
||||||
19. 支持微信测试公众号模板消息发送
|
19. 支持微信测试公众号模板消息发送
|
||||||
|
20. 支持设置自定义的定时消息推送
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"message-nest/pkg/logging"
|
"message-nest/pkg/logging"
|
||||||
"message-nest/pkg/setting"
|
"message-nest/pkg/setting"
|
||||||
"message-nest/routers"
|
"message-nest/routers"
|
||||||
|
"message-nest/service/cron_msg_service"
|
||||||
"message-nest/service/cron_service"
|
"message-nest/service/cron_service"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -34,6 +35,7 @@ func init() {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cron_service.StartLogsCronRun()
|
cron_service.StartLogsCronRun()
|
||||||
|
cron_msg_service.StartUpMsgCronTask()
|
||||||
|
|
||||||
gin.SetMode(setting.ServerSetting.RunMode)
|
gin.SetMode(setting.ServerSetting.RunMode)
|
||||||
routersInit := routers.InitRouter(f)
|
routersInit := routers.InitRouter(f)
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ func Setup() {
|
|||||||
&models.SendTasksLogs{},
|
&models.SendTasksLogs{},
|
||||||
&models.SendTasksIns{},
|
&models.SendTasksIns{},
|
||||||
&models.Settings{},
|
&models.Settings{},
|
||||||
|
&models.CronMessages{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, table := range tables {
|
for _, table := range tables {
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
"message-nest/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CronMessages struct {
|
||||||
|
UUIDModel
|
||||||
|
|
||||||
|
Name string `json:"name" gorm:"type:varchar(200) comment '关联的消息名称';default:'';"`
|
||||||
|
TaskID string `json:"task_id" gorm:"type:varchar(36) comment '关联的消息ID';default:'';"`
|
||||||
|
Cron string `json:"cron" gorm:"type:varchar(4096) comment '定时表达式';default:'';"`
|
||||||
|
Title string `json:"title" gorm:"type:varchar(1000) comment '消息名称';default:'';"`
|
||||||
|
Content string `json:"content" gorm:"type:varchar(4096) comment '消息内容';default:'';"`
|
||||||
|
//MarkDown string `json:"markdown" gorm:"type:varchar(4096) comment 'markdown内容';default:'';"`
|
||||||
|
Url string `json:"url" gorm:"type:varchar(4096) comment 'url地址';default:'';"`
|
||||||
|
Enable int `json:"enable" gorm:"type:int comment '开启、暂停状态';default:1;"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateMsgUniqueID() string {
|
||||||
|
newUUID := util.GenerateUniqueID()
|
||||||
|
return fmt.Sprintf("C-%s", newUUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddSendCronMsg(
|
||||||
|
name string,
|
||||||
|
task_id string,
|
||||||
|
cron string,
|
||||||
|
title string,
|
||||||
|
content string,
|
||||||
|
url string,
|
||||||
|
createdBy string,
|
||||||
|
) (string, error) {
|
||||||
|
newUUID := GenerateMsgUniqueID()
|
||||||
|
msg := CronMessages{
|
||||||
|
UUIDModel: UUIDModel{
|
||||||
|
ID: newUUID,
|
||||||
|
CreatedBy: createdBy,
|
||||||
|
ModifiedBy: createdBy,
|
||||||
|
},
|
||||||
|
Name: name,
|
||||||
|
TaskID: task_id,
|
||||||
|
Cron: cron,
|
||||||
|
Title: title,
|
||||||
|
Content: content,
|
||||||
|
Url: url,
|
||||||
|
Enable: 1,
|
||||||
|
}
|
||||||
|
if err := db.Create(&msg).Error; err != nil {
|
||||||
|
return newUUID, err
|
||||||
|
}
|
||||||
|
return newUUID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCronMessages 获取所有任务
|
||||||
|
func GetCronMessages(pageNum int, pageSize int, name string, maps interface{}) ([]CronMessages, error) {
|
||||||
|
var (
|
||||||
|
msgs []CronMessages
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
query := db.Where(maps)
|
||||||
|
if name != "" {
|
||||||
|
query = query.Where("name like ?", fmt.Sprintf("%%%s%%", name))
|
||||||
|
}
|
||||||
|
query = query.Order("created_on DESC")
|
||||||
|
if pageSize > 0 || pageNum > 0 {
|
||||||
|
query = query.Offset(pageNum).Limit(pageSize)
|
||||||
|
}
|
||||||
|
err = query.Find(&msgs).Error
|
||||||
|
if err != nil && err != gorm.ErrRecordNotFound {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return msgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCronMessagesTotal 获取所有任务总数
|
||||||
|
func GetCronMessagesTotal(name string, maps interface{}) (int, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
total int
|
||||||
|
)
|
||||||
|
query := db.Model(&CronMessages{}).Where(maps)
|
||||||
|
if name != "" {
|
||||||
|
query = query.Where("name like ?", fmt.Sprintf("%%%s%%", name))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = query.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteCronMsg(id string) error {
|
||||||
|
if err := db.Where("id = ?", id).Delete(&CronMessages{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EditCronMsg(id string, data interface{}) error {
|
||||||
|
if err := db.Model(&CronMessages{}).Where("id = ? ", id).Updates(data).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCronMsgByID(id string) (CronMessages, error) {
|
||||||
|
var msg CronMessages
|
||||||
|
err := db.Where("id = ? ", id).Find(&msg).Error
|
||||||
|
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return msg, err
|
||||||
|
}
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
@@ -174,3 +174,12 @@ func EditSendTask(id string, data interface{}) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetTaskByID(id string) (SendTasks, error) {
|
||||||
|
var task SendTasks
|
||||||
|
err := db.Where("id = ? ", id).Find(&task).Error
|
||||||
|
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return task, err
|
||||||
|
}
|
||||||
|
return task, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
|
import "github.com/robfig/cron/v3"
|
||||||
|
|
||||||
const CleanLogsTaskId = "T-IM1GBswSRY"
|
const CleanLogsTaskId = "T-IM1GBswSRY"
|
||||||
const SiteSettingSectionName = "site_config"
|
const SiteSettingSectionName = "site_config"
|
||||||
|
|
||||||
@@ -31,4 +33,5 @@ const AboutSectionName = "about"
|
|||||||
// 限制goroutine的最大数量
|
// 限制goroutine的最大数量
|
||||||
var MaxSendTaskSemaphoreChan = make(chan string, 2048)
|
var MaxSendTaskSemaphoreChan = make(chan string, 2048)
|
||||||
|
|
||||||
// 内存缓存存放所有的微信公共号的缓存实例
|
// cron消息任务内存缓存map
|
||||||
|
var CronMsgIdMapMemoryCache = make(map[string]cron.EntryID)
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"message-nest/pkg/e"
|
||||||
|
"message-nest/pkg/util"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"message-nest/pkg/app"
|
||||||
|
"message-nest/service/cron_msg_service"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteCronMsgTaskReq struct {
|
||||||
|
ID string `json:"id" validate:"required,len=12" label:"任务id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCronMsgTask 删除定时消息
|
||||||
|
func DeleteCronMsgTask(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
appG = app.Gin{C: c}
|
||||||
|
req DeleteCronMsgTaskReq
|
||||||
|
)
|
||||||
|
|
||||||
|
errCode, errMsg := app.BindJsonAndPlayValid(c, &req)
|
||||||
|
if errCode != e.SUCCESS {
|
||||||
|
appG.CResponse(errCode, errMsg, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CronMsgService := cron_msg_service.CronMsgService{
|
||||||
|
ID: req.ID,
|
||||||
|
}
|
||||||
|
msg, _ := CronMsgService.GetByID()
|
||||||
|
|
||||||
|
err := CronMsgService.Delete()
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusBadRequest, "删除定时消息失败!", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cron_msg_service.RemoveCronMsgToCronServer(msg)
|
||||||
|
appG.CResponse(http.StatusOK, "删除定时消息成功!", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCronMsgList 获取定时消息列表
|
||||||
|
func GetCronMsgList(c *gin.Context) {
|
||||||
|
appG := app.Gin{C: c}
|
||||||
|
name := c.Query("name")
|
||||||
|
|
||||||
|
offset, limit := util.GetPageSize(c)
|
||||||
|
CronMsgService := cron_msg_service.CronMsgService{
|
||||||
|
Name: name,
|
||||||
|
PageNum: offset,
|
||||||
|
PageSize: limit,
|
||||||
|
}
|
||||||
|
tasks, err := CronMsgService.GetAll()
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusInternalServerError, "获取定时消息失败!", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := CronMsgService.Count()
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusInternalServerError, "获取定时消息总数失败!", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
appG.CResponse(http.StatusOK, "获取定时消息成功", map[string]interface{}{
|
||||||
|
"lists": tasks,
|
||||||
|
"total": count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddCronMsgTaskReq struct {
|
||||||
|
Name string `json:"name" validate:"required,max=100,min=1" label:"消息名称"`
|
||||||
|
TaskID string `json:"task_id" validate:"required,max=100,min=1" label:"关联的任务id"`
|
||||||
|
Cron string `json:"cron" validate:"required,cron" label:"cron表达式"`
|
||||||
|
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:"消息详情地址"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCronMsgTask 添加定时消息
|
||||||
|
func AddCronMsgTask(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
appG = app.Gin{C: c}
|
||||||
|
req AddCronMsgTaskReq
|
||||||
|
)
|
||||||
|
|
||||||
|
currentUser := app.GetCurrentUserName(c)
|
||||||
|
errCode, errStr := app.BindJsonAndPlayValid(c, &req)
|
||||||
|
if errCode != e.SUCCESS {
|
||||||
|
appG.CResponse(errCode, errStr, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CronMsgService := cron_msg_service.CronMsgService{
|
||||||
|
Name: req.Name,
|
||||||
|
TaskID: req.TaskID,
|
||||||
|
Cron: req.Cron,
|
||||||
|
Title: req.Title,
|
||||||
|
Content: req.Content,
|
||||||
|
Url: req.Url,
|
||||||
|
CreatedBy: currentUser,
|
||||||
|
ModifiedBy: currentUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
uuidstr, err := CronMsgService.Add()
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusBadRequest, "添加定时消息失败!", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CronMsgService.ID = uuidstr
|
||||||
|
msg, _ := CronMsgService.GetByID()
|
||||||
|
cron_msg_service.UpdateCronMsgToCronServer(msg)
|
||||||
|
appG.CResponse(http.StatusOK, "添加定时消息成功!", nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type EditCronMsgTaskReq struct {
|
||||||
|
ID string `json:"id" validate:"required,len=12" label:"定时消息id"`
|
||||||
|
Name string `json:"name" validate:"required,max=100,min=1" label:"消息名称"`
|
||||||
|
TaskID string `json:"task_id" validate:"required,max=100,min=1" label:"关联的任务id"`
|
||||||
|
Cron string `json:"cron" validate:"required,cron" label:"cron表达式"`
|
||||||
|
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:"消息详情地址"`
|
||||||
|
Enable int `json:"enable" validate:"oneof=0 1" label:"是否开启"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditCronMsgTask 编辑定时消息任务
|
||||||
|
func EditCronMsgTask(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
appG = app.Gin{C: c}
|
||||||
|
req EditCronMsgTaskReq
|
||||||
|
)
|
||||||
|
|
||||||
|
errCode, errMsg := app.BindJsonAndPlayValid(c, &req)
|
||||||
|
if errCode != e.SUCCESS {
|
||||||
|
appG.CResponse(errCode, errMsg, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CronMsgService := cron_msg_service.CronMsgService{
|
||||||
|
ID: req.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
data["name"] = req.Name
|
||||||
|
data["task_id"] = req.TaskID
|
||||||
|
data["cron"] = req.Cron
|
||||||
|
data["title"] = req.Title
|
||||||
|
data["content"] = req.Content
|
||||||
|
data["url"] = req.Url
|
||||||
|
data["enable"] = req.Enable
|
||||||
|
err := CronMsgService.Edit(data)
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusBadRequest, "编辑定时消息失败!", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg, _ := CronMsgService.GetByID()
|
||||||
|
cron_msg_service.UpdateCronMsgToCronServer(msg)
|
||||||
|
appG.CResponse(http.StatusOK, "编辑定时消息成功!", nil)
|
||||||
|
}
|
||||||
@@ -134,3 +134,26 @@ func EditMsgSendTask(c *gin.Context) {
|
|||||||
|
|
||||||
appG.CResponse(http.StatusOK, "编辑发信任务成功!", nil)
|
appG.CResponse(http.StatusOK, "编辑发信任务成功!", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMsgSendTask 获取消息任务
|
||||||
|
func GetMsgSendTask(c *gin.Context) {
|
||||||
|
appG := app.Gin{C: c}
|
||||||
|
id := c.Query("id")
|
||||||
|
|
||||||
|
if id == "" {
|
||||||
|
appG.CResponse(http.StatusBadRequest, "任务id为空!", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTaskService := send_task_service.SendTaskService{
|
||||||
|
ID: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
task, err := sendTaskService.GetByID()
|
||||||
|
if err != nil {
|
||||||
|
appG.CResponse(http.StatusBadRequest, "获取到的任务信息为空!", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
appG.CResponse(http.StatusOK, "获取任务信息成功", task)
|
||||||
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ func InitRouter(f embed.FS) *gin.Engine {
|
|||||||
apiV1.POST("/sendtasks/add", v1.AddMsgSendTask)
|
apiV1.POST("/sendtasks/add", v1.AddMsgSendTask)
|
||||||
apiV1.POST("/sendtasks/delete", v1.DeleteMsgSendTask)
|
apiV1.POST("/sendtasks/delete", v1.DeleteMsgSendTask)
|
||||||
apiV1.POST("/sendtasks/edit", v1.EditMsgSendTask)
|
apiV1.POST("/sendtasks/edit", v1.EditMsgSendTask)
|
||||||
|
apiV1.GET("/sendtasks/get", v1.GetMsgSendTask)
|
||||||
|
|
||||||
// sendtasks/ins
|
// sendtasks/ins
|
||||||
apiV1.POST("/sendtasks/ins/addmany", v1.AddManyTasksIns)
|
apiV1.POST("/sendtasks/ins/addmany", v1.AddManyTasksIns)
|
||||||
@@ -84,6 +85,12 @@ func InitRouter(f embed.FS) *gin.Engine {
|
|||||||
// statistic
|
// statistic
|
||||||
apiV1.GET("/statistic", v1.GetStatisticData)
|
apiV1.GET("/statistic", v1.GetStatisticData)
|
||||||
|
|
||||||
|
// cronMessage
|
||||||
|
apiV1.POST("/sendmessages/addone", v1.AddCronMsgTask)
|
||||||
|
apiV1.GET("/sendmessages/list", v1.GetCronMsgList)
|
||||||
|
apiV1.POST("/sendmessages/delete", v1.DeleteCronMsgTask)
|
||||||
|
apiV1.POST("/sendmessages/edit", v1.EditCronMsgTask)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package cron_msg_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"message-nest/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CronMsgService struct {
|
||||||
|
ID string
|
||||||
|
|
||||||
|
Name string
|
||||||
|
TaskID string
|
||||||
|
Cron string
|
||||||
|
Title string
|
||||||
|
Content string
|
||||||
|
Url string
|
||||||
|
|
||||||
|
CreatedBy string
|
||||||
|
ModifiedBy string
|
||||||
|
CreatedOn string
|
||||||
|
|
||||||
|
PageNum int
|
||||||
|
PageSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *CronMsgService) Add() (string, error) {
|
||||||
|
return models.AddSendCronMsg(st.Name, st.TaskID, st.Cron, st.Title, st.Content, st.Url, st.CreatedBy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *CronMsgService) Edit(data map[string]interface{}) error {
|
||||||
|
return models.EditCronMsg(st.ID, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *CronMsgService) GetByID() (models.CronMessages, error) {
|
||||||
|
return models.GetCronMsgByID(st.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *CronMsgService) Count() (int, error) {
|
||||||
|
return models.GetCronMessagesTotal(st.Name, st.getMaps())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *CronMsgService) GetAll() ([]models.CronMessages, error) {
|
||||||
|
msgs, err := models.GetCronMessages(st.PageNum, st.PageSize, st.Name, st.getMaps())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return msgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *CronMsgService) getMaps() map[string]interface{} {
|
||||||
|
maps := make(map[string]interface{})
|
||||||
|
return maps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *CronMsgService) Delete() error {
|
||||||
|
return models.DeleteCronMsg(st.ID)
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package cron_msg_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"message-nest/models"
|
||||||
|
"message-nest/pkg/constant"
|
||||||
|
"message-nest/service/cron_service"
|
||||||
|
"message-nest/service/send_message_service"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MsgCronTask struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s MsgCronTask) Register() {
|
||||||
|
// 获取所有的定时消息任务
|
||||||
|
limit := 10000
|
||||||
|
filter := make(map[string]interface{})
|
||||||
|
filter["enable"] = 1
|
||||||
|
data, err := models.GetCronMessages(0, limit, "", filter)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("获取定时消息任务失败!原因:%s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
logrus.Infof("没有定时消息任务需要注册")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//注册定时任务
|
||||||
|
for _, msg := range data {
|
||||||
|
AddCronMsgToCronServer(msg)
|
||||||
|
}
|
||||||
|
length := len(data)
|
||||||
|
if length > 0 {
|
||||||
|
logrus.Infof("完成用户自定义的定时消息注册,个数:%d", length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCronMsgToCronServer 注册定时任务到定时服务
|
||||||
|
func AddCronMsgToCronServer(msg models.CronMessages) {
|
||||||
|
if msg.Enable != 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
taskId := cron_service.AddTask(cron_service.ScheduledTask{
|
||||||
|
Schedule: msg.Cron,
|
||||||
|
Job: func() {
|
||||||
|
CronMsgSendF(msg)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
constant.CronMsgIdMapMemoryCache[msg.ID] = taskId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行任务的构造函数
|
||||||
|
func CronMsgSendF(msg models.CronMessages) {
|
||||||
|
logrus.Infof("开始只能执行定时消息发送任务: %s , 消息名: %s", msg.ID, msg.Name)
|
||||||
|
task, err := models.GetTaskByID(msg.TaskID)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Infof("消息任务不存在: %s ", msg.TaskID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sender := send_message_service.SendMessageService{
|
||||||
|
TaskID: task.ID,
|
||||||
|
Title: msg.Title,
|
||||||
|
Text: msg.Content,
|
||||||
|
URL: msg.Url,
|
||||||
|
CallerIp: "corn",
|
||||||
|
DefaultLogger: logrus.WithFields(logrus.Fields{
|
||||||
|
"prefix": "[Cron Message]",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
taskData, _ := sender.SendPreCheck()
|
||||||
|
sender.Send(taskData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateCronMsgToCronServer 更新定时服务的任务
|
||||||
|
func UpdateCronMsgToCronServer(msg models.CronMessages) {
|
||||||
|
if entryId, ok := constant.CronMsgIdMapMemoryCache[msg.ID]; ok {
|
||||||
|
// 先删除之前的定时任务
|
||||||
|
delete(constant.CronMsgIdMapMemoryCache, msg.ID)
|
||||||
|
cron_service.RemoveTask(entryId)
|
||||||
|
// 再注册新的定时任务
|
||||||
|
AddCronMsgToCronServer(msg)
|
||||||
|
} else {
|
||||||
|
// 注册新的定时任务
|
||||||
|
AddCronMsgToCronServer(msg)
|
||||||
|
}
|
||||||
|
logrus.Infof("完成定时消息的定时更新,消息id: %s, 总数:%d", msg.ID, len(constant.CronMsgIdMapMemoryCache))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveCronMsgToCronServer 删除定时任务中心的任务
|
||||||
|
func RemoveCronMsgToCronServer(msg models.CronMessages) {
|
||||||
|
if entryId, ok := constant.CronMsgIdMapMemoryCache[msg.ID]; ok {
|
||||||
|
// 先删除之前的定时任务
|
||||||
|
delete(constant.CronMsgIdMapMemoryCache, msg.ID)
|
||||||
|
cron_service.RemoveTask(entryId)
|
||||||
|
}
|
||||||
|
logrus.Infof("完成定时消息的定时删除,消息id: %s, 总数:%d", msg.ID, len(constant.CronMsgIdMapMemoryCache))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartUpMsgCronTask 启动注册定时任务
|
||||||
|
func StartUpMsgCronTask() {
|
||||||
|
MsgCronTask{}.Register()
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ func AddTask(task ScheduledTask) cron.EntryID {
|
|||||||
logrus.Errorf("注册定时任务失败, job: %s, 原因:%s", jobName, err)
|
logrus.Errorf("注册定时任务失败, job: %s, 原因:%s", jobName, err)
|
||||||
} else {
|
} else {
|
||||||
TaskList[taskId] = &task
|
TaskList[taskId] = &task
|
||||||
logrus.Infof("注册定时任务成功, job: %s, entryID: %d, cron: %s", jobName, taskId, task.Schedule)
|
//logrus.Infof("注册定时任务成功, job: %s, entryID: %d, cron: %s", jobName, taskId, task.Schedule)
|
||||||
}
|
}
|
||||||
return taskId
|
return taskId
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,3 +51,7 @@ func (st *SendTaskService) getMaps() map[string]interface{} {
|
|||||||
maps := make(map[string]interface{})
|
maps := make(map[string]interface{})
|
||||||
return maps
|
return maps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (st *SendTaskService) GetByID() (interface{}, error) {
|
||||||
|
return models.GetTaskByID(st.ID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ const router = createRouter({
|
|||||||
name: 'sendtasks',
|
name: 'sendtasks',
|
||||||
component: () => import('../views/tabsTools/sendTasks/sendTasks.vue')
|
component: () => import('../views/tabsTools/sendTasks/sendTasks.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/sendmessages',
|
||||||
|
name: 'sendmessages',
|
||||||
|
component: () => import('../views/tabsTools/sendMessage/sensMessage.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/sendlogs',
|
path: '/sendlogs',
|
||||||
name: 'sendlogs',
|
name: 'sendlogs',
|
||||||
|
|||||||
@@ -35,9 +35,10 @@ export default {
|
|||||||
const menuData = reactive([
|
const menuData = reactive([
|
||||||
{ id: '0', title: '数据统计', path: '/statistic' },
|
{ id: '0', title: '数据统计', path: '/statistic' },
|
||||||
{ id: '1', title: '发信日志', path: '/sendlogs' },
|
{ id: '1', title: '发信日志', path: '/sendlogs' },
|
||||||
{ id: '2', title: '发信任务', path: '/sendtasks' },
|
{ id: '2', title: '定时发信', path: '/sendmessages' },
|
||||||
{ id: '3', title: '发信渠道', path: '/sendways' },
|
{ id: '3', title: '发信任务', path: '/sendtasks' },
|
||||||
{ id: '4', title: '设置', path: '/settings' },
|
{ id: '4', title: '发信渠道', path: '/sendways' },
|
||||||
|
{ id: '5', title: '设置', path: '/settings' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const checkIsLogin = () => {
|
const checkIsLogin = () => {
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main-center-body">
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<div class="search-input-sendways">
|
||||||
|
<el-input v-model="search" size="small" placeholder="搜索" @change="filterFunc()" />
|
||||||
|
</div>
|
||||||
|
<div class="search-box">
|
||||||
|
<el-button size="small" type="primary" @click="clickAdd">新增定时消息</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div ref="refContainer">
|
||||||
|
<el-table :data="tableData" stripe empty-text="定时发信为空" :row-style="rowStyle()">
|
||||||
|
<el-table-column label="消息ID" prop="id" />
|
||||||
|
<el-table-column label="关联ID" prop="task_id" />
|
||||||
|
<el-table-column label="消息名" prop="name" />
|
||||||
|
<el-table-column label="Cron" prop="cron" />
|
||||||
|
<el-table-column label="消息内容" prop="content" />
|
||||||
|
<el-table-column label="创建时间" prop="created_on" />
|
||||||
|
<el-table-column fixed="right" label="操作" width="190px">
|
||||||
|
<template #default="scope">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- <el-button link size="small" type="primary" @click="handleViewAPI(scope.$index, scope.row)">接口</el-button> -->
|
||||||
|
<el-button link size="small" type="primary"
|
||||||
|
@click="handleViewLogs(scope.$index, scope.row)">日志</el-button>
|
||||||
|
<el-button link size="small" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
|
||||||
|
<tableDeleteButton @customHandleDelete="handleDelete(scope.$index, scope.row)" />
|
||||||
|
|
||||||
|
<el-switch v-model.bool="scope.row.enable" inline-prompt active-text="开启" inactive-text="关闭"
|
||||||
|
@click="updateEnableStatus(scope.row)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pagination-block">
|
||||||
|
<el-pagination layout="prev, pager, next" :total="total" :page-size="pageSize"
|
||||||
|
@current-change="handPageChange" />
|
||||||
|
<el-text class="total-tip" size="small">每页{{ pageSize }}条,共{{ total }}条</el-text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<addCronMsgPopUpComponent :componentName="addCronMsgPopUpComponentName" />
|
||||||
|
<editCronMsgPopUpComponent :componentName="editCronMsgPopUpComponentName" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { computed, ref, reactive, toRefs, onMounted } from 'vue'
|
||||||
|
import { usePageState } from '@/store/page_sate';
|
||||||
|
import { request } from '@/api/api'
|
||||||
|
import addCronMsgPopUpComponent from './view/addCronMsgPopUp.vue'
|
||||||
|
import editCronMsgPopUpComponent from './view/editCronMsgPopUp.vue'
|
||||||
|
import tableDeleteButton from '@/views/common/tableDeleteButton.vue'
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { CONSTANT } from '@/constant'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
addCronMsgPopUpComponent,
|
||||||
|
editCronMsgPopUpComponent,
|
||||||
|
tableDeleteButton,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const pageState = usePageState();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
addCronMsgPopUpComponentName: 'addCronMsgPopUpComponentName',
|
||||||
|
editCronMsgPopUpComponentName: 'editCronMsgPopUpComponentName',
|
||||||
|
search: '',
|
||||||
|
optionValue: '',
|
||||||
|
dialogFormVisible: false,
|
||||||
|
tableData: [],
|
||||||
|
total: CONSTANT.TOTAL,
|
||||||
|
pageSize: pageState.siteConfigData.pagesize,
|
||||||
|
currPage: CONSTANT.PAGE,
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleEdit = (index, row) => {
|
||||||
|
let name = state.editCronMsgPopUpComponentName;
|
||||||
|
pageState.ShowDialogData[name] = {};
|
||||||
|
pageState.ShowDialogData[name].isShow = true;
|
||||||
|
pageState.ShowDialogData[name].rowData = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = async (index, row) => {
|
||||||
|
const rsp = await request.post('/sendmessages/delete', { id: row.id });
|
||||||
|
if (rsp.status == 200) {
|
||||||
|
state.tableData.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handPageChange = async (pageNum) => {
|
||||||
|
state.currPage = pageNum;
|
||||||
|
await queryListData(pageNum, state.pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowStyle = () => {
|
||||||
|
return {
|
||||||
|
'font-size': '13px',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleViewLogs = (index, row) => {
|
||||||
|
router.push('/sendlogs?taskid=' + row.task_id, { replace: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterFunc = async () => {
|
||||||
|
await queryListData(state.currPage, state.pageSize, state.search, state.optionValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clickAdd = () => {
|
||||||
|
pageState.ShowDialogData[state.addCronMsgPopUpComponentName] = {};
|
||||||
|
pageState.ShowDialogData[state.addCronMsgPopUpComponentName].isShow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryListData = async (page, size, name = '') => {
|
||||||
|
let params = { page: page, size: size, name: name };
|
||||||
|
const rsp = await request.get('/sendmessages/list', { params: params });
|
||||||
|
state.tableData = await rsp.data.data.lists;
|
||||||
|
dealInsEnableStatus(state.tableData)
|
||||||
|
state.total = await rsp.data.data.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dealInsEnableStatus = (data) => {
|
||||||
|
data.forEach(ins => {
|
||||||
|
ins.enable = ins.enable == 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开启暂停定时任务
|
||||||
|
const updateEnableStatus = async (data) => {
|
||||||
|
data.enable = !Boolean(data.enable) ? 0 : 1
|
||||||
|
const rsp = await request.post('/sendmessages/edit', data);
|
||||||
|
if (await rsp.data.code == 200) {
|
||||||
|
ElMessage({ message: await rsp.data.msg, type: 'success' });
|
||||||
|
data.enable = Boolean(data.enable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await queryListData(1, state.pageSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(state), handleEdit, handleDelete, handleViewLogs,
|
||||||
|
clickAdd, rowStyle, handPageChange, filterFunc, updateEnableStatus
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
hr {
|
||||||
|
color: #FAFCFF;
|
||||||
|
background-color: #FAFCFF;
|
||||||
|
border-color: #FAFCFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
max-width: 1000px;
|
||||||
|
width: 100%;
|
||||||
|
/* margin-top: -10vh; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-block {
|
||||||
|
margin-top: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-tip {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.select .el-input__inner) {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-sendways {
|
||||||
|
/* margin-left: 40px; */
|
||||||
|
width: 150px;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.op-col {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="isShow" width="400px" :close-on-press-escape="false" :before-close="() => { }"
|
||||||
|
:show-close="false">
|
||||||
|
<template #header="">
|
||||||
|
<el-text class="mx-1">添加定时消息发送</el-text>
|
||||||
|
<el-tooltip placement="top">
|
||||||
|
<template #content>
|
||||||
|
可以定制一些定时消息通知,完成一些简单的提醒事件
|
||||||
|
<br />
|
||||||
|
** 需要基于已经创建的发信任务进行绑定
|
||||||
|
</template>
|
||||||
|
<el-icon>
|
||||||
|
<QuestionFilled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="add-top">
|
||||||
|
<el-input v-model="currTaskInput.name" placeholder="请输入消息名称" size="small" class="nameInput"></el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ins-area">
|
||||||
|
|
||||||
|
<div class="ins-add">
|
||||||
|
<el-autocomplete v-model="currSearchInputText" size="small" :fetch-suggestions="querySearchWayAsync"
|
||||||
|
placeholder="请输入消息名进行搜索" @select="handleSearchSelect" :clearable="true" value-key="name" />
|
||||||
|
|
||||||
|
<div class="store-area" v-if="isShowAddBox">
|
||||||
|
|
||||||
|
<div class="display-label">
|
||||||
|
<el-text class="mx-1" size="small">消息ID:{{ currTaskTmp.id }}</el-text><br />
|
||||||
|
<el-text class="mx-1" size="small">消息名:{{ currTaskTmp.name }}</el-text><br />
|
||||||
|
<el-text class="mx-1" size="small">消息创建时间:{{ currTaskTmp.created_on }}</el-text><br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-input v-model="currTaskInput.title" placeholder="请输入消息标题" size="small" class="msg-input"></el-input>
|
||||||
|
<el-input type="textarea" :rows="5" v-model="currTaskInput.content" placeholder="请输入消息内容" size="small"
|
||||||
|
class="msg-input"></el-input>
|
||||||
|
<el-input v-model="currTaskInput.cron" placeholder="请输入定时cron表达式" size="small" class="msg-input"></el-input>
|
||||||
|
<el-input v-model="currTaskInput.url" placeholder="请输入消息详情url(可选)" size="small" class="msg-input"></el-input>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleCancer()" size="small">取消</el-button>
|
||||||
|
<!-- <el-button type="primary" size="small" @click="cliclSendNow()">
|
||||||
|
立即发送
|
||||||
|
</el-button> -->
|
||||||
|
<el-button type="primary" size="small" @click="handleSubmit()">
|
||||||
|
确定添加
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, onMounted, watch, reactive, toRefs } from 'vue';
|
||||||
|
import { _ } from 'lodash';
|
||||||
|
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||||
|
import { usePageState } from '@/store/page_sate.js';
|
||||||
|
import { request } from '@/api/api'
|
||||||
|
import { CONSTANT } from '@/constant'
|
||||||
|
import { CommonUtils } from "@/util/commonUtils.js";
|
||||||
|
import { generateBizUniqueID } from "@/util/uuid.js";
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
QuestionFilled,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
componentName: String
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const pageState = usePageState();
|
||||||
|
const state = reactive({
|
||||||
|
insTableData: [],
|
||||||
|
currSearchWaysData: [],
|
||||||
|
currSearchInputText: '',
|
||||||
|
isShow: false,
|
||||||
|
isShowAddBox: false,
|
||||||
|
searchway_id: '',
|
||||||
|
currTaskTmp: {},
|
||||||
|
currInsInput: {},
|
||||||
|
currInsInputContentType: 'text',
|
||||||
|
currTaskInput: {
|
||||||
|
name: '',
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
cron: '',
|
||||||
|
url: '',
|
||||||
|
id: generateBizUniqueID('C'),
|
||||||
|
},
|
||||||
|
sysKeptTaskIds: [CONSTANT.LOG_TASK_ID],
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(pageState.ShowDialogData, (newValue, oldValue) => {
|
||||||
|
if (newValue[props.componentName]) {
|
||||||
|
state.isShow = pageState.ShowDialogData[props.componentName].isShow;
|
||||||
|
resetPageInitData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCancer = () => {
|
||||||
|
if (pageState.ShowDialogData[props.componentName]) {
|
||||||
|
pageState.ShowDialogData[props.componentName].isShow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面每次弹出,重置数据
|
||||||
|
const resetPageInitData = () => {
|
||||||
|
state.insTableData = [];
|
||||||
|
state.currInsInputContentType = 'text';
|
||||||
|
state.currInsInput = {};
|
||||||
|
state.currTaskTmp = {};
|
||||||
|
state.searchway_id = '';
|
||||||
|
state.isShowAddBox = false;
|
||||||
|
state.currTaskInput = {
|
||||||
|
name: '',
|
||||||
|
id: generateBizUniqueID('C'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cliclSendNow = () => {
|
||||||
|
console.log('cliclSendNow');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配出当前搜索的消息数据
|
||||||
|
const matchSearchData = (way_name) => {
|
||||||
|
let result = {};
|
||||||
|
state.currSearchWaysData.forEach(element => {
|
||||||
|
if (element.name == way_name) {
|
||||||
|
result = element;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearchSelect = async () => {
|
||||||
|
let currTask = matchSearchData(state.currSearchInputText)
|
||||||
|
state.isShowAddBox = Boolean(currTask);
|
||||||
|
if (currTask) {
|
||||||
|
state.currTaskTmp = currTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const querySearchWayAsync = async (query, cb) => {
|
||||||
|
let params = { name: query };
|
||||||
|
const rsp = await request.get('/sendtasks/list', { params: params });
|
||||||
|
let tableData = await rsp.data.data.lists;
|
||||||
|
tableData = filtersysKeptTask(tableData);
|
||||||
|
cb(tableData);
|
||||||
|
state.currSearchWaysData = tableData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtersysKeptTask = (data) => {
|
||||||
|
let result = data.filter(item => !state.sysKeptTaskIds.includes(item.id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFinalData = () => {
|
||||||
|
state.currTaskInput.task_id = state.currTaskTmp.id;
|
||||||
|
return state.currTaskInput
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
let postData = getFinalData();
|
||||||
|
const rsp = await request.post('/sendmessages/addone', postData);
|
||||||
|
if (await rsp.data.code == 200) {
|
||||||
|
ElMessage({ message: await rsp.data.msg, type: 'success' });
|
||||||
|
handleCancer();
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(state), handleCancer, handleSubmit, querySearchWayAsync,
|
||||||
|
handleSearchSelect, CONSTANT, CommonUtils,
|
||||||
|
cliclSendNow
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.el-autocomplete) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-input {
|
||||||
|
/* width: 200px; */
|
||||||
|
margin: 5px 10px 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-top {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-label {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="isShow" width="400px" :close-on-press-escape="false" :before-close="() => { }"
|
||||||
|
:show-close="false">
|
||||||
|
<template #header="">
|
||||||
|
<el-text class="mx-1">编辑发信任务</el-text>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="add-top">
|
||||||
|
<el-input v-model="currTaskInput.name" placeholder="请输入消息名称" size="small" class="nameInput"></el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ins-area">
|
||||||
|
|
||||||
|
<div class="ins-add">
|
||||||
|
<el-autocomplete v-model="currSearchInputText" size="small" :fetch-suggestions="querySearchWayAsync"
|
||||||
|
placeholder="请输入任务名进行搜索" @select="handleSearchSelect" :clearable="true" value-key="name" />
|
||||||
|
|
||||||
|
<div class="store-area" v-if="isShowAddBox">
|
||||||
|
|
||||||
|
<div class="display-label">
|
||||||
|
<el-text class="mx-1" size="small">消息ID:{{ currTaskTmp.id }}</el-text><br />
|
||||||
|
<el-text class="mx-1" size="small">消息名:{{ currTaskTmp.name }}</el-text><br />
|
||||||
|
<el-text class="mx-1" size="small">消息创建时间:{{ currTaskTmp.created_on }}</el-text><br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-input v-model="currTaskInput.title" placeholder="请输入消息标题" size="small" class="msg-input"></el-input>
|
||||||
|
<el-input type="textarea" :rows="5" v-model="currTaskInput.content" placeholder="请输入消息内容" size="small"
|
||||||
|
class="msg-input"></el-input>
|
||||||
|
<el-input v-model="currTaskInput.cron" placeholder="请输入定时cron表达式" size="small" class="msg-input"></el-input>
|
||||||
|
<el-input v-model="currTaskInput.url" placeholder="请输入消息详情url(可选)" size="small" class="msg-input"></el-input>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleCancer()" size="small">取消</el-button>
|
||||||
|
<el-button type="primary" size="small" @click="handleEditCronMsg()">
|
||||||
|
确定修改
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, onMounted, watch, reactive, toRefs } from 'vue';
|
||||||
|
import { _ } from 'lodash';
|
||||||
|
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||||
|
import { usePageState } from '@/store/page_sate.js';
|
||||||
|
import { request } from '@/api/api'
|
||||||
|
import tableDeleteButton from '@/views/common/tableDeleteButton.vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { CONSTANT } from '@/constant'
|
||||||
|
import { CommonUtils } from "@/util/commonUtils.js";
|
||||||
|
import { generateBizUniqueID } from "@/util/uuid.js";
|
||||||
|
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
QuestionFilled,
|
||||||
|
tableDeleteButton,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
componentName: String
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const pageState = usePageState();
|
||||||
|
const state = reactive({
|
||||||
|
insTableData: [],
|
||||||
|
currSearchWaysData: [],
|
||||||
|
currSearchInputText: '',
|
||||||
|
isShow: false,
|
||||||
|
isShowAddBox: false,
|
||||||
|
searchWayID: '',
|
||||||
|
currInsInputContentType: '',
|
||||||
|
currTaskTmp: {},
|
||||||
|
currInsInput: {},
|
||||||
|
currTaskInput: {
|
||||||
|
name: '',
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
cron: '',
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
sysKeptTaskIds: [CONSTANT.LOG_TASK_ID],
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(pageState.ShowDialogData, (newValue, oldValue) => {
|
||||||
|
if (newValue[props.componentName]) {
|
||||||
|
let data = pageState.ShowDialogData[props.componentName];
|
||||||
|
state.isShow = data.isShow;
|
||||||
|
resetPageInitData();
|
||||||
|
state.currTaskInput.taskId = data.rowData.id;
|
||||||
|
if (data && state.isShow) {
|
||||||
|
state.currTaskInput = data.rowData;
|
||||||
|
InitOpenSeletValue(state.currTaskInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const InitOpenSeletValue = async (data) => {
|
||||||
|
// 填充编辑框数据
|
||||||
|
let task_id = data.task_id;
|
||||||
|
const rsp = await request.get('/sendtasks/get', { params: { id: task_id } });
|
||||||
|
let rsp_data = await rsp.data;
|
||||||
|
state.isShowAddBox = true;
|
||||||
|
state.currSearchInputText = rsp_data.data.name;
|
||||||
|
state.currTaskTmp = {
|
||||||
|
id: rsp_data.data.id,
|
||||||
|
name: rsp_data.data.name,
|
||||||
|
created_on: rsp_data.data.created_on,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCancer = () => {
|
||||||
|
if (pageState.ShowDialogData[props.componentName]) {
|
||||||
|
pageState.ShowDialogData[props.componentName].isShow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面每次弹出,重置数据
|
||||||
|
const resetPageInitData = () => {
|
||||||
|
state.insTableData = [];
|
||||||
|
state.currInsInput = {};
|
||||||
|
state.currTaskTmp = {};
|
||||||
|
state.currInsInput = {};
|
||||||
|
state.searchWayID = '';
|
||||||
|
state.currInsInputContentType = '';
|
||||||
|
state.isShowAddBox = false;
|
||||||
|
state.currTaskInput = {
|
||||||
|
taskName: '',
|
||||||
|
// taskId: uuidv4(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配出当前搜索的任务数据
|
||||||
|
const matchSearchData = (way_name) => {
|
||||||
|
let result = {};
|
||||||
|
state.currSearchWaysData.forEach(element => {
|
||||||
|
if (element.name == way_name) {
|
||||||
|
result = element;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearchSelect = async () => {
|
||||||
|
let currTask = matchSearchData(state.currSearchInputText)
|
||||||
|
state.isShowAddBox = Boolean(currTask);
|
||||||
|
if (currTask) {
|
||||||
|
state.currTaskTmp = currTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const querySearchWayAsync = async (query, cb) => {
|
||||||
|
let params = { name: query };
|
||||||
|
const rsp = await request.get('/sendtasks/list', { params: params });
|
||||||
|
let tableData = await rsp.data.data.lists;
|
||||||
|
tableData = filtersysKeptTask(tableData);
|
||||||
|
cb(tableData);
|
||||||
|
state.currSearchWaysData = tableData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtersysKeptTask = (data) => {
|
||||||
|
let result = data.filter(item => !state.sysKeptTaskIds.includes(item.id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFinalData = () => {
|
||||||
|
let postData = {
|
||||||
|
name: state.currTaskInput.name,
|
||||||
|
title: state.currTaskInput.title,
|
||||||
|
content: state.currTaskInput.content,
|
||||||
|
cron: state.currTaskInput.cron,
|
||||||
|
url: state.currTaskInput.url,
|
||||||
|
id: state.currTaskInput.id,
|
||||||
|
enable: state.currTaskInput.enable ? 1 : 0,
|
||||||
|
task_id: state.currTaskTmp.id,
|
||||||
|
};
|
||||||
|
return postData
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEditCronMsg = async () => {
|
||||||
|
let postData = getFinalData();
|
||||||
|
console.log('postdata', postData);
|
||||||
|
const rsp = await request.post('/sendmessages/edit', postData);
|
||||||
|
if (await rsp.data.code == 200) {
|
||||||
|
ElMessage({ message: await rsp.data.msg, type: 'success' });
|
||||||
|
setTimeout(() => {
|
||||||
|
handleCancer();
|
||||||
|
window.location.reload();
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(state), handleCancer, CONSTANT, CommonUtils,
|
||||||
|
handleSearchSelect, querySearchWayAsync, handleEditCronMsg
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.el-autocomplete) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-input {
|
||||||
|
/* width: 200px; */
|
||||||
|
margin: 5px 10px 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-top {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-label {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user