feat: add hosted message
This commit is contained in:
@@ -19,3 +19,4 @@
|
||||
19. 支持微信测试公众号模板消息发送
|
||||
20. 支持设置自定义的定时消息推送
|
||||
21. 支持sqlite部署,支持不同版本mysql
|
||||
22. 增加托管消息,现在可以将站点作为消息的接受,登录站点查看消息
|
||||
|
||||
@@ -65,6 +65,7 @@ func Setup() {
|
||||
&models.SendTasksIns{},
|
||||
&models.Settings{},
|
||||
&models.CronMessages{},
|
||||
&models.HostedMessage{},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"message-nest/pkg/util"
|
||||
)
|
||||
|
||||
type HostedMessage struct {
|
||||
ID int `gorm:"primaryKey" json:"id" `
|
||||
Title string `json:"title" gorm:"type:text ;"`
|
||||
Content string `json:"content" gorm:"type:text ;"`
|
||||
Type string `json:"type" gorm:"type:varchar(100) ;default:'';index"`
|
||||
|
||||
CreatedAt util.Time `json:"created_on" gorm:"column:created_on;autoCreateTime "`
|
||||
UpdatedAt util.Time `json:"modified_on" gorm:"column:modified_on;autoUpdateTime ;"`
|
||||
}
|
||||
|
||||
// Add 添加托管消息
|
||||
func (message *HostedMessage) Add() error {
|
||||
if err := db.Create(&message).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 托管消息的结果
|
||||
type HostMessageResult struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Type string `json:"type"`
|
||||
CreatedOn util.Time `json:"created_on"`
|
||||
ModifiedOn util.Time `json:"modified_on"`
|
||||
}
|
||||
|
||||
// GetHostMessages 获取所有托管消息记录
|
||||
func GetHostMessages(pageNum int, pageSize int, text string, maps map[string]interface{}) ([]HostMessageResult, error) {
|
||||
var datas []HostMessageResult
|
||||
hostMessageT := GetSchema(HostedMessage{})
|
||||
|
||||
query := db.Table(hostMessageT)
|
||||
|
||||
//dayVal, ok := maps["day_created_on"]
|
||||
//if ok {
|
||||
// delete(maps, "day_created_on")
|
||||
// query = query.Where(fmt.Sprintf("DATE(%s.created_on) = ?", logt), dayVal)
|
||||
//}
|
||||
|
||||
query = query.Where(maps)
|
||||
if text != "" {
|
||||
query = query.Where("title like ? or content like ?", fmt.Sprintf("%%%s%%", text), fmt.Sprintf("%%%s%%", text))
|
||||
}
|
||||
query = query.Order("created_on DESC")
|
||||
if pageSize > 0 || pageNum > 0 {
|
||||
query = query.Offset(pageNum).Limit(pageSize)
|
||||
}
|
||||
query.Scan(&datas)
|
||||
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
// GetHostMessagesTotal 获取托管消息总数
|
||||
func GetHostMessagesTotal(text string, maps map[string]interface{}) (int64, error) {
|
||||
var total int64
|
||||
hostMessageT := GetSchema(HostedMessage{})
|
||||
|
||||
query := db.Table(hostMessageT)
|
||||
|
||||
//dayVal, ok := maps["day_created_on"]
|
||||
//if ok {
|
||||
// delete(maps, "day_created_on")
|
||||
// query = query.Where(fmt.Sprintf("DATE(%s.created_on) = ?", logt), dayVal)
|
||||
//}
|
||||
|
||||
query = query.Where(maps)
|
||||
if text != "" {
|
||||
query = query.Where("title like ? or content like ?", fmt.Sprintf("%%%s%%", text), fmt.Sprintf("%%%s%%", text))
|
||||
}
|
||||
query.Count(&total)
|
||||
return total, nil
|
||||
}
|
||||
@@ -34,6 +34,10 @@ type InsQyWeiXinConfig struct {
|
||||
type InsCustomConfig struct {
|
||||
}
|
||||
|
||||
// InsMessageNestConfig 实例里面的托管消息config
|
||||
type InsMessageNestConfig struct {
|
||||
}
|
||||
|
||||
// ManyAddTaskIns 批量添加实例
|
||||
func ManyAddTaskIns(taskIns []SendTasksIns) error {
|
||||
tx := db.Begin()
|
||||
|
||||
@@ -119,10 +119,11 @@ func DeleteOutDateLogs(keepNum int) (int, error) {
|
||||
}
|
||||
|
||||
type StatisticData struct {
|
||||
TodaySuccNum int `json:"today_succ_num"`
|
||||
TodayFailedNum int `json:"today_failed_num"`
|
||||
TodayTotalNum int `json:"today_total_num"`
|
||||
MessageTotalNum int `json:"message_total_num"`
|
||||
TodaySuccNum int `json:"today_succ_num"`
|
||||
TodayFailedNum int `json:"today_failed_num"`
|
||||
TodayTotalNum int `json:"today_total_num"`
|
||||
MessageTotalNum int `json:"message_total_num"`
|
||||
HostedMessageTotalNum int `json:"hosted_message_total_num"`
|
||||
|
||||
LatestSendData []LatestSendData `json:"latest_send_data" gorm:"many2many:latest_send_data;"`
|
||||
WayCateData []WayCateData `json:"way_cate_data" gorm:"many2many:way_cate_data;"`
|
||||
@@ -148,6 +149,7 @@ func GetStatisticData() (StatisticData, error) {
|
||||
var wayCateData []WayCateData
|
||||
logt := GetSchema(SendTasksLogs{})
|
||||
inst := GetSchema(SendTasksIns{})
|
||||
hostedt := GetSchema(HostedMessage{})
|
||||
wayst := GetSchema(SendWays{})
|
||||
currDay := util.GetNowTimeStr()[:10]
|
||||
|
||||
@@ -166,6 +168,10 @@ func GetStatisticData() (StatisticData, error) {
|
||||
totalQuery := db.Table(logt).Select(`COUNT(*) AS message_total_num`)
|
||||
totalQuery.Take(&statistic)
|
||||
|
||||
// 托管消息统计数据
|
||||
hostedMessageTotalQuery := db.Table(hostedt).Select(`COUNT(*) AS hosted_message_total_num`)
|
||||
hostedMessageTotalQuery.Take(&statistic)
|
||||
|
||||
// 最近30天数据
|
||||
days := 30
|
||||
now := util.GetNowTime()
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"message-nest/pkg/app"
|
||||
"message-nest/pkg/util"
|
||||
"message-nest/service/hosted_message_service"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// GetHostMessageList 获取托管消息列表
|
||||
func GetHostMessageList(c *gin.Context) {
|
||||
appG := app.Gin{C: c}
|
||||
text := c.Query("text")
|
||||
|
||||
offset, limit := util.GetPageSize(c)
|
||||
messageService := hosted_message_service.HostMessageService{
|
||||
Text: text,
|
||||
PageNum: offset,
|
||||
PageSize: limit,
|
||||
}
|
||||
ways, err := messageService.GetAll()
|
||||
if err != nil {
|
||||
appG.CResponse(http.StatusInternalServerError, "获取托管消息失败!", nil)
|
||||
return
|
||||
}
|
||||
|
||||
count, err := messageService.Count()
|
||||
if err != nil {
|
||||
appG.CResponse(http.StatusInternalServerError, "获取托管消息总数失败!", nil)
|
||||
return
|
||||
}
|
||||
|
||||
appG.CResponse(http.StatusOK, "获取托管消息成功", map[string]interface{}{
|
||||
"lists": ways,
|
||||
"total": count,
|
||||
})
|
||||
}
|
||||
@@ -97,7 +97,7 @@ func GetMsgSendWayList(c *gin.Context) {
|
||||
type AddMsgSendWayReq struct {
|
||||
Name string `json:"name" validate:"required,max=100,min=1" label:"渠道名"`
|
||||
Type string `json:"type" validate:"required,max=100,min=1" label:"渠道类型"`
|
||||
Auth string `json:"auth" validate:"required,max=2048,min=6" label:"渠道认证方式"`
|
||||
Auth string `json:"auth" label:"渠道认证方式"`
|
||||
}
|
||||
|
||||
// AddMsgSendWay 添加发送渠道
|
||||
|
||||
@@ -91,6 +91,9 @@ func InitRouter(f embed.FS) *gin.Engine {
|
||||
apiV1.POST("/cronmessages/delete", v1.DeleteCronMsgTask)
|
||||
apiV1.POST("/cronmessages/edit", v1.EditCronMsgTask)
|
||||
|
||||
// hostedMessage
|
||||
apiV1.GET("/hostedmessages/list", v1.GetHostMessageList)
|
||||
|
||||
}
|
||||
|
||||
return app
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package hosted_message_service
|
||||
|
||||
import (
|
||||
"message-nest/models"
|
||||
)
|
||||
|
||||
type HostMessageService struct {
|
||||
ID int
|
||||
Text string
|
||||
Title string
|
||||
Type string
|
||||
Content string
|
||||
|
||||
PageNum int
|
||||
PageSize int
|
||||
}
|
||||
|
||||
func (st *HostMessageService) Add() error {
|
||||
model := models.HostedMessage{
|
||||
Title: st.Title,
|
||||
Content: st.Content,
|
||||
Type: st.Type,
|
||||
}
|
||||
return model.Add()
|
||||
}
|
||||
|
||||
func (st *HostMessageService) Count() (int64, error) {
|
||||
return models.GetHostMessagesTotal(st.Text, st.getMaps())
|
||||
}
|
||||
|
||||
func (st *HostMessageService) GetAll() ([]models.HostMessageResult, error) {
|
||||
tasks, err := models.GetHostMessages(st.PageNum, st.PageSize, st.Text, st.getMaps())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tasks, nil
|
||||
}
|
||||
|
||||
func (st *HostMessageService) getMaps() map[string]interface{} {
|
||||
maps := make(map[string]interface{})
|
||||
//if len(st.Query) > 0 {
|
||||
// decodedString, err := url.QueryUnescape(st.Query)
|
||||
// if err != nil {
|
||||
// logrus.Errorf("queryUrl编码解码失败: %s", err)
|
||||
// return maps
|
||||
// }
|
||||
// err = json.Unmarshal([]byte(decodedString), &maps)
|
||||
// if err != nil {
|
||||
// logrus.Errorf("queryJson反序列化失败: %s", err)
|
||||
// return maps
|
||||
// }
|
||||
//}
|
||||
return maps
|
||||
}
|
||||
@@ -39,6 +39,10 @@ func (sw *SendTaskInsService) ValidateDiffIns(ins models.SendTasksIns) (string,
|
||||
var Config models.InsQyWeiXinConfig
|
||||
return "", Config
|
||||
}
|
||||
if ins.WayType == "MessageNest" {
|
||||
var Config models.InsQyWeiXinConfig
|
||||
return "", Config
|
||||
}
|
||||
if ins.WayType == "Custom" {
|
||||
var Config models.InsCustomConfig
|
||||
err := json.Unmarshal([]byte(ins.Config), &Config)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package send_message_service
|
||||
|
||||
import (
|
||||
"message-nest/models"
|
||||
"message-nest/service/hosted_message_service"
|
||||
"message-nest/service/send_way_service"
|
||||
)
|
||||
|
||||
type HostMessageService struct {
|
||||
}
|
||||
|
||||
// SendHostMessage 执行托管消息记录
|
||||
func (s *HostMessageService) SendHostMessage(
|
||||
auth send_way_service.MessageNest,
|
||||
ins models.SendTasksIns,
|
||||
typeC string,
|
||||
title string,
|
||||
content string) (string, string) {
|
||||
|
||||
errMsg := ""
|
||||
var res string
|
||||
var err error
|
||||
messageService := hosted_message_service.HostMessageService{
|
||||
Title: title,
|
||||
Content: content,
|
||||
Type: typeC,
|
||||
}
|
||||
err = messageService.Add()
|
||||
if err != nil {
|
||||
errMsg = err.Error()
|
||||
res = "托管消息创建失败!"
|
||||
} else {
|
||||
res = "托管消息创建成功!"
|
||||
}
|
||||
return string(res), errMsg
|
||||
}
|
||||
@@ -194,6 +194,15 @@ func (sm *SendMessageService) Send(task models.TaskIns) (string, error) {
|
||||
sm.LogsAndStatusMark(sm.TransError(errMsg), errStrIsSuccess(errMsg))
|
||||
continue
|
||||
}
|
||||
// 托管消息的实例发送
|
||||
mnt, ok := msgObj.(send_way_service.MessageNest)
|
||||
if ok {
|
||||
cs := HostMessageService{}
|
||||
res, errMsg := cs.SendHostMessage(mnt, ins.SendTasksIns, typeC, sm.Title, content)
|
||||
sm.LogsAndStatusMark(fmt.Sprintf("返回内容:%s", res), sm.Status)
|
||||
sm.LogsAndStatusMark(sm.TransError(errMsg), errStrIsSuccess(errMsg))
|
||||
continue
|
||||
}
|
||||
sm.LogsAndStatusMark(fmt.Sprintf("发送失败:未知渠道的发信实例: %s\n", ins.ID), SendFail)
|
||||
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@ type WeChatOFAccount struct {
|
||||
TempID string `json:"tempid" validate:"max=2000" label:"模板消息id"`
|
||||
}
|
||||
|
||||
// MessageNest 自托管消息
|
||||
type MessageNest struct {
|
||||
}
|
||||
|
||||
func (sw *SendWay) GetByID() (interface{}, error) {
|
||||
return models.GetWayByID(sw.ID)
|
||||
}
|
||||
@@ -170,6 +174,14 @@ func (sw *SendWay) ValidateDiffWay() (string, interface{}) {
|
||||
}
|
||||
_, Msg := app.CommonPlaygroundValid(wca)
|
||||
return Msg, wca
|
||||
} else if sw.Type == "MessageNest" {
|
||||
var wca MessageNest
|
||||
err := json.Unmarshal([]byte(sw.Auth), &wca)
|
||||
if err != nil {
|
||||
return "自托管消息反序列化失败!", empty
|
||||
}
|
||||
_, Msg := app.CommonPlaygroundValid(wca)
|
||||
return Msg, wca
|
||||
}
|
||||
return fmt.Sprintf("未知的发信渠道校验: %s", sw.Type), empty
|
||||
}
|
||||
@@ -209,11 +221,11 @@ func (sw *SendWay) TestSendWay(msgObj interface{}) (string, string) {
|
||||
}
|
||||
_, ok = msgObj.(WeChatOFAccount)
|
||||
if ok {
|
||||
//var cli = message.WeChatOFAccount{
|
||||
// AppID: wca.AppID,
|
||||
// AppSecret: wca.APPSecret,
|
||||
//}
|
||||
return "微信公众号模板消息不用测试运行,请直接添加", ""
|
||||
}
|
||||
_, ok = msgObj.(MessageNest)
|
||||
if ok {
|
||||
return "自托管消息不用测试运行,请直接添加", ""
|
||||
}
|
||||
return fmt.Sprintf("未知的发信渠道校验: %s", sw.Type), ""
|
||||
}
|
||||
|
||||
+16
-1
@@ -69,7 +69,7 @@ const CONSTANT = {
|
||||
},
|
||||
{
|
||||
type: 'Custom',
|
||||
label: '自定义',
|
||||
label: '自定义推送',
|
||||
inputs: [
|
||||
{ subLabel: 'webhook地址', value: '', col: 'webhook', desc: "自定义webhook地址" },
|
||||
{ subLabel: '请求体', value: '', col: 'body', desc: "请求体, text内容请使用 TEXT 进行占位\n例如:{\"message\": \"TEXT\", \"foo\": \"bar\"}", isTextArea: true },
|
||||
@@ -103,6 +103,21 @@ const CONSTANT = {
|
||||
{ value: '', col: 'to_account', desc: "要发送的OpenId(登录微信公众号后台查看)" },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'MessageNest',
|
||||
label: '自托管消息',
|
||||
inputs: [
|
||||
{ subLabel: '渠道名', value: '', col: 'name', desc: "想要设置的渠道名字" },
|
||||
],
|
||||
tips: {
|
||||
text: "自托管消息说明", desc: "站点本身会作为消息接收站点,接收、展示推送过来的消息。"
|
||||
},
|
||||
taskInsRadios: [
|
||||
{ subLabel: 'text', content: 'text' },
|
||||
],
|
||||
taskInsInputs: [
|
||||
],
|
||||
},
|
||||
],
|
||||
API_VIEW_DATA: [
|
||||
{ label: "curl", class: "language-shell line-numbers", code: "", func: ApiStrGenerate.getCurlString },
|
||||
|
||||
@@ -42,6 +42,11 @@ const router = createRouter({
|
||||
name: 'settings',
|
||||
component: () => import('../views/tabsTools/settings/settings.vue')
|
||||
},
|
||||
{
|
||||
path: '/hostedMessage',
|
||||
name: 'hostedmessage',
|
||||
component: () => import('../views/tabsTools/hostedMessage/hostedMessage.vue')
|
||||
},
|
||||
{
|
||||
path: '/:catchAll(.*)',
|
||||
name: '404',
|
||||
|
||||
@@ -35,10 +35,11 @@ export default {
|
||||
const menuData = reactive([
|
||||
{ id: '0', title: '数据统计', path: '/statistic' },
|
||||
{ id: '1', title: '发信日志', path: '/sendlogs' },
|
||||
{ id: '2', title: '定时发信', path: '/cronmessages' },
|
||||
{ id: '3', title: '发信任务', path: '/sendtasks' },
|
||||
{ id: '4', title: '发信渠道', path: '/sendways' },
|
||||
{ id: '5', title: '设置', path: '/settings' },
|
||||
{ id: '2', title: '托管消息', path: '/hostedmessage' },
|
||||
{ id: '3', title: '定时发信', path: '/cronmessages' },
|
||||
{ id: '4', title: '发信任务', path: '/sendtasks' },
|
||||
{ id: '5', title: '发信渠道', path: '/sendways' },
|
||||
{ id: '6', title: '设置', path: '/settings' },
|
||||
]);
|
||||
|
||||
const checkIsLogin = () => {
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
<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-text class="refresh-time" v-if="refreshText" size="small">{{ refreshText }}</el-text>
|
||||
<el-input-number class="refresh-box" v-model="refreshSec" size="small" :step="2" :min="5"
|
||||
controls-position="right" />
|
||||
<el-switch v-model="refreshSwitch" class="ml-2" width="80" inline-prompt active-text="自动刷新" inactive-text="自动刷新"
|
||||
@click="clickFreshSwitch" />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div ref="refContainer">
|
||||
<el-table :data="tableData" stripe empty-text="托管消息为空" :row-style="rowStyle()">
|
||||
<el-table-column label="ID" prop="id" width="85px" />
|
||||
<el-table-column label="消息标题" prop="title" show-overflow-tooltip width="150px" />
|
||||
<el-table-column label="托管消息" prop="content">
|
||||
<template #default="scope">
|
||||
<el-tooltip enterable placement="top">
|
||||
<template #content>
|
||||
<div v-html="formatLogDisplayHtml(scope)"></div>
|
||||
</template>
|
||||
<span class="log-overflow">{{ scope.row.content }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发送时间" prop="created_on" width="160px" />
|
||||
<el-table-column label="详情" prop="status" width="120px" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button link size="small" style="margin-right: 10px;" type="primary"
|
||||
@click="drawer = true; logText = formatLogDisplayHtml(scope)">查看消息</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<el-drawer v-model="drawer" :with-header="false">
|
||||
<el-text v-html="logText" size="small"></el-text>
|
||||
</el-drawer>
|
||||
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs, onMounted, watch, ref } from 'vue'
|
||||
import { request } from '../../../api/api'
|
||||
import { copyToClipboard } from '../../../util/clipboard.js';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { CONSTANT } from '@/constant'
|
||||
import { usePageState } from '@/store/page_sate.js';
|
||||
import { CommonUtils } from "@/util/commonUtils.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
setup() {
|
||||
const pageState = usePageState();
|
||||
const router = useRoute();
|
||||
const state = reactive({
|
||||
search: '',
|
||||
refreshText: '',
|
||||
refreshSwitch: false,
|
||||
refreshSec: 20,
|
||||
refreshIntervalFuncList: [],
|
||||
optionValue: '',
|
||||
logText: '',
|
||||
drawer: false,
|
||||
tableData: [],
|
||||
total: CONSTANT.TOTAL,
|
||||
pageSize: pageState.siteConfigData.pagesize,
|
||||
currPage: CONSTANT.PAGE,
|
||||
});
|
||||
|
||||
const TransHtml = (raw) => {
|
||||
if (raw) {
|
||||
return raw.replace(/\n/g, '<br />')
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
const formatLogDisplayHtml = (scope) => {
|
||||
let content = TransHtml(scope.row.content);
|
||||
return content;
|
||||
}
|
||||
|
||||
const handPageChange = async (pageNum) => {
|
||||
state.currPage = pageNum;
|
||||
await queryListData(pageNum, state.pageSize);
|
||||
|
||||
}
|
||||
|
||||
const rowStyle = () => {
|
||||
return {
|
||||
'font-size': '13px',
|
||||
}
|
||||
}
|
||||
|
||||
const clickFreshSwitch = () => {
|
||||
if (state.refreshSwitch) {
|
||||
let flag = setInterval(async function () {
|
||||
await filterFunc();
|
||||
state.refreshText = `自动刷新于:${CommonUtils.getCurrentTimeStr()}`;
|
||||
}, state.refreshSec * 1000);
|
||||
state.refreshIntervalFuncList.push(flag);
|
||||
} else {
|
||||
state.refreshIntervalFuncList.forEach(intervalId => {
|
||||
clearInterval(intervalId);
|
||||
});
|
||||
state.refreshIntervalFuncList = [];
|
||||
state.refreshText = '';
|
||||
}
|
||||
}
|
||||
|
||||
const filterFunc = async () => {
|
||||
await queryListData(state.currPage, state.pageSize, state.search, state.optionValue);
|
||||
|
||||
}
|
||||
|
||||
const queryListData = async (page, size, name = '', query = '') => {
|
||||
let params = { page: page, size: size, text: name, query: query };
|
||||
const rsp = await request.get('/hostedmessages/list', { params: params });
|
||||
state.tableData = await rsp.data.data.lists;
|
||||
state.total = await rsp.data.data.total;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
state.search = router.query.name;
|
||||
await queryListData(1, state.pageSize, router.query.name, router.query.taskid, router.query.query);
|
||||
});
|
||||
|
||||
return {
|
||||
...toRefs(state), TransHtml, clickFreshSwitch,
|
||||
rowStyle, handPageChange, filterFunc, copyToClipboard, formatLogDisplayHtml
|
||||
};
|
||||
}
|
||||
}
|
||||
</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; */
|
||||
}
|
||||
|
||||
.search-box {
|
||||
float: right;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.refresh-box {
|
||||
width: 80px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.refresh-time {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.pagination-block {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
}
|
||||
|
||||
.total-tip {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.search-input-sendways {
|
||||
width: 200px;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
|
||||
.log-overflow {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="main-center-body">
|
||||
<div class="container">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="6">
|
||||
<el-row :gutter="18">
|
||||
<el-col :span="4">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="data.message_total_num">
|
||||
<template #title>
|
||||
@@ -13,7 +13,18 @@
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-col :span="5">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="data.hosted_message_total_num">
|
||||
<template #title>
|
||||
<div style="display: inline-flex; align-items: center">
|
||||
托管消息数
|
||||
</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="data.today_total_num">
|
||||
<template #title>
|
||||
@@ -24,7 +35,7 @@
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-col :span="5">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="data.today_succ_num">
|
||||
<template #title>
|
||||
@@ -35,7 +46,7 @@
|
||||
</el-statistic>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-col :span="5">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="data.today_failed_num" :value-style="formatFailedNumStyle()">
|
||||
<template #title>
|
||||
|
||||
Reference in New Issue
Block a user