mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 05:00:25 +08:00 
			
		
		
		
	优化自建DNS交互
This commit is contained in:
		
							
								
								
									
										96
									
								
								internal/web/actions/default/ns/domains/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								internal/web/actions/default/ns/domains/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
package domains
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.FirstMenu("domain")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
	ClusterId int64
 | 
			
		||||
	UserId    int64
 | 
			
		||||
	Keyword   string
 | 
			
		||||
}) {
 | 
			
		||||
	if !teaconst.IsPlus {
 | 
			
		||||
		this.RedirectURL("/")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["clusterId"] = params.ClusterId
 | 
			
		||||
	this.Data["userId"] = params.UserId
 | 
			
		||||
	this.Data["keyword"] = params.Keyword
 | 
			
		||||
 | 
			
		||||
	// 集群数量
 | 
			
		||||
	countClustersResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["countClusters"] = countClustersResp.Count
 | 
			
		||||
 | 
			
		||||
	// 分页
 | 
			
		||||
	countResp, err := this.RPC().NSDomainRPC().CountAllEnabledNSDomains(this.AdminContext(), &pb.CountAllEnabledNSDomainsRequest{
 | 
			
		||||
		UserId:      params.UserId,
 | 
			
		||||
		NsClusterId: params.ClusterId,
 | 
			
		||||
		Keyword:     params.Keyword,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	page := this.NewPage(countResp.Count)
 | 
			
		||||
 | 
			
		||||
	// 列表
 | 
			
		||||
	domainsResp, err := this.RPC().NSDomainRPC().ListEnabledNSDomains(this.AdminContext(), &pb.ListEnabledNSDomainsRequest{
 | 
			
		||||
		UserId:      params.UserId,
 | 
			
		||||
		NsClusterId: params.ClusterId,
 | 
			
		||||
		Keyword:     params.Keyword,
 | 
			
		||||
		Offset:      page.Offset,
 | 
			
		||||
		Size:        page.Size,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	domainMaps := []maps.Map{}
 | 
			
		||||
	for _, domain := range domainsResp.NsDomains {
 | 
			
		||||
		// 集群信息
 | 
			
		||||
		var clusterMap maps.Map
 | 
			
		||||
		if domain.NsCluster != nil {
 | 
			
		||||
			clusterMap = maps.Map{
 | 
			
		||||
				"id":   domain.NsCluster.Id,
 | 
			
		||||
				"name": domain.NsCluster.Name,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 用户信息
 | 
			
		||||
		var userMap maps.Map
 | 
			
		||||
		if domain.User != nil {
 | 
			
		||||
			userMap = maps.Map{
 | 
			
		||||
				"id":       domain.User.Id,
 | 
			
		||||
				"username": domain.User.Username,
 | 
			
		||||
				"fullname": domain.User.Fullname,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		domainMaps = append(domainMaps, maps.Map{
 | 
			
		||||
			"id":      domain.Id,
 | 
			
		||||
			"name":    domain.Name,
 | 
			
		||||
			"isOn":    domain.IsOn,
 | 
			
		||||
			"cluster": clusterMap,
 | 
			
		||||
			"user":    userMap,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["domains"] = domainMaps
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,13 @@
 | 
			
		||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
			
		||||
 | 
			
		||||
package ns
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	timeutil "github.com/iwind/TeaGo/utils/time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
@@ -12,85 +15,113 @@ type IndexAction struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.FirstMenu("index")
 | 
			
		||||
	this.Nav("", "", "dns")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
	ClusterId int64
 | 
			
		||||
	UserId    int64
 | 
			
		||||
	Keyword   string
 | 
			
		||||
}) {
 | 
			
		||||
	if !teaconst.IsPlus {
 | 
			
		||||
		this.RedirectURL("/")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["clusterId"] = params.ClusterId
 | 
			
		||||
	this.Data["userId"] = params.UserId
 | 
			
		||||
	this.Data["keyword"] = params.Keyword
 | 
			
		||||
 | 
			
		||||
	// 集群数量
 | 
			
		||||
	countClustersResp, err := this.RPC().NSClusterRPC().CountAllEnabledNSClusters(this.AdminContext(), &pb.CountAllEnabledNSClustersRequest{})
 | 
			
		||||
func (this *IndexAction) RunGet(params struct{}) {
 | 
			
		||||
	resp, err := this.RPC().NSRPC().ComposeNSBoard(this.AdminContext(), &pb.ComposeNSBoardRequest{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["countClusters"] = countClustersResp.Count
 | 
			
		||||
 | 
			
		||||
	// 分页
 | 
			
		||||
	countResp, err := this.RPC().NSDomainRPC().CountAllEnabledNSDomains(this.AdminContext(), &pb.CountAllEnabledNSDomainsRequest{
 | 
			
		||||
		UserId:      params.UserId,
 | 
			
		||||
		NsClusterId: params.ClusterId,
 | 
			
		||||
		Keyword:     params.Keyword,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	this.Data["board"] = maps.Map{
 | 
			
		||||
		"countDomains":      resp.CountNSDomains,
 | 
			
		||||
		"countRecords":      resp.CountNSRecords,
 | 
			
		||||
		"countClusters":     resp.CountNSClusters,
 | 
			
		||||
		"countNodes":        resp.CountNSNodes,
 | 
			
		||||
		"countOfflineNodes": resp.CountOfflineNSNodes,
 | 
			
		||||
	}
 | 
			
		||||
	page := this.NewPage(countResp.Count)
 | 
			
		||||
 | 
			
		||||
	// 列表
 | 
			
		||||
	domainsResp, err := this.RPC().NSDomainRPC().ListEnabledNSDomains(this.AdminContext(), &pb.ListEnabledNSDomainsRequest{
 | 
			
		||||
		UserId:      params.UserId,
 | 
			
		||||
		NsClusterId: params.ClusterId,
 | 
			
		||||
		Keyword:     params.Keyword,
 | 
			
		||||
		Offset:      page.Offset,
 | 
			
		||||
		Size:        page.Size,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	domainMaps := []maps.Map{}
 | 
			
		||||
	for _, domain := range domainsResp.NsDomains {
 | 
			
		||||
		// 集群信息
 | 
			
		||||
		var clusterMap maps.Map
 | 
			
		||||
		if domain.NsCluster != nil {
 | 
			
		||||
			clusterMap = maps.Map{
 | 
			
		||||
				"id":   domain.NsCluster.Id,
 | 
			
		||||
				"name": domain.NsCluster.Name,
 | 
			
		||||
			}
 | 
			
		||||
	// 流量排行
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.HourlyTrafficStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"day":           stat.Hour[4:6] + "月" + stat.Hour[6:8] + "日",
 | 
			
		||||
				"hour":          stat.Hour[8:],
 | 
			
		||||
				"countRequests": stat.CountRequests,
 | 
			
		||||
				"bytes":         stat.Bytes,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 用户信息
 | 
			
		||||
		var userMap maps.Map
 | 
			
		||||
		if domain.User != nil {
 | 
			
		||||
			userMap = maps.Map{
 | 
			
		||||
				"id":       domain.User.Id,
 | 
			
		||||
				"username": domain.User.Username,
 | 
			
		||||
				"fullname": domain.User.Fullname,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		domainMaps = append(domainMaps, maps.Map{
 | 
			
		||||
			"id":      domain.Id,
 | 
			
		||||
			"name":    domain.Name,
 | 
			
		||||
			"isOn":    domain.IsOn,
 | 
			
		||||
			"cluster": clusterMap,
 | 
			
		||||
			"user":    userMap,
 | 
			
		||||
		})
 | 
			
		||||
		this.Data["hourlyStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.DailyTrafficStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"day":           stat.Day[4:6] + "月" + stat.Day[6:] + "日",
 | 
			
		||||
				"countRequests": stat.CountRequests,
 | 
			
		||||
				"bytes":         stat.Bytes,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["dailyStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 域名排行
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.TopNSDomainStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"domainId":      stat.NsDomainId,
 | 
			
		||||
				"domainName":    stat.NsDomainName,
 | 
			
		||||
				"countRequests": stat.CountRequests,
 | 
			
		||||
				"bytes":         stat.Bytes,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["topDomainStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 节点排行
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.TopNSNodeStats {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"clusterId":     stat.NsClusterId,
 | 
			
		||||
				"nodeId":        stat.NsNodeId,
 | 
			
		||||
				"nodeName":      stat.NsNodeName,
 | 
			
		||||
				"countRequests": stat.CountRequests,
 | 
			
		||||
				"bytes":         stat.Bytes,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["topNodeStats"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// CPU
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.CpuNodeValues {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"time":  timeutil.FormatTime("H:i", stat.CreatedAt),
 | 
			
		||||
				"value": types.Float32(string(stat.ValueJSON)),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["cpuValues"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Memory
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.MemoryNodeValues {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"time":  timeutil.FormatTime("H:i", stat.CreatedAt),
 | 
			
		||||
				"value": types.Float32(string(stat.ValueJSON)),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["memoryValues"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Load
 | 
			
		||||
	{
 | 
			
		||||
		var statMaps = []maps.Map{}
 | 
			
		||||
		for _, stat := range resp.LoadNodeValues {
 | 
			
		||||
			statMaps = append(statMaps, maps.Map{
 | 
			
		||||
				"time":  timeutil.FormatTime("H:i", stat.CreatedAt),
 | 
			
		||||
				"value": types.Float32(string(stat.ValueJSON)),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		this.Data["loadValues"] = statMaps
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["domains"] = domainMaps
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,8 @@ func init() {
 | 
			
		||||
 | 
			
		||||
			// 域名相关
 | 
			
		||||
			Prefix("/ns/domains").
 | 
			
		||||
			Data("teaSubMenu", "domain").
 | 
			
		||||
			Get("", new(domains.IndexAction)).
 | 
			
		||||
			GetPost("/create", new(domains.CreateAction)).
 | 
			
		||||
			Post("/delete", new(domains.DeleteAction)).
 | 
			
		||||
			Get("/domain", new(domains.DomainAction)).
 | 
			
		||||
@@ -28,6 +30,7 @@ func init() {
 | 
			
		||||
 | 
			
		||||
			// 域名密钥
 | 
			
		||||
			Prefix("/ns/domains/keys").
 | 
			
		||||
			Data("teaSubMenu", "domain").
 | 
			
		||||
			Get("", new(keys.IndexAction)).
 | 
			
		||||
			GetPost("/createPopup", new(keys.CreatePopupAction)).
 | 
			
		||||
			GetPost("/updatePopup", new(keys.UpdatePopupAction)).
 | 
			
		||||
 
 | 
			
		||||
@@ -261,13 +261,17 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code":     "ns",
 | 
			
		||||
			"module":   configloaders.AdminModuleCodeNS,
 | 
			
		||||
			"name":     "自建DNS",
 | 
			
		||||
			"subtitle": "域名列表",
 | 
			
		||||
			"icon":     "cubes",
 | 
			
		||||
			"isOn":     teaconst.IsPlus,
 | 
			
		||||
			"code":   "ns",
 | 
			
		||||
			"module": configloaders.AdminModuleCodeNS,
 | 
			
		||||
			"name":   "自建DNS",
 | 
			
		||||
			"icon":   "cubes",
 | 
			
		||||
			"isOn":   teaconst.IsPlus,
 | 
			
		||||
			"subItems": []maps.Map{
 | 
			
		||||
				{
 | 
			
		||||
					"name": "域名管理",
 | 
			
		||||
					"url":  "/ns/domains",
 | 
			
		||||
					"code": "domain",
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					"name": "集群管理",
 | 
			
		||||
					"url":  "/ns/clusters",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								web/public/js/world.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								web/public/js/world.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -4,11 +4,11 @@
 | 
			
		||||
 | 
			
		||||
<div class="ui four columns grid">
 | 
			
		||||
    <div class="ui column">
 | 
			
		||||
        <h4>域名<link-icon href="/ns"></link-icon></h4>
 | 
			
		||||
        <h4>域名<link-icon href="/ns/domains"></link-icon></h4>
 | 
			
		||||
        <div class="value"><span>{{board.countDomains}}</span>个</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="ui column">
 | 
			
		||||
        <h4>记录<link-icon href="/ns"></link-icon></h4>
 | 
			
		||||
        <h4>记录<link-icon href="/ns/domains"></link-icon></h4>
 | 
			
		||||
        <div class="value"><span>{{board.countRecords}}</span>个</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="ui column">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<first-menu>
 | 
			
		||||
    <menu-item href="/ns">所有域名</menu-item>
 | 
			
		||||
    <menu-item href="/ns/domains">所有域名</menu-item>
 | 
			
		||||
    <span class="item disabled">|</span>
 | 
			
		||||
    <menu-item :href="'/ns/domains/domain?domainId=' + domain.id" code="index">详情<span class="grey small">({{domain.name}})</span></menu-item>
 | 
			
		||||
    <menu-item :href="'/ns/domains/records?domainId=' + domain.id" code="record">记录({{domain.countRecords}})</menu-item>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<first-menu>
 | 
			
		||||
    <menu-item href="/ns" code="index">域名列表</menu-item>
 | 
			
		||||
    <menu-item href="/ns/domains" code="index">域名列表</menu-item>
 | 
			
		||||
    <menu-item href="/ns/domains/create" code="create">添加域名</menu-item>
 | 
			
		||||
</first-menu>
 | 
			
		||||
<div class="margin"></div>
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "../menu"}
 | 
			
		||||
 | 
			
		||||
{$template "menu"}
 | 
			
		||||
 | 
			
		||||
<div v-if="countClusters == 0">
 | 
			
		||||
    <not-found-box>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifySuccess("保存成功", "/ns")
 | 
			
		||||
	this.success = NotifySuccess("保存成功", "/ns/domains")
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										61
									
								
								web/views/@default/ns/domains/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								web/views/@default/ns/domains/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "menu"}
 | 
			
		||||
 | 
			
		||||
<div v-if="countClusters == 0">
 | 
			
		||||
    <not-found-box>
 | 
			
		||||
        暂时还没有集群,请先 <a href="/ns/clusters/create">创建集群</a>。
 | 
			
		||||
    </not-found-box>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div v-if="countClusters > 0">
 | 
			
		||||
    <form class="ui form" method="get" action="/ns/domains">
 | 
			
		||||
        <div class="ui fields inline">
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <ns-cluster-selector :v-cluster-id="clusterId"></ns-cluster-selector>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <ns-user-selector :v-user-id="userId"></ns-user-selector>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <input type="text" name="keyword" v-model="keyword" placeholder="域名..."/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <button class="ui button" type="submit">搜索</button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <div v-if="domains.length == 0">
 | 
			
		||||
        <div class="margin"></div>
 | 
			
		||||
        <p class="comment">暂时还没有域名。</p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 域名列表 -->
 | 
			
		||||
    <table class="ui table selectable celled" v-if="domains.length > 0">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th>域名</th>
 | 
			
		||||
                <th>集群</th>
 | 
			
		||||
                <th>用户</th>
 | 
			
		||||
                <th class="two wide">状态</th>
 | 
			
		||||
                <th class="two op">操作</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tr v-for="domain in domains">
 | 
			
		||||
            <td><keyword :v-word="keyword">{{domain.name}}</keyword></td>
 | 
			
		||||
            <td>
 | 
			
		||||
                {{domain.cluster.name}}<link-icon :href="'/ns/clusters/cluster?clusterId=' + domain.cluster.id"></link-icon>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <span v-if="domain.user != null">
 | 
			
		||||
                    {{domain.user.fullname}} ({{domain.user.username}})
 | 
			
		||||
                </span>
 | 
			
		||||
                <span v-else class="disabled">-</span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td><label-on :v-is-on="domain.isOn"></label-on></td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <a :href="'/ns/domains/domain?domainId=' + domain.id">详情</a>   <a href="" @click.prevent="deleteDomain(domain.id)">删除</a>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										14
									
								
								web/views/@default/ns/domains/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								web/views/@default/ns/domains/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.deleteDomain = function (domainId) {
 | 
			
		||||
		let that = this
 | 
			
		||||
		teaweb.confirm("确定要删除此域名吗?", function () {
 | 
			
		||||
			that.$post("/ns/domains/delete")
 | 
			
		||||
				.params({
 | 
			
		||||
					domainId: domainId
 | 
			
		||||
				})
 | 
			
		||||
				.success(function () {
 | 
			
		||||
					teaweb.reload()
 | 
			
		||||
				})
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										33
									
								
								web/views/@default/ns/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								web/views/@default/ns/index.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
.ui.message .icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 1em;
 | 
			
		||||
  top: 1.8em;
 | 
			
		||||
}
 | 
			
		||||
.grid {
 | 
			
		||||
  margin-top: 2em !important;
 | 
			
		||||
  margin-left: 2em !important;
 | 
			
		||||
}
 | 
			
		||||
.grid .column {
 | 
			
		||||
  margin-bottom: 2em;
 | 
			
		||||
  border-right: 1px #eee solid;
 | 
			
		||||
}
 | 
			
		||||
.grid .column div.value {
 | 
			
		||||
  margin-top: 1.5em;
 | 
			
		||||
}
 | 
			
		||||
.grid .column div.value span {
 | 
			
		||||
  font-size: 2em;
 | 
			
		||||
  margin-right: 0.2em;
 | 
			
		||||
}
 | 
			
		||||
.grid .column.no-border {
 | 
			
		||||
  border-right: 0;
 | 
			
		||||
}
 | 
			
		||||
.grid h4 a {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
.grid .column:hover a {
 | 
			
		||||
  display: inline;
 | 
			
		||||
}
 | 
			
		||||
.chart-box {
 | 
			
		||||
  height: 20em;
 | 
			
		||||
}
 | 
			
		||||
/*# sourceMappingURL=index.css.map */
 | 
			
		||||
							
								
								
									
										1
									
								
								web/views/@default/ns/index.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/views/@default/ns/index.css.map
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,GAAG,QACF;EACC,kBAAA;EACA,UAAA;EACA,UAAA;;AAIF;EACC,0BAAA;EACA,2BAAA;;AAFD,KAIC;EACC,kBAAA;EACA,4BAAA;;AANF,KAIC,QAIC,IAAG;EACF,iBAAA;;AATH,KAIC,QAIC,IAAG,MAGF;EACC,cAAA;EACA,mBAAA;;AAbJ,KAkBC,QAAO;EACN,eAAA;;AAnBF,KAsBC,GACC;EACC,aAAA;;AAxBH,KA4BC,QAAO,MACN;EACC,eAAA;;AAKH;EACC,YAAA","file":"index.css"}
 | 
			
		||||
@@ -1,61 +1,60 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "menu"}
 | 
			
		||||
{$template "/echarts"}
 | 
			
		||||
 | 
			
		||||
<div v-if="countClusters == 0">
 | 
			
		||||
    <not-found-box>
 | 
			
		||||
        暂时还没有集群,请先 <a href="/ns/clusters/create">创建集群</a>。
 | 
			
		||||
    </not-found-box>
 | 
			
		||||
<div class="ui four columns grid">
 | 
			
		||||
    <div class="ui column">
 | 
			
		||||
        <h4>域名<link-icon href="/ns/domains"></link-icon></h4>
 | 
			
		||||
        <div class="value"><span>{{board.countDomains}}</span>个</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="ui column">
 | 
			
		||||
        <h4>记录<link-icon href="/ns/domains"></link-icon></h4>
 | 
			
		||||
        <div class="value"><span>{{board.countRecords}}</span>个</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="ui column">
 | 
			
		||||
        <h4>集群<link-icon href="/ns/clusters"></link-icon></h4>
 | 
			
		||||
        <div class="value"><span>{{board.countClusters}}</span>个</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="ui column no-border">
 | 
			
		||||
        <h4>节点<link-icon href="/ns/clusters"></link-icon></h4>
 | 
			
		||||
        <div class="value"><span>{{board.countNodes}}</span>
 | 
			
		||||
            <span v-if="board.countOfflineNodes > 0" class="red" style="font-size: 1em">{{board.countOfflineNodes}}离线</span>
 | 
			
		||||
            <span v-else style="font-size: 1em">个</span>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div v-if="countClusters > 0">
 | 
			
		||||
    <form class="ui form" method="get" action="/ns">
 | 
			
		||||
        <div class="ui fields inline">
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <ns-cluster-selector :v-cluster-id="clusterId"></ns-cluster-selector>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <ns-user-selector :v-user-id="userId"></ns-user-selector>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <input type="text" name="keyword" v-model="keyword" placeholder="域名..."/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="ui field">
 | 
			
		||||
                <button class="ui button" type="submit">搜索</button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
<!-- 流量统计 -->
 | 
			
		||||
<div class="ui menu tabular">
 | 
			
		||||
    <a href="" class="item" :class="{active: trafficTab == 'hourly'}" @click.prevent="selectTrafficTab('hourly')">24小时流量趋势</a>
 | 
			
		||||
    <a href="" class="item" :class="{active: trafficTab == 'daily'}" @click.prevent="selectTrafficTab('daily')">15天流量趋势</a>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
    <div v-if="domains.length == 0">
 | 
			
		||||
        <div class="margin"></div>
 | 
			
		||||
        <p class="comment">暂时还没有域名。</p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 域名列表 -->
 | 
			
		||||
    <table class="ui table selectable celled" v-if="domains.length > 0">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th>域名</th>
 | 
			
		||||
                <th>集群</th>
 | 
			
		||||
                <th>用户</th>
 | 
			
		||||
                <th class="two wide">状态</th>
 | 
			
		||||
                <th class="two op">操作</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tr v-for="domain in domains">
 | 
			
		||||
            <td><keyword :v-word="keyword">{{domain.name}}</keyword></td>
 | 
			
		||||
            <td>
 | 
			
		||||
                {{domain.cluster.name}}<link-icon :href="'/ns/clusters/cluster?clusterId=' + domain.cluster.id"></link-icon>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <span v-if="domain.user != null">
 | 
			
		||||
                    {{domain.user.fullname}} ({{domain.user.username}})
 | 
			
		||||
                </span>
 | 
			
		||||
                <span v-else class="disabled">-</span>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td><label-on :v-is-on="domain.isOn"></label-on></td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <a :href="'/ns/domains/domain?domainId=' + domain.id">详情</a>   <a href="" @click.prevent="deleteDomain(domain.id)">删除</a>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
<!-- 按小时统计流量 -->
 | 
			
		||||
<div class="chart-box" id="hourly-traffic-chart" v-show="trafficTab == 'hourly'"></div>
 | 
			
		||||
 | 
			
		||||
<!-- 按日统计流量 -->
 | 
			
		||||
<div class="chart-box" id="daily-traffic-chart" v-show="trafficTab == 'daily'"></div>
 | 
			
		||||
<div class="ui divider"></div>
 | 
			
		||||
 | 
			
		||||
<!-- 域名排行 -->
 | 
			
		||||
<h4>域名访问排行 <span>(24小时)</span></h4>
 | 
			
		||||
<div class="chart-box" id="top-domains-chart"></div>
 | 
			
		||||
<div class="ui divider"></div>
 | 
			
		||||
 | 
			
		||||
<!-- 节点排行 -->
 | 
			
		||||
<h4>节点访问排行 <span>(24小时)</span></h4>
 | 
			
		||||
<div class="chart-box" id="top-nodes-chart"></div>
 | 
			
		||||
<div class="ui divider"></div>
 | 
			
		||||
 | 
			
		||||
<!-- 系统信息 -->
 | 
			
		||||
<div class="ui divider"></div>
 | 
			
		||||
<div class="ui menu tabular">
 | 
			
		||||
    <a href="" class="item" :class="{active: nodeStatusTab == 'cpu'}" @click.prevent="selectNodeStatusTab('cpu')">DNS节点CPU</a>
 | 
			
		||||
    <a href="" class="item" :class="{active: nodeStatusTab == 'memory'}" @click.prevent="selectNodeStatusTab('memory')">DNS节点内存</a>
 | 
			
		||||
    <a href="" class="item" :class="{active: nodeStatusTab == 'load'}" @click.prevent="selectNodeStatusTab('load')">DNS节点负载</a>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="chart-box" id="cpu-chart" v-show="nodeStatusTab == 'cpu'"></div>
 | 
			
		||||
<div class="chart-box" id="memory-chart" v-show="nodeStatusTab == 'memory'"></div>
 | 
			
		||||
<div class="chart-box" id="load-chart" v-show="nodeStatusTab == 'load'"></div>
 | 
			
		||||
@@ -1,14 +1,246 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.deleteDomain = function (domainId) {
 | 
			
		||||
	this.$delay(function () {
 | 
			
		||||
		this.reloadHourlyTrafficChart()
 | 
			
		||||
		this.reloadTopDomainsChart()
 | 
			
		||||
		this.reloadTopNodesChart()
 | 
			
		||||
		this.reloadCPUChart()
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * 流量统计
 | 
			
		||||
	 */
 | 
			
		||||
	this.trafficTab = "hourly"
 | 
			
		||||
 | 
			
		||||
	this.selectTrafficTab = function (tab) {
 | 
			
		||||
		this.trafficTab = tab
 | 
			
		||||
		if (tab == "hourly") {
 | 
			
		||||
			this.$delay(function () {
 | 
			
		||||
				this.reloadHourlyTrafficChart()
 | 
			
		||||
			})
 | 
			
		||||
		} else if (tab == "daily") {
 | 
			
		||||
			this.$delay(function () {
 | 
			
		||||
				this.reloadDailyTrafficChart()
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.reloadHourlyTrafficChart = function () {
 | 
			
		||||
		let stats = this.hourlyStats
 | 
			
		||||
		this.reloadTrafficChart("hourly-traffic-chart", "流量统计", stats, function (args) {
 | 
			
		||||
			return stats[args.dataIndex].day + " " + stats[args.dataIndex].hour + "时 流量: " + teaweb.formatBytes(stats[args.dataIndex].bytes)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.reloadDailyTrafficChart = function () {
 | 
			
		||||
		let stats = this.dailyStats
 | 
			
		||||
		this.reloadTrafficChart("daily-traffic-chart", "流量统计", stats, function (args) {
 | 
			
		||||
			return stats[args.dataIndex].day + " 流量: " + teaweb.formatBytes(stats[args.dataIndex].bytes)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.reloadTrafficChart = function (chartId, name, stats, tooltipFunc) {
 | 
			
		||||
		let chartBox = document.getElementById(chartId)
 | 
			
		||||
		if (chartBox == null) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		let axis = teaweb.bytesAxis(stats, function (v) {
 | 
			
		||||
			return v.bytes
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		let chart = teaweb.initChart(chartBox)
 | 
			
		||||
		let option = {
 | 
			
		||||
			xAxis: {
 | 
			
		||||
				data: stats.map(function (v) {
 | 
			
		||||
					if (v.hour != null) {
 | 
			
		||||
						return v.hour
 | 
			
		||||
					}
 | 
			
		||||
					return v.day
 | 
			
		||||
				})
 | 
			
		||||
			},
 | 
			
		||||
			yAxis: {
 | 
			
		||||
				axisLabel: {
 | 
			
		||||
					formatter: function (value) {
 | 
			
		||||
						return value + axis.unit
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: {
 | 
			
		||||
				show: true,
 | 
			
		||||
				trigger: "item",
 | 
			
		||||
				formatter: tooltipFunc
 | 
			
		||||
			},
 | 
			
		||||
			grid: {
 | 
			
		||||
				left: 50,
 | 
			
		||||
				top: 40,
 | 
			
		||||
				right: 20,
 | 
			
		||||
				bottom: 20
 | 
			
		||||
			},
 | 
			
		||||
			series: [
 | 
			
		||||
				{
 | 
			
		||||
					name: "流量",
 | 
			
		||||
					type: "line",
 | 
			
		||||
					data: stats.map(function (v) {
 | 
			
		||||
						return v.bytes / axis.divider
 | 
			
		||||
					}),
 | 
			
		||||
					itemStyle: {
 | 
			
		||||
						color: "#9DD3E8"
 | 
			
		||||
					},
 | 
			
		||||
					areaStyle: {
 | 
			
		||||
						color: "#9DD3E8"
 | 
			
		||||
					},
 | 
			
		||||
					smooth: true
 | 
			
		||||
				}
 | 
			
		||||
			],
 | 
			
		||||
			animation: true
 | 
			
		||||
		}
 | 
			
		||||
		chart.setOption(option)
 | 
			
		||||
		chart.resize()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 域名排行
 | 
			
		||||
	this.reloadTopDomainsChart = function () {
 | 
			
		||||
		let that = this
 | 
			
		||||
		teaweb.confirm("确定要删除此域名吗?", function () {
 | 
			
		||||
			that.$post("/ns/domains/delete")
 | 
			
		||||
				.params({
 | 
			
		||||
					domainId: domainId
 | 
			
		||||
				})
 | 
			
		||||
				.success(function () {
 | 
			
		||||
					teaweb.reload()
 | 
			
		||||
				})
 | 
			
		||||
		let axis = teaweb.countAxis(this.topDomainStats, function (v) {
 | 
			
		||||
			return v.countRequests
 | 
			
		||||
		})
 | 
			
		||||
		teaweb.renderBarChart({
 | 
			
		||||
			id: "top-domains-chart",
 | 
			
		||||
			name: "域名",
 | 
			
		||||
			values: this.topDomainStats,
 | 
			
		||||
			x: function (v) {
 | 
			
		||||
				return v.domainName
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: function (args, stats) {
 | 
			
		||||
				return stats[args.dataIndex].domainName + "<br/>请求数:" + " " + teaweb.formatNumber(stats[args.dataIndex].countRequests) + "<br/>流量:" + teaweb.formatBytes(stats[args.dataIndex].bytes)
 | 
			
		||||
			},
 | 
			
		||||
			value: function (v) {
 | 
			
		||||
				return v.countRequests / axis.divider;
 | 
			
		||||
			},
 | 
			
		||||
			axis: axis,
 | 
			
		||||
			click: function (args, stats) {
 | 
			
		||||
				window.location = "/ns/domains/domain?domainId=" + stats[args.dataIndex].domainId
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 节点排行
 | 
			
		||||
	this.reloadTopNodesChart = function () {
 | 
			
		||||
		let that = this
 | 
			
		||||
		let axis = teaweb.countAxis(this.topNodeStats, function (v) {
 | 
			
		||||
			return v.countRequests
 | 
			
		||||
		})
 | 
			
		||||
		teaweb.renderBarChart({
 | 
			
		||||
			id: "top-nodes-chart",
 | 
			
		||||
			name: "节点",
 | 
			
		||||
			values: this.topNodeStats,
 | 
			
		||||
			x: function (v) {
 | 
			
		||||
				return v.nodeName
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: function (args, stats) {
 | 
			
		||||
				return stats[args.dataIndex].nodeName + "<br/>请求数:" + " " + teaweb.formatNumber(stats[args.dataIndex].countRequests) + "<br/>流量:" + teaweb.formatBytes(stats[args.dataIndex].bytes)
 | 
			
		||||
			},
 | 
			
		||||
			value: function (v) {
 | 
			
		||||
				return v.countRequests / axis.divider;
 | 
			
		||||
			},
 | 
			
		||||
			axis: axis,
 | 
			
		||||
			click: function (args, stats) {
 | 
			
		||||
				window.location = "/ns/clusters/cluster/node?nodeId=" + stats[args.dataIndex].nodeId + "&clusterId=" + stats[args.dataIndex].clusterId
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * 系统信息
 | 
			
		||||
	 */
 | 
			
		||||
	this.nodeStatusTab = "cpu"
 | 
			
		||||
 | 
			
		||||
	this.selectNodeStatusTab = function (tab) {
 | 
			
		||||
		this.nodeStatusTab = tab
 | 
			
		||||
		this.$delay(function () {
 | 
			
		||||
			switch (tab) {
 | 
			
		||||
				case "cpu":
 | 
			
		||||
					this.reloadCPUChart()
 | 
			
		||||
					break
 | 
			
		||||
				case "memory":
 | 
			
		||||
					this.reloadMemoryChart()
 | 
			
		||||
					break
 | 
			
		||||
				case "load":
 | 
			
		||||
					this.reloadLoadChart()
 | 
			
		||||
					break
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.reloadCPUChart = function () {
 | 
			
		||||
		let axis = {unit: "%", divider: 1}
 | 
			
		||||
		teaweb.renderLineChart({
 | 
			
		||||
			id: "cpu-chart",
 | 
			
		||||
			name: "CPU",
 | 
			
		||||
			values: this.cpuValues,
 | 
			
		||||
			x: function (v) {
 | 
			
		||||
				return v.time
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: function (args, stats) {
 | 
			
		||||
				return stats[args.dataIndex].time + ":" + (Math.ceil(stats[args.dataIndex].value * 100 * 100) / 100) + "%"
 | 
			
		||||
			},
 | 
			
		||||
			value: function (v) {
 | 
			
		||||
				return v.value * 100;
 | 
			
		||||
			},
 | 
			
		||||
			axis: axis,
 | 
			
		||||
			max: 100
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.reloadMemoryChart = function () {
 | 
			
		||||
		let axis = {unit: "%", divider: 1}
 | 
			
		||||
		teaweb.renderLineChart({
 | 
			
		||||
			id: "memory-chart",
 | 
			
		||||
			name: "内存",
 | 
			
		||||
			values: this.memoryValues,
 | 
			
		||||
			x: function (v) {
 | 
			
		||||
				return v.time
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: function (args, stats) {
 | 
			
		||||
				return stats[args.dataIndex].time + ":" + (Math.ceil(stats[args.dataIndex].value * 100 * 100) / 100) + "%"
 | 
			
		||||
			},
 | 
			
		||||
			value: function (v) {
 | 
			
		||||
				return v.value * 100;
 | 
			
		||||
			},
 | 
			
		||||
			axis: axis,
 | 
			
		||||
			max: 100
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.reloadLoadChart = function () {
 | 
			
		||||
		let axis = {unit: "", divider: 1}
 | 
			
		||||
		let max = this.loadValues.$map(function (k, v) {
 | 
			
		||||
			return v.value
 | 
			
		||||
		}).$max()
 | 
			
		||||
		if (max < 10) {
 | 
			
		||||
			max = 10
 | 
			
		||||
		} else if (max < 20) {
 | 
			
		||||
			max = 20
 | 
			
		||||
		} else if (max < 100) {
 | 
			
		||||
			max = 100
 | 
			
		||||
		} else {
 | 
			
		||||
			max = null
 | 
			
		||||
		}
 | 
			
		||||
		teaweb.renderLineChart({
 | 
			
		||||
			id: "load-chart",
 | 
			
		||||
			name: "负载",
 | 
			
		||||
			values: this.loadValues,
 | 
			
		||||
			x: function (v) {
 | 
			
		||||
				return v.time
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: function (args, stats) {
 | 
			
		||||
				return stats[args.dataIndex].time + ":" + (Math.ceil(stats[args.dataIndex].value * 100) / 100)
 | 
			
		||||
			},
 | 
			
		||||
			value: function (v) {
 | 
			
		||||
				return v.value;
 | 
			
		||||
			},
 | 
			
		||||
			axis: axis,
 | 
			
		||||
			max: max
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										46
									
								
								web/views/@default/ns/index.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								web/views/@default/ns/index.less
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
.ui.message {
 | 
			
		||||
	.icon {
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		right: 1em;
 | 
			
		||||
		top: 1.8em;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid {
 | 
			
		||||
	margin-top: 2em !important;
 | 
			
		||||
	margin-left: 2em !important;
 | 
			
		||||
 | 
			
		||||
	.column {
 | 
			
		||||
		margin-bottom: 2em;
 | 
			
		||||
		border-right: 1px #eee solid;
 | 
			
		||||
 | 
			
		||||
		div.value {
 | 
			
		||||
			margin-top: 1.5em;
 | 
			
		||||
 | 
			
		||||
			span {
 | 
			
		||||
				font-size: 2em;
 | 
			
		||||
				margin-right: 0.2em;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.column.no-border {
 | 
			
		||||
		border-right: 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h4 {
 | 
			
		||||
		a {
 | 
			
		||||
			display: none;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.column:hover {
 | 
			
		||||
		a {
 | 
			
		||||
			display: inline;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.chart-box {
 | 
			
		||||
	height: 20em;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user