mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-04 05:00:25 +08:00
运行日志显示未读的日志数量
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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").
|
||||||
|
|
||||||
|
|||||||
@@ -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)).
|
||||||
|
|||||||
@@ -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{
|
||||||
|
|||||||
@@ -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()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
26
internal/web/actions/default/clusters/logs/readLogs.go
Normal file
26
internal/web/actions/default/clusters/logs/readLogs.go
Normal 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()
|
||||||
|
}
|
||||||
@@ -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地址",
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
4
web/views/@default/clusters/logs/@menu.html
Normal file
4
web/views/@default/clusters/logs/@menu.html
Normal 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>
|
||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user