Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3df181dcc | ||
|
|
699ea47ac5 | ||
|
|
fba69f3109 | ||
|
|
063583dda1 | ||
|
|
a31ca5cfb6 | ||
|
|
c0a13305ad | ||
|
|
9d8cbf87dc | ||
|
|
009f7da26b | ||
|
|
f1d0359dc4 | ||
|
|
473baa8c5b | ||
|
|
1a5dda6c72 |
@@ -1,7 +1,7 @@
|
||||
FROM alpine:latest
|
||||
LABEL maintainer="iwind.liu@gmail.com"
|
||||
ENV TZ "Asia/Shanghai"
|
||||
ENV VERSION 0.6.4
|
||||
ENV VERSION 0.6.4.1
|
||||
ENV ROOT_DIR /usr/local/goedge
|
||||
ENV TAR_FILE edge-admin-linux-amd64-plus-v${VERSION}.zip
|
||||
ENV TAR_URL "https://dl.goedge.cn/edge/v${VERSION}/edge-admin-linux-amd64-plus-v${VERSION}.zip"
|
||||
|
||||
@@ -21,9 +21,9 @@ type APIConfig struct {
|
||||
// LoadAPIConfig 加载API配置
|
||||
func LoadAPIConfig() (*APIConfig, error) {
|
||||
// 候选文件
|
||||
localFile := Tea.ConfigFile("api.yaml")
|
||||
isFromLocal := false
|
||||
paths := []string{localFile}
|
||||
var localFile = Tea.ConfigFile("api.yaml")
|
||||
var isFromLocal = false
|
||||
var paths = []string{localFile}
|
||||
homeDir, homeErr := os.UserHomeDir()
|
||||
if homeErr == nil {
|
||||
paths = append(paths, homeDir+"/."+teaconst.ProcessName+"/api.yaml")
|
||||
@@ -45,7 +45,7 @@ func LoadAPIConfig() (*APIConfig, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := &APIConfig{}
|
||||
var config = &APIConfig{}
|
||||
err = yaml.Unmarshal(data, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.6.4.1"
|
||||
Version = "0.6.4.2"
|
||||
|
||||
APINodeVersion = "0.6.4.1"
|
||||
APINodeVersion = "0.6.4.2"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
@@ -32,11 +32,12 @@ func (this *NodesAction) RunGet(params struct {
|
||||
Keyword string
|
||||
Level int32
|
||||
|
||||
CpuOrder string
|
||||
MemoryOrder string
|
||||
TrafficInOrder string
|
||||
TrafficOutOrder string
|
||||
LoadOrder string
|
||||
CpuOrder string
|
||||
MemoryOrder string
|
||||
TrafficInOrder string
|
||||
TrafficOutOrder string
|
||||
LoadOrder string
|
||||
ConnectionsOrder string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["regionId"] = params.RegionId
|
||||
@@ -44,7 +45,7 @@ func (this *NodesAction) RunGet(params struct {
|
||||
this.Data["activeState"] = params.ActiveState
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
this.Data["hasOrder"] = len(params.CpuOrder) > 0 || len(params.MemoryOrder) > 0 || len(params.TrafficInOrder) > 0 || len(params.TrafficOutOrder) > 0 || len(params.LoadOrder) > 0
|
||||
this.Data["hasOrder"] = len(params.CpuOrder) > 0 || len(params.MemoryOrder) > 0 || len(params.TrafficInOrder) > 0 || len(params.TrafficOutOrder) > 0 || len(params.LoadOrder) > 0 || len(params.ConnectionsOrder) > 0
|
||||
|
||||
// 集群是否已经设置了线路
|
||||
clusterDNSResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
@@ -112,6 +113,10 @@ func (this *NodesAction) RunGet(params struct {
|
||||
req.LoadAsc = true
|
||||
} else if params.LoadOrder == "desc" {
|
||||
req.LoadDesc = true
|
||||
} else if params.ConnectionsOrder == "asc" {
|
||||
req.ConnectionsAsc = true
|
||||
} else if params.ConnectionsOrder == "desc" {
|
||||
req.ConnectionsDesc = true
|
||||
}
|
||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), req)
|
||||
if err != nil {
|
||||
@@ -121,8 +126,8 @@ func (this *NodesAction) RunGet(params struct {
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
isSynced := false
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
var isSynced = false
|
||||
var status = &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
@@ -211,16 +216,17 @@ func (this *NodesAction) RunGet(params struct {
|
||||
"error": node.InstallStatus.Error,
|
||||
},
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"trafficInBytes": status.TrafficInBytes,
|
||||
"trafficOutBytes": status.TrafficOutBytes,
|
||||
"load1m": numberutils.FormatFloat2(status.Load1m),
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": fmt.Sprintf("%.2f%%", status.CPUUsage*100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": fmt.Sprintf("%.2f%%", status.MemoryUsage*100),
|
||||
"trafficInBytes": status.TrafficInBytes,
|
||||
"trafficOutBytes": status.TrafficOutBytes,
|
||||
"load1m": numberutils.FormatFloat2(status.Load1m),
|
||||
"countConnections": status.ConnectionCount,
|
||||
},
|
||||
"cluster": maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
|
||||
@@ -33,11 +33,12 @@ func (this *NodesAction) RunGet(params struct {
|
||||
Keyword string
|
||||
Level int32
|
||||
|
||||
CpuOrder string
|
||||
MemoryOrder string
|
||||
TrafficInOrder string
|
||||
TrafficOutOrder string
|
||||
LoadOrder string
|
||||
CpuOrder string
|
||||
MemoryOrder string
|
||||
TrafficInOrder string
|
||||
TrafficOutOrder string
|
||||
LoadOrder string
|
||||
ConnectionsOrder string
|
||||
}) {
|
||||
this.Data["groupId"] = params.GroupId
|
||||
this.Data["regionId"] = params.RegionId
|
||||
@@ -46,7 +47,7 @@ func (this *NodesAction) RunGet(params struct {
|
||||
this.Data["keyword"] = params.Keyword
|
||||
this.Data["level"] = params.Level
|
||||
this.Data["clusterId"] = params.ClusterId
|
||||
this.Data["hasOrder"] = len(params.CpuOrder) > 0 || len(params.MemoryOrder) > 0 || len(params.TrafficInOrder) > 0 || len(params.TrafficOutOrder) > 0 || len(params.LoadOrder) > 0
|
||||
this.Data["hasOrder"] = len(params.CpuOrder) > 0 || len(params.MemoryOrder) > 0 || len(params.TrafficInOrder) > 0 || len(params.TrafficOutOrder) > 0 || len(params.LoadOrder) > 0 || len(params.ConnectionsOrder) > 0
|
||||
|
||||
// 集群是否已经设置了线路
|
||||
clusterDNSResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
|
||||
@@ -114,6 +115,10 @@ func (this *NodesAction) RunGet(params struct {
|
||||
req.LoadAsc = true
|
||||
} else if params.LoadOrder == "desc" {
|
||||
req.LoadDesc = true
|
||||
} else if params.ConnectionsOrder == "asc" {
|
||||
req.ConnectionsAsc = true
|
||||
} else if params.ConnectionsOrder == "desc" {
|
||||
req.ConnectionsDesc = true
|
||||
}
|
||||
nodesResp, err := this.RPC().NodeRPC().ListEnabledNodesMatch(this.AdminContext(), req)
|
||||
if err != nil {
|
||||
@@ -123,8 +128,8 @@ func (this *NodesAction) RunGet(params struct {
|
||||
var nodeMaps = []maps.Map{}
|
||||
for _, node := range nodesResp.Nodes {
|
||||
// 状态
|
||||
isSynced := false
|
||||
status := &nodeconfigs.NodeStatus{}
|
||||
var isSynced = false
|
||||
var status = &nodeconfigs.NodeStatus{}
|
||||
if len(node.StatusJSON) > 0 {
|
||||
err = json.Unmarshal(node.StatusJSON, &status)
|
||||
if err != nil {
|
||||
@@ -213,16 +218,17 @@ func (this *NodesAction) RunGet(params struct {
|
||||
"error": node.InstallStatus.Error,
|
||||
},
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": numberutils.FormatFloat2(status.CPUUsage * 100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": numberutils.FormatFloat2(status.MemoryUsage * 100),
|
||||
"trafficInBytes": status.TrafficInBytes,
|
||||
"trafficOutBytes": status.TrafficOutBytes,
|
||||
"load1m": numberutils.FormatFloat2(status.Load1m),
|
||||
"isActive": status.IsActive,
|
||||
"updatedAt": status.UpdatedAt,
|
||||
"hostname": status.Hostname,
|
||||
"cpuUsage": status.CPUUsage,
|
||||
"cpuUsageText": numberutils.FormatFloat2(status.CPUUsage * 100),
|
||||
"memUsage": status.MemoryUsage,
|
||||
"memUsageText": numberutils.FormatFloat2(status.MemoryUsage * 100),
|
||||
"trafficInBytes": status.TrafficInBytes,
|
||||
"trafficOutBytes": status.TrafficOutBytes,
|
||||
"load1m": numberutils.FormatFloat2(status.Load1m),
|
||||
"countConnections": status.ConnectionCount,
|
||||
},
|
||||
"cluster": maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
|
||||
@@ -3,6 +3,7 @@ package redirects
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
@@ -134,6 +135,23 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
this.FailField("domainAfter", "请输入跳转后域名")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户输入的是否为域名
|
||||
if !domainutils.ValidateDomainFormat(params.DomainAfter) {
|
||||
// 是否为URL
|
||||
u, err := url.Parse(params.DomainAfter)
|
||||
if err == nil {
|
||||
if len(u.Host) == 0 {
|
||||
this.FailField("domainAfter", "跳转后域名输入不正确")
|
||||
return
|
||||
}
|
||||
params.DomainAfter = u.Host
|
||||
} else {
|
||||
this.FailField("domainAfter", "跳转后域名输入不正确")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
config.DomainAfter = params.DomainAfter
|
||||
config.DomainAfterScheme = params.DomainAfterScheme
|
||||
case serverconfigs.HTTPHostRedirectTypePort:
|
||||
|
||||
@@ -15,7 +15,7 @@ type ThemeAction struct {
|
||||
func (this *ThemeAction) RunPost(params struct{}) {
|
||||
theme := configloaders.FindAdminTheme(this.AdminId())
|
||||
|
||||
var themes = []string{"theme1", "theme2", "theme3", "theme4", "theme5"}
|
||||
var themes = []string{"theme1", "theme2", "theme3", "theme4", "theme5", "theme6", "theme7"}
|
||||
var nextTheme = "theme1"
|
||||
if len(theme) == 0 {
|
||||
nextTheme = "theme2"
|
||||
|
||||
@@ -5282,7 +5282,9 @@ example2.com
|
||||
<option value="10">[每页]</option><option value="10" selected="selected">10条</option><option value="20">20条</option><option value="30">30条</option><option value="40">40条</option><option value="50">50条</option><option value="60">60条</option><option value="70">70条</option><option value="80">80条</option><option value="90">90条</option><option value="100">100条</option>
|
||||
</select>`}),Vue.component("second-menu",{template:' \t\t<div class="second-menu"> \t\t\t<div class="ui menu text blue small">\t\t\t\t<slot></slot>\t\t\t</div> \t\t\t<div class="ui divider"></div> \t\t</div>'}),Vue.component("loading-message",{template:`<div class="ui message loading">
|
||||
<div class="ui active inline loader small"></div> <slot></slot>
|
||||
</div>`}),Vue.component("more-options-angle",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:'<a href="" @click.prevent="show()"><span v-if="!isVisible">更多选项</span><span v-if="isVisible">收起选项</span><i class="icon angle" :class="{down:!isVisible, up:isVisible}"></i></a>'}),Vue.component("inner-menu-item",{props:["href","active","code"],data:function(){var e,t=this.active;return void 0===t&&(e="",t=(e=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:e)==this.code),{vHref:null==this.href?"":this.href,vActive:t}},template:'\t\t<a :href="vHref" class="item right" style="color:#4183c4" :class="{active:vActive}">[<slot></slot>]</a> \t\t'}),Vue.component("health-check-config-box",{props:["v-health-check-config","v-check-domain-url"],data:function(){let t=this.vHealthCheckConfig,i="http",n="",s="/",o="";if(null==t){t={isOn:!1,url:"",interval:{count:60,unit:"second"},statusCodes:[200],timeout:{count:10,unit:"second"},countTries:3,tryDelay:{count:100,unit:"ms"},autoDown:!0,countUp:1,countDown:3,userAgent:"",onlyBasicRequest:!0,accessLogIsOn:!0};let e=this;setTimeout(function(){e.changeURL()},500)}else{try{let e=new URL(t.url);i=e.protocol.substring(0,e.protocol.length-1);var a=(o="%24%7Bhost%7D"==(o=e.host)?"${host}":o).indexOf(":");0<a&&(o=o.substring(0,a)),n=e.port,s=e.pathname,0<e.search.length&&(s+=e.search)}catch(e){}null==t.statusCodes&&(t.statusCodes=[200]),null==t.interval&&(t.interval={count:60,unit:"second"}),null==t.timeout&&(t.timeout={count:10,unit:"second"}),null==t.tryDelay&&(t.tryDelay={count:100,unit:"ms"}),(null==t.countUp||t.countUp<1)&&(t.countUp=1),(null==t.countDown||t.countDown<1)&&(t.countDown=3)}return{healthCheck:t,advancedVisible:!1,urlProtocol:i,urlHost:o,urlPort:n,urlRequestURI:s,urlIsEditing:0==t.url.length,hostErr:""}},watch:{urlRequestURI:function(){0<this.urlRequestURI.length&&"/"!=this.urlRequestURI[0]&&(this.urlRequestURI="/"+this.urlRequestURI),this.changeURL()},urlPort:function(e){let t=parseInt(e);isNaN(t)?this.urlPort="":this.urlPort=t.toString(),this.changeURL()},urlProtocol:function(){this.changeURL()},urlHost:function(){this.changeURL(),this.hostErr=""},"healthCheck.countTries":function(e){e=parseInt(e);isNaN(e)?this.healthCheck.countTries=0:this.healthCheck.countTries=e},"healthCheck.countUp":function(e){e=parseInt(e);isNaN(e)?this.healthCheck.countUp=0:this.healthCheck.countUp=e},"healthCheck.countDown":function(e){e=parseInt(e);isNaN(e)?this.healthCheck.countDown=0:this.healthCheck.countDown=e}},methods:{showAdvanced:function(){this.advancedVisible=!this.advancedVisible},changeURL:function(){let e=this.urlHost;0==e.length&&(e="${host}"),this.healthCheck.url=this.urlProtocol+"://"+e+(0<this.urlPort.length?":"+this.urlPort:"")+this.urlRequestURI},changeStatus:function(e){this.healthCheck.statusCodes=e.$map(function(e,t){t=parseInt(t);return isNaN(t)?0:t})},onChangeURLHost:function(){var e=this.vCheckDomainUrl;if(null!=e&&0!=e.length){let t=this;Tea.action(e).params({host:this.urlHost}).success(function(e){e.data.isOk?t.hostErr="":t.hostErr="在当前集群中找不到此域名,可能会影响健康检查结果。"}).post()}},editURL:function(){this.urlIsEditing=!this.urlIsEditing}},template:`<div>
|
||||
</div>`}),Vue.component("more-options-angle",{data:function(){return{isVisible:!1}},methods:{show:function(){this.isVisible=!this.isVisible,this.$emit("change",this.isVisible)}},template:'<a href="" @click.prevent="show()"><span v-if="!isVisible">更多选项</span><span v-if="isVisible">收起选项</span><i class="icon angle" :class="{down:!isVisible, up:isVisible}"></i></a>'}),Vue.component("inner-menu-item",{props:["href","active","code"],data:function(){var e,t=this.active;return void 0===t&&(e="",t=(e=void 0!==window.TEA.ACTION.data.firstMenuItem?window.TEA.ACTION.data.firstMenuItem:e)==this.code),{vHref:null==this.href?"":this.href,vActive:t}},template:'\t\t<a :href="vHref" class="item right" style="color:#4183c4" :class="{active:vActive}">[<slot></slot>]</a> \t\t'}),Vue.component("columns-grid",{props:[],mounted:function(){this.columns=this.calculateColumns();let e=this;window.addEventListener("resize",function(){e.columns=e.calculateColumns()})},data:function(){return{columns:"four"}},methods:{calculateColumns:function(){var e=window.innerWidth;let i=Math.floor(e/250);0==i&&(i=1);var n=this.$el.getElementsByClassName("column");if(0!=n.length){e=n.length;i>e&&(i=e);for(let t=0;t<n.length;t++){let e=n[t];e.className=e.className.replace("with-border",""),t%i!=i-1&&t!=n.length-1||(e.className+=" with-border")}switch(i){case 1:return"one";case 2:return"two";case 3:return"three";case 4:return"four";case 5:return"five";case 6:return"six";case 7:return"seven";case 8:return"eight";case 9:return"nine";default:return"ten"}}}},template:`<div :class="'ui ' + columns + ' columns grid counter-chart'">
|
||||
<slot></slot>
|
||||
</div>`}),Vue.component("health-check-config-box",{props:["v-health-check-config","v-check-domain-url"],data:function(){let t=this.vHealthCheckConfig,i="http",n="",s="/",o="";if(null==t){t={isOn:!1,url:"",interval:{count:60,unit:"second"},statusCodes:[200],timeout:{count:10,unit:"second"},countTries:3,tryDelay:{count:100,unit:"ms"},autoDown:!0,countUp:1,countDown:3,userAgent:"",onlyBasicRequest:!0,accessLogIsOn:!0};let e=this;setTimeout(function(){e.changeURL()},500)}else{try{let e=new URL(t.url);i=e.protocol.substring(0,e.protocol.length-1);var a=(o="%24%7Bhost%7D"==(o=e.host)?"${host}":o).indexOf(":");0<a&&(o=o.substring(0,a)),n=e.port,s=e.pathname,0<e.search.length&&(s+=e.search)}catch(e){}null==t.statusCodes&&(t.statusCodes=[200]),null==t.interval&&(t.interval={count:60,unit:"second"}),null==t.timeout&&(t.timeout={count:10,unit:"second"}),null==t.tryDelay&&(t.tryDelay={count:100,unit:"ms"}),(null==t.countUp||t.countUp<1)&&(t.countUp=1),(null==t.countDown||t.countDown<1)&&(t.countDown=3)}return{healthCheck:t,advancedVisible:!1,urlProtocol:i,urlHost:o,urlPort:n,urlRequestURI:s,urlIsEditing:0==t.url.length,hostErr:""}},watch:{urlRequestURI:function(){0<this.urlRequestURI.length&&"/"!=this.urlRequestURI[0]&&(this.urlRequestURI="/"+this.urlRequestURI),this.changeURL()},urlPort:function(e){let t=parseInt(e);isNaN(t)?this.urlPort="":this.urlPort=t.toString(),this.changeURL()},urlProtocol:function(){this.changeURL()},urlHost:function(){this.changeURL(),this.hostErr=""},"healthCheck.countTries":function(e){e=parseInt(e);isNaN(e)?this.healthCheck.countTries=0:this.healthCheck.countTries=e},"healthCheck.countUp":function(e){e=parseInt(e);isNaN(e)?this.healthCheck.countUp=0:this.healthCheck.countUp=e},"healthCheck.countDown":function(e){e=parseInt(e);isNaN(e)?this.healthCheck.countDown=0:this.healthCheck.countDown=e}},methods:{showAdvanced:function(){this.advancedVisible=!this.advancedVisible},changeURL:function(){let e=this.urlHost;0==e.length&&(e="${host}"),this.healthCheck.url=this.urlProtocol+"://"+e+(0<this.urlPort.length?":"+this.urlPort:"")+this.urlRequestURI},changeStatus:function(e){this.healthCheck.statusCodes=e.$map(function(e,t){t=parseInt(t);return isNaN(t)?0:t})},onChangeURLHost:function(){var e=this.vCheckDomainUrl;if(null!=e&&0!=e.length){let t=this;Tea.action(e).params({host:this.urlHost}).success(function(e){e.data.isOk?t.hostErr="":t.hostErr="在当前集群中找不到此域名,可能会影响健康检查结果。"}).post()}},editURL:function(){this.urlIsEditing=!this.urlIsEditing}},template:`<div>
|
||||
<input type="hidden" name="healthCheckJSON" :value="JSON.stringify(healthCheck)"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tbody>
|
||||
|
||||
@@ -15654,6 +15654,78 @@ Vue.component("inner-menu-item", {
|
||||
'
|
||||
});
|
||||
|
||||
Vue.component("columns-grid", {
|
||||
props: [],
|
||||
mounted: function () {
|
||||
this.columns = this.calculateColumns()
|
||||
|
||||
let that = this
|
||||
window.addEventListener("resize", function () {
|
||||
that.columns = that.calculateColumns()
|
||||
})
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
columns: "four"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculateColumns: function () {
|
||||
let w = window.innerWidth
|
||||
let columns = Math.floor(w / 250)
|
||||
if (columns == 0) {
|
||||
columns = 1
|
||||
}
|
||||
|
||||
let columnElements = this.$el.getElementsByClassName("column")
|
||||
if (columnElements.length == 0) {
|
||||
return
|
||||
}
|
||||
let maxColumns = columnElements.length
|
||||
if (columns > maxColumns) {
|
||||
columns = maxColumns
|
||||
}
|
||||
|
||||
// 添加右侧边框
|
||||
for (let index = 0; index < columnElements.length; index++) {
|
||||
let el = columnElements[index]
|
||||
el.className = el.className.replace("with-border", "")
|
||||
if (index % columns == columns - 1 || index == columnElements.length - 1 /** 最后一个 **/) {
|
||||
el.className += " with-border"
|
||||
}
|
||||
}
|
||||
|
||||
switch (columns) {
|
||||
case 1:
|
||||
return "one"
|
||||
case 2:
|
||||
return "two"
|
||||
case 3:
|
||||
return "three"
|
||||
case 4:
|
||||
return "four"
|
||||
case 5:
|
||||
return "five"
|
||||
case 6:
|
||||
return "six"
|
||||
case 7:
|
||||
return "seven"
|
||||
case 8:
|
||||
return "eight"
|
||||
case 9:
|
||||
return "nine"
|
||||
case 10:
|
||||
return "ten"
|
||||
default:
|
||||
return "ten"
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<div :class="'ui ' + columns + ' columns grid counter-chart'">
|
||||
<slot></slot>
|
||||
</div>`
|
||||
})
|
||||
|
||||
Vue.component("health-check-config-box", {
|
||||
props: ["v-health-check-config", "v-check-domain-url"],
|
||||
data: function () {
|
||||
|
||||
71
web/public/js/components/common/grid_columns.js
Normal file
71
web/public/js/components/common/grid_columns.js
Normal file
@@ -0,0 +1,71 @@
|
||||
Vue.component("columns-grid", {
|
||||
props: [],
|
||||
mounted: function () {
|
||||
this.columns = this.calculateColumns()
|
||||
|
||||
let that = this
|
||||
window.addEventListener("resize", function () {
|
||||
that.columns = that.calculateColumns()
|
||||
})
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
columns: "four"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculateColumns: function () {
|
||||
let w = window.innerWidth
|
||||
let columns = Math.floor(w / 250)
|
||||
if (columns == 0) {
|
||||
columns = 1
|
||||
}
|
||||
|
||||
let columnElements = this.$el.getElementsByClassName("column")
|
||||
if (columnElements.length == 0) {
|
||||
return
|
||||
}
|
||||
let maxColumns = columnElements.length
|
||||
if (columns > maxColumns) {
|
||||
columns = maxColumns
|
||||
}
|
||||
|
||||
// 添加右侧边框
|
||||
for (let index = 0; index < columnElements.length; index++) {
|
||||
let el = columnElements[index]
|
||||
el.className = el.className.replace("with-border", "")
|
||||
if (index % columns == columns - 1 || index == columnElements.length - 1 /** 最后一个 **/) {
|
||||
el.className += " with-border"
|
||||
}
|
||||
}
|
||||
|
||||
switch (columns) {
|
||||
case 1:
|
||||
return "one"
|
||||
case 2:
|
||||
return "two"
|
||||
case 3:
|
||||
return "three"
|
||||
case 4:
|
||||
return "four"
|
||||
case 5:
|
||||
return "five"
|
||||
case 6:
|
||||
return "six"
|
||||
case 7:
|
||||
return "seven"
|
||||
case 8:
|
||||
return "eight"
|
||||
case 9:
|
||||
return "nine"
|
||||
case 10:
|
||||
return "ten"
|
||||
default:
|
||||
return "ten"
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `<div :class="'ui ' + columns + ' columns grid counter-chart'">
|
||||
<slot></slot>
|
||||
</div>`
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
.grid.counter-chart {
|
||||
margin-top: 1.5em !important;
|
||||
margin-top: 1em !important;
|
||||
margin-left: 0.4em !important;
|
||||
}
|
||||
.grid.counter-chart .column {
|
||||
@@ -22,14 +22,19 @@
|
||||
border-right: 1px rgba(0, 0, 0, 0.1) solid;
|
||||
}
|
||||
.grid.counter-chart h4 {
|
||||
color: grey;
|
||||
position: relative;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
.grid.counter-chart h4 a {
|
||||
position: absolute;
|
||||
right: 0.1em;
|
||||
font-size: 1.26em;
|
||||
display: none;
|
||||
}
|
||||
.grid.counter-chart .column:hover {
|
||||
background: rgba(0, 0, 0, 0.1) !important;
|
||||
background: rgba(0, 0, 0, 0.03) !important;
|
||||
}
|
||||
.grid.counter-chart .column:hover a {
|
||||
display: inline;
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":["@grids.less"],"names":[],"mappings":"AAAA,KAAK;EACJ,iBAAA;EACA,kBAAA;;AAFD,KAAK,cAIJ;EACC,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,kBAAA;EACA,oCAAA;EACA,eAAA;;AAVF,KAAK,cAIJ,QAQC,IAAG;EACF,iBAAA;EACA,mBAAA;;AAdH,KAAK,cAIJ,QAQC,IAAG,MAIF;EACC,gBAAA;EACA,mBAAA;;AAlBJ,KAAK,cAuBJ,QAAO;EACN,0CAAA;;AAxBF,KAAK,cA2BJ;EAKC,cAAA;EACA,gBAAA;;AAjCF,KAAK,cA2BJ,GACC;EACC,aAAA;;AA7BH,KAAK,cAoCJ,QAAO;EACN,8BAAA;;AArCF,KAAK,cAoCJ,QAAO,MAGN;EACC,eAAA","file":"@grids.css"}
|
||||
{"version":3,"sources":["@grids.less"],"names":[],"mappings":"AAAA,KAAK;EACJ,0BAAA;EACA,kBAAA;;AAFD,KAAK,cAIJ;EACC,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,kBAAA;EACA,oCAAA;EACA,eAAA;;AAVF,KAAK,cAIJ,QAQC,IAAG;EACF,iBAAA;EACA,mBAAA;;AAdH,KAAK,cAIJ,QAQC,IAAG,MAIF;EACC,gBAAA;EACA,mBAAA;;AAlBJ,KAAK,cAuBJ,QAAO;EACN,0CAAA;;AAxBF,KAAK,cA2BJ;EACC,WAAA;EACA,kBAAA;EASA,cAAA;EACA,gBAAA;;AAvCF,KAAK,cA2BJ,GAIC;EACC,kBAAA;EACA,YAAA;EACA,iBAAA;EACA,aAAA;;AAnCH,KAAK,cA0CJ,QAAO;EACN,+BAAA;;AA3CF,KAAK,cA0CJ,QAAO,MAGN;EACC,eAAA","file":"@grids.css"}
|
||||
@@ -405,6 +405,12 @@ body.expanded .main {
|
||||
.top-nav.theme5 {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
.top-nav.theme6 {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
.top-nav.theme7 {
|
||||
background: black !important;
|
||||
}
|
||||
.top-nav::-webkit-scrollbar {
|
||||
height: 2px;
|
||||
}
|
||||
@@ -563,6 +569,18 @@ body.expanded .main {
|
||||
.main-menu.theme5 .menu {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
.main-menu.theme6 {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
.main-menu.theme6 .menu {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
.main-menu.theme7 {
|
||||
background: black !important;
|
||||
}
|
||||
.main-menu.theme7 .menu {
|
||||
background: black !important;
|
||||
}
|
||||
.main-menu::-webkit-scrollbar {
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -82,7 +82,7 @@ Tea.context(function () {
|
||||
|
||||
this.showMessages = function () {
|
||||
teaweb.popup("/messages", {
|
||||
height: "24em",
|
||||
height: "28em",
|
||||
width: "50em"
|
||||
})
|
||||
}
|
||||
@@ -138,7 +138,7 @@ Tea.context(function () {
|
||||
|
||||
this.showNodeTasks = function () {
|
||||
teaweb.popup("/clusters/tasks/listPopup", {
|
||||
height: "24em",
|
||||
height: "28em",
|
||||
width: "54em"
|
||||
})
|
||||
}
|
||||
@@ -177,7 +177,7 @@ Tea.context(function () {
|
||||
|
||||
this.showDNSTasks = function () {
|
||||
teaweb.popup("/dns/tasks/listPopup", {
|
||||
height: "24em",
|
||||
height: "28em",
|
||||
width: "54em"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -338,11 +338,18 @@ body.expanded .main {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
|
||||
.top-nav.theme6 {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
|
||||
.top-nav.theme7 {
|
||||
background: black !important;
|
||||
}
|
||||
|
||||
.top-nav::-webkit-scrollbar {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
|
||||
/** 顶部菜单 **/
|
||||
.top-secondary-menu {
|
||||
position: fixed;
|
||||
@@ -544,6 +551,22 @@ body.expanded .main {
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme6 {
|
||||
background: #1D365D !important;
|
||||
|
||||
.menu {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme7 {
|
||||
background: black !important;
|
||||
|
||||
.menu {
|
||||
background: black !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu::-webkit-scrollbar {
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
@@ -64,10 +64,11 @@
|
||||
<th>节点名称</th>
|
||||
<th>IP</th>
|
||||
<th class="width10">DNS线路</th>
|
||||
<th class="width5 center">CPU<sort-arrow name="cpuOrder"></sort-arrow></th>
|
||||
<th class="width5 center">内存<sort-arrow name="memoryOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em">下行带宽<sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em">负载<sort-arrow name="loadOrder"></sort-arrow></th>
|
||||
<th class="width5 center" v-if="windowWidth < miniWidth || windowWidth > columnWidth1">CPU<sort-arrow name="cpuOrder"></sort-arrow></th>
|
||||
<th class="width5 center" v-if="windowWidth < miniWidth || windowWidth > columnWidth2">内存<sort-arrow name="memoryOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em" v-if="windowWidth < miniWidth || windowWidth > columnWidth3">下行带宽<sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em" v-if="windowWidth < miniWidth || windowWidth > columnWidth4">连接数<sort-arrow name="connectionsOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em" v-if="windowWidth < miniWidth || windowWidth > columnWidth5">负载<sort-arrow name="loadOrder"></sort-arrow></th>
|
||||
<th class="two wide center">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
@@ -117,20 +118,24 @@
|
||||
</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth1">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.cpuUsage > 0.50}">{{node.status.cpuUsageText}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth2">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.memUsage > 0.80}">{{node.status.memUsageText}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth3">
|
||||
<span v-if="node.status.isActive && node.status.trafficOutBytes > 0">{{teaweb.formatBits(node.status.trafficOutBytes * 8/60)}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<span v-if="node.status.isActive">{{node.status.load1m}}</span>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth4">
|
||||
<span v-if="node.status.isActive && node.status.countConnections > 0">{{node.status.countConnections}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth5">
|
||||
<span v-if="node.status.isActive && node.status.load1m > 0">{{node.status.load1m}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
Tea.context(function () {
|
||||
this.teaweb = teaweb
|
||||
|
||||
// 显示的统计项
|
||||
this.windowWidth = window.innerWidth
|
||||
this.miniWidth = 760
|
||||
this.columnWidth1 = 800
|
||||
this.columnWidth2 = 900
|
||||
this.columnWidth3 = 1000
|
||||
this.columnWidth4 = 1100
|
||||
this.columnWidth5 = 1200
|
||||
|
||||
let that = this
|
||||
window.addEventListener("resize", function () {
|
||||
that.windowWidth = window.innerWidth
|
||||
})
|
||||
|
||||
this.deleteNode = function (nodeId) {
|
||||
teaweb.confirm("确定要从当前集群中删除这个节点吗?", function () {
|
||||
this.$post("/nodes/delete")
|
||||
|
||||
@@ -58,10 +58,11 @@
|
||||
<th>节点名称</th>
|
||||
<th>IP</th>
|
||||
<th class="width10">DNS线路</th>
|
||||
<th class="width5 center">CPU<sort-arrow name="cpuOrder"></sort-arrow></th>
|
||||
<th class="width5 center">内存<sort-arrow name="memoryOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em">下行带宽<sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em">负载<sort-arrow name="loadOrder"></sort-arrow></th>
|
||||
<th class="width5 center" v-if="windowWidth < miniWidth || windowWidth > columnWidth1">CPU<sort-arrow name="cpuOrder"></sort-arrow></th>
|
||||
<th class="width5 center" v-if="windowWidth < miniWidth || windowWidth > columnWidth2">内存<sort-arrow name="memoryOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em" v-if="windowWidth < miniWidth || windowWidth > columnWidth3">下行带宽<sort-arrow name="trafficOutOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em" v-if="windowWidth < miniWidth || windowWidth > columnWidth4">连接数<sort-arrow name="connectionsOrder"></sort-arrow></th>
|
||||
<th class="center" style="width: 7em" v-if="windowWidth < miniWidth || windowWidth > columnWidth5">负载<sort-arrow name="loadOrder"></sort-arrow></th>
|
||||
<th class="two wide center">状态</th>
|
||||
<th class="one op">操作</th>
|
||||
</tr>
|
||||
@@ -111,20 +112,24 @@
|
||||
</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.cpuUsage > 0.50}">{{node.status.cpuUsageText}}%</span>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth1">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.cpuUsage > 0.50}">{{node.status.cpuUsageText}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.memUsage > 0.80}">{{node.status.memUsageText}}%</span>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth2">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.memUsage > 0.80}">{{node.status.memUsageText}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth3">
|
||||
<span v-if="node.status.isActive && node.status.trafficOutBytes > 0">{{teaweb.formatBits(node.status.trafficOutBytes * 8/60)}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<span v-if="node.status.isActive">{{node.status.load1m}}<span class="grey small"></span></span>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth4">
|
||||
<span v-if="node.status.isActive && node.status.countConnections > 0">{{node.status.countConnections}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth5">
|
||||
<span v-if="node.status.isActive && node.status.load1m > 0">{{node.status.load1m}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
Tea.context(function () {
|
||||
this.teaweb = teaweb
|
||||
|
||||
// 显示的统计项
|
||||
this.windowWidth = window.innerWidth
|
||||
this.miniWidth = 760
|
||||
this.columnWidth1 = 800
|
||||
this.columnWidth2 = 900
|
||||
this.columnWidth3 = 1000
|
||||
this.columnWidth4 = 1100
|
||||
this.columnWidth5 = 1200
|
||||
|
||||
let that = this
|
||||
window.addEventListener("resize", function () {
|
||||
that.windowWidth = window.innerWidth
|
||||
})
|
||||
|
||||
this.deleteNode = function (nodeId) {
|
||||
teaweb.confirm("确定要删除这个节点吗?", function () {
|
||||
this.$post("/cluster/nodes/delete")
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 统计图表 -->
|
||||
<div class="ui three columns grid counter-chart" v-if="!isLoading">
|
||||
<columns-grid v-if="!isLoading">
|
||||
<div class="ui column">
|
||||
<h4>集群<link-icon href="/clusters" v-if="dashboard.canGoNodes"></link-icon></h4>
|
||||
<div class="value"><span>{{dashboard.countNodeClusters}}</span>个</div>
|
||||
@@ -85,7 +85,7 @@
|
||||
<h4>今日流量</h4>
|
||||
<div class="value"><span>{{todayTraffic}}</span>{{todayTrafficUnit}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</columns-grid>
|
||||
|
||||
<div class="ui divider" v-show="!isLoading"></div>
|
||||
|
||||
|
||||
@@ -90,7 +90,8 @@
|
||||
<tr>
|
||||
<td class="color-border">跳转后域名 *</td>
|
||||
<td>
|
||||
<input type="text" name="domainAfter" maxlength="100" v-model="redirect.domainAfter"/>
|
||||
<input type="text" name="domainAfter" maxlength="100" v-model="redirect.domainAfter" placeholder="比如example.com"/>
|
||||
<p class="comment">这里填写的是网址中的域名部分,不需要添加<code-label>https://</code-label>部分。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user