运行日志显示未读的日志数量

This commit is contained in:
GoEdgeLab
2021-10-15 12:54:23 +08:00
parent 56e6ba083b
commit 8043362e53
14 changed files with 161 additions and 23 deletions

View File

@@ -12,7 +12,8 @@ func NewClustersHelper() *ClustersHelper {
return &ClustersHelper{} return &ClustersHelper{}
} }
func (this *ClustersHelper) BeforeAction(action *actions.ActionObject) { func (this *ClustersHelper) BeforeAction(actionPtr actions.ActionWrapper) {
var action = actionPtr.Object()
if action.Request.Method != http.MethodGet { if action.Request.Method != http.MethodGet {
return return
} }

View File

@@ -12,6 +12,7 @@ func init() {
server. server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)). Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
Helper(clusterutils.NewClustersHelper()). Helper(clusterutils.NewClustersHelper()).
Data("teaMenu", "clusters").
Data("teaSubMenu", "grant"). Data("teaSubMenu", "grant").
Prefix("/clusters/grants"). Prefix("/clusters/grants").

View File

@@ -12,6 +12,7 @@ func init() {
server. server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)). Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNode)).
Helper(clusterutils.NewClustersHelper()). Helper(clusterutils.NewClustersHelper()).
Data("teaMenu", "clusters").
Prefix("/clusters"). Prefix("/clusters").
Get("", new(IndexAction)). Get("", new(IndexAction)).
GetPost("/create", new(CreateAction)). GetPost("/create", new(CreateAction)).

View File

@@ -2,6 +2,7 @@ package logs
import ( import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time" timeutil "github.com/iwind/TeaGo/utils/time"
@@ -12,6 +13,11 @@ type IndexAction struct {
} }
func (this *IndexAction) Init() { func (this *IndexAction) Init() {
if this.ParamString("type") == "unread" {
this.FirstMenu("unread")
} else {
this.FirstMenu("index")
}
} }
func (this *IndexAction) RunGet(params struct { func (this *IndexAction) RunGet(params struct {
@@ -19,19 +25,34 @@ func (this *IndexAction) RunGet(params struct {
DayTo string DayTo string
Keyword string Keyword string
Level string Level string
Type string
}) { }) {
this.Data["dayFrom"] = params.DayFrom this.Data["dayFrom"] = params.DayFrom
this.Data["dayTo"] = params.DayTo this.Data["dayTo"] = params.DayTo
this.Data["keyword"] = params.Keyword this.Data["keyword"] = params.Keyword
this.Data["level"] = params.Level this.Data["level"] = params.Level
this.Data["type"] = params.Type
// 未读数量
countUnreadResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
Role: nodeconfigs.NodeRoleNode,
IsUnread: true,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["countUnreadLogs"] = countUnreadResp.Count
// 日志数量
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{ countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
NodeId: 0, NodeId: 0,
Role: "node", Role: nodeconfigs.NodeRoleNode,
DayFrom: params.DayFrom, DayFrom: params.DayFrom,
DayTo: params.DayTo, DayTo: params.DayTo,
Keyword: params.Keyword, Keyword: params.Keyword,
Level: params.Level, Level: params.Level,
IsUnread: params.Type == "unread",
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -42,14 +63,15 @@ func (this *IndexAction) RunGet(params struct {
this.Data["page"] = page.AsHTML() this.Data["page"] = page.AsHTML()
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{ logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
NodeId: 0, NodeId: 0,
Role: "node", Role: nodeconfigs.NodeRoleNode,
DayFrom: params.DayFrom, DayFrom: params.DayFrom,
DayTo: params.DayTo, DayTo: params.DayTo,
Keyword: params.Keyword, Keyword: params.Keyword,
Level: params.Level, Level: params.Level,
Offset: page.Offset, IsUnread: params.Type == "unread",
Size: page.Size, Offset: page.Offset,
Size: page.Size,
}) })
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)
@@ -69,12 +91,14 @@ func (this *IndexAction) RunGet(params struct {
} }
logs = append(logs, maps.Map{ logs = append(logs, maps.Map{
"id": log.Id,
"tag": log.Tag, "tag": log.Tag,
"description": log.Description, "description": log.Description,
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt), "createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
"level": log.Level, "level": log.Level,
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"), "isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
"count": log.Count, "count": log.Count,
"isRead": log.IsRead,
"node": maps.Map{ "node": maps.Map{
"id": node.Id, "id": node.Id,
"cluster": maps.Map{ "cluster": maps.Map{

View File

@@ -14,6 +14,7 @@ func init() {
Data("teaSubMenu", "log"). Data("teaSubMenu", "log").
Prefix("/clusters/logs"). Prefix("/clusters/logs").
Get("", new(IndexAction)). Get("", new(IndexAction)).
Post("/readLogs", new(ReadLogsAction)).
EndAll() EndAll()
}) })
} }

View File

@@ -0,0 +1,26 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package logs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type ReadLogsAction struct {
actionutils.ParentAction
}
func (this *ReadLogsAction) RunPost(params struct {
LogIds []int64
}) {
_, err := this.RPC().NodeLogRPC().UpdateNodeLogsRead(this.AdminContext(), &pb.UpdateNodeLogsReadRequest{
NodeLogIds: params.LogIds,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -4,7 +4,11 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders" "github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const" teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/setup" "github.com/TeaOSLab/EdgeAdmin/internal/setup"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/maps"
"net" "net"
"net/http" "net/http"
@@ -130,7 +134,7 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
if !action.Data.Has("teaMenu") { if !action.Data.Has("teaMenu") {
action.Data["teaMenu"] = "" action.Data["teaMenu"] = ""
} }
action.Data["teaModules"] = this.modules(adminId) action.Data["teaModules"] = this.modules(actionPtr, adminId)
action.Data["teaSubMenus"] = []map[string]interface{}{} action.Data["teaSubMenus"] = []map[string]interface{}{}
action.Data["teaTabbar"] = []map[string]interface{}{} action.Data["teaTabbar"] = []map[string]interface{}{}
if len(config.Version) == 0 { if len(config.Version) == 0 {
@@ -165,7 +169,34 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
} }
// 菜单配置 // 菜单配置
func (this *userMustAuth) modules(adminId int64) []maps.Map { func (this *userMustAuth) modules(actionPtr actions.ActionWrapper, adminId int64) []maps.Map {
var countUnreadNodeLogs int64 = 0
// 父级动作
parentAction, ok := actionPtr.(actionutils.ActionInterface)
if ok {
var action = actionPtr.Object()
// 未读日志数
if action.Data.GetString("teaMenu") == "clusters" {
countNodeLogsResp, err := parentAction.RPC().NodeLogRPC().CountNodeLogs(parentAction.AdminContext(), &pb.CountNodeLogsRequest{
Role: nodeconfigs.NodeRoleNode,
IsUnread: true,
})
if err != nil {
logs.Error(err)
} else {
var countNodeLogs = countNodeLogsResp.Count
if countNodeLogs > 0 {
countUnreadNodeLogs = countNodeLogs
if countUnreadNodeLogs >= 1000 {
countUnreadNodeLogs = 999
}
}
}
}
}
allMaps := []maps.Map{ allMaps := []maps.Map{
{ {
"code": "dashboard", "code": "dashboard",
@@ -236,9 +267,10 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
"icon": "cloud", "icon": "cloud",
"subItems": []maps.Map{ "subItems": []maps.Map{
{ {
"name": "运行日志", "name": "运行日志",
"url": "/clusters/logs", "url": "/clusters/logs",
"code": "log", "code": "log",
"badge": countUnreadNodeLogs,
}, },
{ {
"name": "IP地址", "name": "IP地址",

View File

@@ -239,12 +239,20 @@ p.margin {
} }
.main-menu .ui.menu .sub-items .item { .main-menu .ui.menu .sub-items .item {
padding-left: 2.8em !important; padding-left: 2.8em !important;
padding-right: 0.4em !important;
} }
.main-menu .ui.menu .sub-items .item .icon { .main-menu .ui.menu .sub-items .item .icon {
position: absolute; position: absolute;
left: 1.1em; left: 1.1em;
top: 0.93em; top: 0.93em;
} }
.main-menu .ui.menu .sub-items .item .label {
margin-left: 0;
margin-right: 0;
padding-left: 0.4em;
padding-right: 0.4em;
min-width: 2em;
}
@media screen and (max-width: 512px) { @media screen and (max-width: 512px) {
.main-menu .ui.menu .sub-items .item { .main-menu .ui.menu .sub-items .item {
padding-left: 1em !important; padding-left: 1em !important;

File diff suppressed because one or more lines are too long

View File

@@ -92,7 +92,9 @@
<div class="subtitle" v-if="module.subtitle != null && module.subtitle.length > 0">{{module.subtitle}}</div> <div class="subtitle" v-if="module.subtitle != null && module.subtitle.length > 0">{{module.subtitle}}</div>
</a> </a>
<div v-if="teaMenu == module.code" class="sub-items"> <div v-if="teaMenu == module.code" class="sub-items">
<a class="item" v-for="subItem in module.subItems" v-if="subItem.isOn !== false" :href="subItem.url"><i class="icon angle right" v-if="subItem.code == teaSubMenu"></i> {{subItem.name}}</a> <a class="item" v-for="subItem in module.subItems" v-if="subItem.isOn !== false" :href="subItem.url"><i class="icon angle right" v-if="subItem.code == teaSubMenu"></i> {{subItem.name}}
<span class="ui label tiny red" v-if="subItem.badge != null && subItem.badge > 0">{{subItem.badge}}</span>
</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -179,12 +179,21 @@ div.margin, p.margin {
.sub-items { .sub-items {
.item { .item {
padding-left: 2.8em !important; padding-left: 2.8em !important;
padding-right: 0.4em !important;
.icon { .icon {
position: absolute; position: absolute;
left: 1.1em; left: 1.1em;
top: 0.93em; top: 0.93em;
} }
.label {
margin-left: 0;
margin-right: 0;
padding-left: 0.4em;
padding-right: 0.4em;
min-width: 2em;
}
} }
@media screen and (max-width: 512px) { @media screen and (max-width: 512px) {

View File

@@ -0,0 +1,4 @@
<first-menu>
<menu-item href="/clusters/logs" code="index">所有</menu-item>
<menu-item href="/clusters/logs?type=unread" code="unread">未读<span :class="{red: countUnreadLogs > 0}">({{countUnreadLogs}})</span></menu-item>
</first-menu>

View File

@@ -1,9 +1,11 @@
{$layout} {$layout}
{$template "/datepicker"} {$template "/datepicker"}
{$template "menu"}
<div class="margin"></div> <div class="margin"></div>
<form method="get" action="/clusters/logs" class="ui form" autocomplete="off"> <form method="get" action="/clusters/logs" class="ui form" autocomplete="off">
<input type="hidden" name="type" :value="type"/>
<div class="ui fields inline"> <div class="ui fields inline">
<div class="ui field"> <div class="ui field">
<input type="text" name="dayFrom" placeholder="开始日期" v-model="dayFrom" value="" style="width:8em" id="day-from-picker"/> <input type="text" name="dayFrom" placeholder="开始日期" v-model="dayFrom" value="" style="width:8em" id="day-from-picker"/>
@@ -27,7 +29,7 @@
<button type="submit" class="ui button">查询</button> <button type="submit" class="ui button">查询</button>
</div> </div>
<div class="ui field" v-if="dayFrom.length > 0 || dayTo.length > 0 || keyword.length > 0 || level.length > 0"> <div class="ui field" v-if="dayFrom.length > 0 || dayTo.length > 0 || keyword.length > 0 || level.length > 0">
<a href="/clusters/logs">[清除条件]</a> <a :href="'/clusters/logs?type=' + type">[清除条件]</a>
</div> </div>
</div> </div>
</form> </form>
@@ -40,6 +42,7 @@
<th>集群</th> <th>集群</th>
<th>节点</th> <th>节点</th>
<th>信息</th> <th>信息</th>
<th class="one op">操作</th>
</tr> </tr>
</thead> </thead>
<tr v-for="log in logs"> <tr v-for="log in logs">
@@ -48,6 +51,9 @@
<td> <td>
<node-log-row :v-log="log" :v-keyword="keyword"></node-log-row> <node-log-row :v-log="log" :v-keyword="keyword"></node-log-row>
</td> </td>
<td>
<a href="" @click.prevent="updateRead(log.id)" v-if="!log.isRead">已读</a>
</td>
</tr> </tr>
</table> </table>

View File

@@ -3,4 +3,27 @@ Tea.context(function () {
teaweb.datepicker("day-from-picker") teaweb.datepicker("day-from-picker")
teaweb.datepicker("day-to-picker") teaweb.datepicker("day-to-picker")
}) })
this.updateRead = function (logId) {
this.$post(".readLogs")
.params({
logIds: [logId]
})
.success(function () {
teaweb.reload()
})
}
this.updatePageRead = function () {
let logIds = this.logs.map(function (v) {
return v.id
})
this.$post(".readLogs")
.params({
logIds: logIds
})
.success(function () {
teaweb.reload()
})
}
}) })