mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-06 06:40:27 +08:00
实现基本的域名、记录管理
This commit is contained in:
@@ -158,7 +158,7 @@ func AllModuleMaps() []maps.Map {
|
|||||||
}
|
}
|
||||||
if teaconst.IsPlus {
|
if teaconst.IsPlus {
|
||||||
m = append(m, maps.Map{
|
m = append(m, maps.Map{
|
||||||
"name": "域名服务器",
|
"name": "域名服务",
|
||||||
"code": AdminModuleCodeNS,
|
"code": AdminModuleCodeNS,
|
||||||
"url": "/ns",
|
"url": "/ns",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -360,6 +360,14 @@ func (this *RPCClient) NSNodeRPC() pb.NSNodeServiceClient {
|
|||||||
return pb.NewNSNodeServiceClient(this.pickConn())
|
return pb.NewNSNodeServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) NSDomainRPC() pb.NSDomainServiceClient {
|
||||||
|
return pb.NewNSDomainServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) NSRecordRPC() pb.NSRecordServiceClient {
|
||||||
|
return pb.NewNSRecordServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
// Context 构造Admin上下文
|
// Context 构造Admin上下文
|
||||||
func (this *RPCClient) Context(adminId int64) context.Context {
|
func (this *RPCClient) Context(adminId int64) context.Context {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ func FailPage(action actions.ActionWrapper, err error) {
|
|||||||
<div style="background: #eee; border: 1px #ccc solid; padding: 10px; font-size: 12px; line-height: 1.8">
|
<div style="background: #eee; border: 1px #ccc solid; padding: 10px; font-size: 12px; line-height: 1.8">
|
||||||
` + teaconst.ErrServer + `
|
` + teaconst.ErrServer + `
|
||||||
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
<div>可以通过查看 <strong><em>$安装目录/logs/run.log</em></strong> 日志文件查看具体的错误提示。</div>
|
||||||
|
<hr style="border-top: 1px #ccc solid"/>
|
||||||
|
<div style="color: red">Error: ` + err.Error() + `</pre>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>`)
|
</html>`)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ func init() {
|
|||||||
Prefix("/ns/clusters").
|
Prefix("/ns/clusters").
|
||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
GetPost("/create", new(CreateAction)).
|
GetPost("/create", new(CreateAction)).
|
||||||
|
Post("/options", new(OptionsAction)).
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
88
internal/web/actions/default/ns/clusters/logs/index.go
Normal file
88
internal/web/actions/default/ns/clusters/logs/index.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/maps"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
DayFrom string
|
||||||
|
DayTo string
|
||||||
|
Keyword string
|
||||||
|
Level string
|
||||||
|
}) {
|
||||||
|
this.Data["dayFrom"] = params.DayFrom
|
||||||
|
this.Data["dayTo"] = params.DayTo
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
this.Data["level"] = params.Level
|
||||||
|
|
||||||
|
countResp, err := this.RPC().NodeLogRPC().CountNodeLogs(this.AdminContext(), &pb.CountNodeLogsRequest{
|
||||||
|
NodeId: 0,
|
||||||
|
Role: nodeconfigs.NodeRoleDNS,
|
||||||
|
DayFrom: params.DayFrom,
|
||||||
|
DayTo: params.DayTo,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Level: params.Level,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count := countResp.Count
|
||||||
|
page := this.NewPage(count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
logsResp, err := this.RPC().NodeLogRPC().ListNodeLogs(this.AdminContext(), &pb.ListNodeLogsRequest{
|
||||||
|
NodeId: 0,
|
||||||
|
Role: nodeconfigs.NodeRoleDNS,
|
||||||
|
DayFrom: params.DayFrom,
|
||||||
|
DayTo: params.DayTo,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Level: params.Level,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
|
||||||
|
logs := []maps.Map{}
|
||||||
|
for _, log := range logsResp.NodeLogs {
|
||||||
|
// 节点信息
|
||||||
|
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: log.NodeId})
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node := nodeResp.NsNode
|
||||||
|
if node == nil || node.NsCluster == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logs = append(logs, maps.Map{
|
||||||
|
"tag": log.Tag,
|
||||||
|
"description": log.Description,
|
||||||
|
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
|
||||||
|
"level": log.Level,
|
||||||
|
"isToday": timeutil.FormatTime("Y-m-d", log.CreatedAt) == timeutil.Format("Y-m-d"),
|
||||||
|
"count": log.Count,
|
||||||
|
"node": maps.Map{
|
||||||
|
"id": node.Id,
|
||||||
|
"cluster": maps.Map{
|
||||||
|
"id": node.NsCluster.Id,
|
||||||
|
"name": node.NsCluster.Name,
|
||||||
|
},
|
||||||
|
"name": node.Name,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["logs"] = logs
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
19
internal/web/actions/default/ns/clusters/logs/init.go
Normal file
19
internal/web/actions/default/ns/clusters/logs/init.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNS)).
|
||||||
|
Data("teaMenu", "ns").
|
||||||
|
Data("teaSubMenu", "log").
|
||||||
|
Prefix("/ns/clusters/logs").
|
||||||
|
Get("", new(IndexAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
30
internal/web/actions/default/ns/clusters/options.go
Normal file
30
internal/web/actions/default/ns/clusters/options.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package clusters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OptionsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *OptionsAction) RunPost(params struct{}) {
|
||||||
|
clustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clusterMaps := []maps.Map{}
|
||||||
|
for _, cluster := range clustersResp.NsClusters {
|
||||||
|
clusterMaps = append(clusterMaps, maps.Map{
|
||||||
|
"id": cluster.Id,
|
||||||
|
"name": cluster.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["clusters"] = clusterMaps
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
62
internal/web/actions/default/ns/domains/create.go
Normal file
62
internal/web/actions/default/ns/domains/create.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateAction) Init() {
|
||||||
|
this.Nav("", "", "create")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateAction) RunGet(params struct{}) {
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreateAction) RunPost(params struct {
|
||||||
|
Name string
|
||||||
|
ClusterId int64
|
||||||
|
UserId int64
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
var domainId int64
|
||||||
|
defer func() {
|
||||||
|
this.CreateLogInfo("创建域名 %d", domainId)
|
||||||
|
}()
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入域名").
|
||||||
|
Expect(func() (message string, success bool) {
|
||||||
|
success = domainutils.ValidateDomainFormat(params.Name)
|
||||||
|
if !success {
|
||||||
|
message = "请输入正确的域名"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}).
|
||||||
|
Field("clusterId", params.ClusterId).
|
||||||
|
Gt(0, "请选择所属集群")
|
||||||
|
|
||||||
|
createResp, err := this.RPC().NSDomainRPC().CreateNSDomain(this.AdminContext(), &pb.CreateNSDomainRequest{
|
||||||
|
NsClusterId: params.ClusterId,
|
||||||
|
UserId: params.UserId,
|
||||||
|
Name: params.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domainId = createResp.NsDomainId
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
26
internal/web/actions/default/ns/domains/delete.go
Normal file
26
internal/web/actions/default/ns/domains/delete.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DeleteAction) RunPost(params struct {
|
||||||
|
DomainId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("删除域名 %d", params.DomainId)
|
||||||
|
|
||||||
|
_, err := this.RPC().NSDomainRPC().DeleteNSDomain(this.AdminContext(), &pb.DeleteNSDomainRequest{NsDomainId: params.DomainId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
61
internal/web/actions/default/ns/domains/domain.go
Normal file
61
internal/web/actions/default/ns/domains/domain.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DomainAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DomainAction) Init() {
|
||||||
|
this.Nav("", "", "index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DomainAction) RunGet(params struct {
|
||||||
|
DomainId int64
|
||||||
|
}) {
|
||||||
|
// 域名信息
|
||||||
|
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domain := domainResp.NsDomain
|
||||||
|
if domain == nil {
|
||||||
|
this.NotFound("nsDomain", params.DomainId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["domain"] = maps.Map{
|
||||||
|
"id": domain.Id,
|
||||||
|
"name": domain.Name,
|
||||||
|
"isOn": domain.IsOn,
|
||||||
|
"cluster": clusterMap,
|
||||||
|
"user": userMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package records
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunGet(params struct {
|
||||||
|
DomainId int64
|
||||||
|
}) {
|
||||||
|
// 域名信息
|
||||||
|
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domain := domainResp.NsDomain
|
||||||
|
if domain == nil {
|
||||||
|
this.NotFound("nsDomain", params.DomainId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["domain"] = maps.Map{
|
||||||
|
"id": domain.Id,
|
||||||
|
"name": domain.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类型
|
||||||
|
this.Data["types"] = dnsconfigs.FindAllRecordTypeDefinitions()
|
||||||
|
|
||||||
|
// TTL
|
||||||
|
this.Data["ttlValues"] = dnsconfigs.FindAllRecordTTL()
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *CreatePopupAction) RunPost(params struct {
|
||||||
|
DomainId int64
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Value string
|
||||||
|
Ttl int32
|
||||||
|
Description string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
var recordId int64
|
||||||
|
defer func() {
|
||||||
|
this.CreateLogInfo("创建域名记录 %d", recordId)
|
||||||
|
}()
|
||||||
|
|
||||||
|
createResp, err := this.RPC().NSRecordRPC().CreateNSRecord(this.AdminContext(), &pb.CreateNSRecordRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
Description: params.Description,
|
||||||
|
Name: params.Name,
|
||||||
|
Type: params.Type,
|
||||||
|
Value: params.Value,
|
||||||
|
Ttl: params.Ttl,
|
||||||
|
NsRouteIds: nil, // TODO 等待实现
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
recordId = createResp.NsRecordId
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
26
internal/web/actions/default/ns/domains/records/delete.go
Normal file
26
internal/web/actions/default/ns/domains/records/delete.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package records
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *DeleteAction) RunPost(params struct {
|
||||||
|
RecordId int64
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("删除域名记录 %d", params.RecordId)
|
||||||
|
|
||||||
|
_, err := this.RPC().NSRecordRPC().DeleteNSRecord(this.AdminContext(), &pb.DeleteNSRecordRequest{NsRecordId: params.RecordId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
96
internal/web/actions/default/ns/domains/records/index.go
Normal file
96
internal/web/actions/default/ns/domains/records/index.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package records
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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.Nav("", "", "record")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
DomainId int64
|
||||||
|
Type string
|
||||||
|
Keyword string
|
||||||
|
RouteId int64 // TODO
|
||||||
|
}) {
|
||||||
|
this.Data["type"] = params.Type
|
||||||
|
this.Data["keyword"] = params.Keyword
|
||||||
|
this.Data["routeId"] = params.RouteId
|
||||||
|
|
||||||
|
// 域名信息
|
||||||
|
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domain := domainResp.NsDomain
|
||||||
|
if domain == nil {
|
||||||
|
this.NotFound("nsDomain", params.DomainId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["domain"] = maps.Map{
|
||||||
|
"id": domain.Id,
|
||||||
|
"name": domain.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录
|
||||||
|
countResp, err := this.RPC().NSRecordRPC().CountAllEnabledNSRecords(this.AdminContext(), &pb.CountAllEnabledNSRecordsRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
Type: params.Type,
|
||||||
|
NsRouteId: params.RouteId,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count := countResp.Count
|
||||||
|
page := this.NewPage(count)
|
||||||
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
|
recordsResp, err := this.RPC().NSRecordRPC().ListEnabledNSRecords(this.AdminContext(), &pb.ListEnabledNSRecordsRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
Type: params.Type,
|
||||||
|
NsRouteId: params.RouteId,
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var recordMaps = []maps.Map{}
|
||||||
|
for _, record := range recordsResp.NsRecords {
|
||||||
|
routeMaps := []maps.Map{}
|
||||||
|
for _, route := range record.NsRoutes {
|
||||||
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
|
"id": route.Id,
|
||||||
|
"name": route.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
recordMaps = append(recordMaps, maps.Map{
|
||||||
|
"id": record.Id,
|
||||||
|
"name": record.Name,
|
||||||
|
"type": record.Type,
|
||||||
|
"value": record.Value,
|
||||||
|
"ttl": record.Ttl,
|
||||||
|
"weight": record.Weight,
|
||||||
|
"description": record.Description,
|
||||||
|
"routes": routeMaps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["records"] = recordMaps
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package records
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdatePopupAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdatePopupAction) Init() {
|
||||||
|
this.Nav("", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdatePopupAction) RunGet(params struct {
|
||||||
|
RecordId int64
|
||||||
|
}) {
|
||||||
|
recordResp, err := this.RPC().NSRecordRPC().FindEnabledNSRecord(this.AdminContext(), &pb.FindEnabledNSRecordRequest{NsRecordId: params.RecordId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
record := recordResp.NsRecord
|
||||||
|
if record == nil {
|
||||||
|
this.NotFound("nsRecord", params.RecordId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["record"] = maps.Map{
|
||||||
|
"id": record.Id,
|
||||||
|
"name": record.Name,
|
||||||
|
"type": record.Type,
|
||||||
|
"value": record.Value,
|
||||||
|
"ttl": record.Ttl,
|
||||||
|
"weight": record.Weight,
|
||||||
|
"description": record.Description,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 域名信息
|
||||||
|
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: record.NsDomain.Id})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domain := domainResp.NsDomain
|
||||||
|
if domain == nil {
|
||||||
|
this.NotFound("nsDomain", record.NsDomain.Id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.Data["domain"] = maps.Map{
|
||||||
|
"id": domain.Id,
|
||||||
|
"name": domain.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类型
|
||||||
|
this.Data["types"] = dnsconfigs.FindAllRecordTypeDefinitions()
|
||||||
|
|
||||||
|
// TTL
|
||||||
|
this.Data["ttlValues"] = dnsconfigs.FindAllRecordTTL()
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdatePopupAction) RunPost(params struct {
|
||||||
|
RecordId int64
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Value string
|
||||||
|
Ttl int32
|
||||||
|
Description string
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
this.CreateLogInfo("修改域名记录 %d", params.RecordId)
|
||||||
|
|
||||||
|
_, err := this.RPC().NSRecordRPC().UpdateNSRecord(this.AdminContext(), &pb.UpdateNSRecordRequest{
|
||||||
|
NsRecordId: params.RecordId,
|
||||||
|
Description: params.Description,
|
||||||
|
Name: params.Name,
|
||||||
|
Type: params.Type,
|
||||||
|
Value: params.Value,
|
||||||
|
Ttl: params.Ttl,
|
||||||
|
NsRouteIds: nil, // TODO 等待实现
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
96
internal/web/actions/default/ns/domains/update.go
Normal file
96
internal/web/actions/default/ns/domains/update.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) Init() {
|
||||||
|
this.Nav("", "", "update")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) RunGet(params struct {
|
||||||
|
DomainId int64
|
||||||
|
}) {
|
||||||
|
// 域名信息
|
||||||
|
domainResp, err := this.RPC().NSDomainRPC().FindEnabledNSDomain(this.AdminContext(), &pb.FindEnabledNSDomainRequest{NsDomainId: params.DomainId})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
domain := domainResp.NsDomain
|
||||||
|
if domain == nil {
|
||||||
|
this.NotFound("nsDomain", params.DomainId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var clusterId = int64(0)
|
||||||
|
if domain.NsCluster != nil {
|
||||||
|
clusterId = domain.NsCluster.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
var userId = int64(0)
|
||||||
|
if domain.User != nil {
|
||||||
|
userId = domain.User.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["domain"] = maps.Map{
|
||||||
|
"id": domain.Id,
|
||||||
|
"name": domain.Name,
|
||||||
|
"isOn": domain.IsOn,
|
||||||
|
"clusterId": clusterId,
|
||||||
|
"userId": userId,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *UpdateAction) RunPost(params struct {
|
||||||
|
DomainId int64
|
||||||
|
Name string
|
||||||
|
ClusterId int64
|
||||||
|
UserId int64
|
||||||
|
IsOn bool
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
this.CreateLogInfo("修改域名 %d", params.DomainId)
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("name", params.Name).
|
||||||
|
Require("请输入域名").
|
||||||
|
Expect(func() (message string, success bool) {
|
||||||
|
success = domainutils.ValidateDomainFormat(params.Name)
|
||||||
|
if !success {
|
||||||
|
message = "请输入正确的域名"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}).
|
||||||
|
Field("clusterId", params.ClusterId).
|
||||||
|
Gt(0, "请选择所属集群")
|
||||||
|
|
||||||
|
_, err := this.RPC().NSDomainRPC().UpdateNSDomain(this.AdminContext(), &pb.UpdateNSDomainRequest{
|
||||||
|
NsDomainId: params.DomainId,
|
||||||
|
NsClusterId: params.ClusterId,
|
||||||
|
UserId: params.UserId,
|
||||||
|
Name: params.Name,
|
||||||
|
IsOn: params.IsOn,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ package ns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexAction struct {
|
type IndexAction struct {
|
||||||
@@ -9,9 +11,80 @@ type IndexAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) Init() {
|
func (this *IndexAction) Init() {
|
||||||
|
this.FirstMenu("index")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct{}) {
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
|
UserId int64
|
||||||
|
Keyword string
|
||||||
|
}) {
|
||||||
|
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()
|
this.Show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package ns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/domains/records"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
)
|
)
|
||||||
@@ -14,6 +16,20 @@ func init() {
|
|||||||
Prefix("/ns").
|
Prefix("/ns").
|
||||||
Get("", new(IndexAction)).
|
Get("", new(IndexAction)).
|
||||||
|
|
||||||
|
// 域名相关
|
||||||
|
Prefix("/ns/domains").
|
||||||
|
GetPost("/create", new(domains.CreateAction)).
|
||||||
|
Post("/delete", new(domains.DeleteAction)).
|
||||||
|
Get("/domain", new(domains.DomainAction)).
|
||||||
|
GetPost("/update", new(domains.UpdateAction)).
|
||||||
|
|
||||||
|
// 记录相关
|
||||||
|
Prefix("/ns/domains/records").
|
||||||
|
Get("", new(records.IndexAction)).
|
||||||
|
GetPost("/createPopup", new(records.CreatePopupAction)).
|
||||||
|
GetPost("/updatePopup", new(records.UpdatePopupAction)).
|
||||||
|
Post("/delete", new(records.DeleteAction)).
|
||||||
|
|
||||||
EndAll()
|
EndAll()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
19
internal/web/actions/default/ns/users/init.go
Normal file
19
internal/web/actions/default/ns/users/init.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNS)).
|
||||||
|
Data("teaMenu", "ns").
|
||||||
|
Data("teaSubMenu", "domain").
|
||||||
|
Prefix("/ns/users").
|
||||||
|
Post("/options", new(OptionsAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
34
internal/web/actions/default/ns/users/options.go
Normal file
34
internal/web/actions/default/ns/users/options.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OptionsAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *OptionsAction) RunPost(params struct{}) {
|
||||||
|
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{
|
||||||
|
Offset: 0,
|
||||||
|
Size: 10000, // TODO 改进 <ns-user-selector> 组件
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userMaps := []maps.Map{}
|
||||||
|
for _, user := range usersResp.Users {
|
||||||
|
userMaps = append(userMaps, maps.Map{
|
||||||
|
"id": user.Id,
|
||||||
|
"fullname": user.Fullname,
|
||||||
|
"username": user.Username,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.Data["users"] = userMaps
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -27,7 +27,11 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
page := this.NewPage(count)
|
page := this.NewPage(count)
|
||||||
this.Data["page"] = page.AsHTML()
|
this.Data["page"] = page.AsHTML()
|
||||||
|
|
||||||
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{Keyword: params.Keyword})
|
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{
|
||||||
|
Keyword: params.Keyword,
|
||||||
|
Offset: page.Offset,
|
||||||
|
Size: page.Size,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
{
|
{
|
||||||
"code": "ns",
|
"code": "ns",
|
||||||
"module": configloaders.AdminModuleCodeNS,
|
"module": configloaders.AdminModuleCodeNS,
|
||||||
"name": "域名服务器",
|
"name": "域名服务",
|
||||||
"subtitle": "域名列表",
|
"subtitle": "域名列表",
|
||||||
"icon": "cubes",
|
"icon": "cubes",
|
||||||
"isOn": teaconst.IsPlus,
|
"isOn": teaconst.IsPlus,
|
||||||
@@ -232,7 +232,7 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "节点日志",
|
"name": "节点日志",
|
||||||
"url": "/ns/logs",
|
"url": "/ns/clusters/logs",
|
||||||
"code": "log",
|
"code": "log",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster/settings"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/cluster/settings"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/logs"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/users"
|
||||||
|
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/certs"
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ Vue.component("not-found-box", {
|
|||||||
props: ["message"],
|
props: ["message"],
|
||||||
template: `<div style="text-align: center; margin-top: 5em;">
|
template: `<div style="text-align: center; margin-top: 5em;">
|
||||||
<div style="font-size: 2em; margin-bottom: 1em"><i class="icon exclamation triangle large grey"></i></div>
|
<div style="font-size: 2em; margin-bottom: 1em"><i class="icon exclamation triangle large grey"></i></div>
|
||||||
<p class="comment">{{message}}</p>
|
<p class="comment">{{message}}<slot></slot></p>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
28
web/public/js/components/ns/ns-cluster-selector.js
Normal file
28
web/public/js/components/ns/ns-cluster-selector.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
Vue.component("ns-cluster-selector", {
|
||||||
|
mounted: function () {
|
||||||
|
let that = this
|
||||||
|
|
||||||
|
Tea.action("/ns/clusters/options")
|
||||||
|
.post()
|
||||||
|
.success(function (resp) {
|
||||||
|
that.clusters = resp.data.clusters
|
||||||
|
})
|
||||||
|
},
|
||||||
|
props: ["v-cluster-id"],
|
||||||
|
data: function () {
|
||||||
|
let clusterId = this.vClusterId
|
||||||
|
if (clusterId == null) {
|
||||||
|
clusterId = 0
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
clusters: [],
|
||||||
|
clusterId: clusterId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<select class="ui dropdown auto-width" name="clusterId" v-model="clusterId">
|
||||||
|
<option value="0">[选择集群]</option>
|
||||||
|
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||||
|
</select>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
28
web/public/js/components/ns/ns-user-selector.js
Normal file
28
web/public/js/components/ns/ns-user-selector.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
Vue.component("ns-user-selector", {
|
||||||
|
mounted: function () {
|
||||||
|
let that = this
|
||||||
|
|
||||||
|
Tea.action("/ns/users/options")
|
||||||
|
.post()
|
||||||
|
.success(function (resp) {
|
||||||
|
that.users = resp.data.users
|
||||||
|
})
|
||||||
|
},
|
||||||
|
props: ["v-user-id"],
|
||||||
|
data: function () {
|
||||||
|
let userId = this.vUserId
|
||||||
|
if (userId == null) {
|
||||||
|
userId = 0
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
users: [],
|
||||||
|
userId: userId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
||||||
|
<option value="0">[选择用户]</option>
|
||||||
|
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
||||||
|
</select>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
5
web/views/@default/ns/@menu.html
Normal file
5
web/views/@default/ns/@menu.html
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<first-menu>
|
||||||
|
<menu-item href="/ns" code="index">域名列表</menu-item>
|
||||||
|
<menu-item href="/ns/domains/create" code="create">添加域名</menu-item>
|
||||||
|
</first-menu>
|
||||||
|
<div class="margin"></div>
|
||||||
5
web/views/@default/ns/clusters/logs/index.css
Normal file
5
web/views/@default/ns/clusters/logs/index.css
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pre.log-box {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=index.css.map */
|
||||||
1
web/views/@default/ns/clusters/logs/index.css.map
Normal file
1
web/views/@default/ns/clusters/logs/index.css.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,GAAG;EACF,SAAA;EACA,UAAA","file":"index.css"}
|
||||||
62
web/views/@default/ns/clusters/logs/index.html
Normal file
62
web/views/@default/ns/clusters/logs/index.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{$layout}
|
||||||
|
|
||||||
|
{$var "header"}
|
||||||
|
<!-- datepicker -->
|
||||||
|
<script type="text/javascript" src="/js/moment.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/js/pikaday.js"></script>
|
||||||
|
<link rel="stylesheet" href="/js/pikaday.css"/>
|
||||||
|
<link rel="stylesheet" href="/js/pikaday.theme.css"/>
|
||||||
|
<link rel="stylesheet" href="/js/pikaday.triangle.css"/>
|
||||||
|
{$end}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="margin"></div>
|
||||||
|
|
||||||
|
<form method="get" action="/ns/clusters/logs" class="ui form" autocomplete="off">
|
||||||
|
<div class="ui fields inline">
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" name="dayFrom" placeholder="开始日期" v-model="dayFrom" value="" style="width:8em" id="day-from-picker"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" name="dayTo" placeholder="结束日期" v-model="dayTo" value="" style="width:8em" id="day-to-picker"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<select class="ui dropdown" name="level" v-model="level">
|
||||||
|
<option value="">[级别]</option>
|
||||||
|
<option value="error">错误</option>
|
||||||
|
<option value="warning">警告</option>
|
||||||
|
<option value="info">信息</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<input type="text" name="keyword" style="width:10em" v-model="keyword" placeholder="关键词"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui field">
|
||||||
|
<button type="submit" class="ui button">查询</button>
|
||||||
|
</div>
|
||||||
|
<div class="ui field" v-if="dayFrom.length > 0 || dayTo.length > 0 || keyword.length > 0 || level.length > 0">
|
||||||
|
<a href="/ns/clusters/logs">[清除条件]</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="comment" v-if="logs.length == 0">暂时还没有日志。</p>
|
||||||
|
|
||||||
|
<table class="ui table selectable celled" v-if="logs.length > 0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>集群</th>
|
||||||
|
<th>节点</th>
|
||||||
|
<th>信息</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="log in logs">
|
||||||
|
<td nowrap=""><link-icon :href="'/ns/clusters/cluster?clusterId=' + log.node.cluster.id">{{log.node.cluster.name}}</link-icon></td>
|
||||||
|
<td nowrap=""><link-icon :href="'/ns/clusters/cluster/node?clusterId=' + log.node.cluster.id + '&nodeId=' + log.node.id">{{log.node.name}}</link-icon></td>
|
||||||
|
<td>
|
||||||
|
<pre class="log-box"><span :class="{red:log.level == 'error', orange:log.level == 'warning'}"><span v-if="!log.isToday">[{{log.createdTime}}]</span><strong v-if="log.isToday">[{{log.createdTime}}]</strong>[{{log.tag}}]{{log.description}}</span> <span v-if="log.count > 0" class="ui label tiny" :class="{red:log.level == 'error', orange:log.level == 'warning'}">共{{log.count}}条</span></pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="page" v-html="page"></div>
|
||||||
6
web/views/@default/ns/clusters/logs/index.js
Normal file
6
web/views/@default/ns/clusters/logs/index.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.$delay(function () {
|
||||||
|
teaweb.datepicker("day-from-picker")
|
||||||
|
teaweb.datepicker("day-to-picker")
|
||||||
|
})
|
||||||
|
})
|
||||||
4
web/views/@default/ns/clusters/logs/index.less
Normal file
4
web/views/@default/ns/clusters/logs/index.less
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pre.log-box {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
7
web/views/@default/ns/domains/@domain_menu.html
Normal file
7
web/views/@default/ns/domains/@domain_menu.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<first-menu>
|
||||||
|
<menu-item href="/ns">所有域名</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">记录</menu-item>
|
||||||
|
<menu-item :href="'/ns/domains/update?domainId=' + domain.id" code="update">修改</menu-item>
|
||||||
|
</first-menu>
|
||||||
27
web/views/@default/ns/domains/create.html
Normal file
27
web/views/@default/ns/domains/create.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "../menu"}
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td>域名 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="name" maxlength="255" ref="focus"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="title">所属集群 *</td>
|
||||||
|
<td>
|
||||||
|
<ns-cluster-selector></ns-cluster-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>所属用户</td>
|
||||||
|
<td>
|
||||||
|
<ns-user-selector></ns-user-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
3
web/views/@default/ns/domains/create.js
Normal file
3
web/views/@default/ns/domains/create.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifySuccess("保存成功", "/ns")
|
||||||
|
})
|
||||||
30
web/views/@default/ns/domains/domain.html
Normal file
30
web/views/@default/ns/domains/domain.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "domain_menu"}
|
||||||
|
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">域名</td>
|
||||||
|
<td>{{domain.name}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>状态</td>
|
||||||
|
<td>
|
||||||
|
<label-on :v-is-on="domain.isOn"></label-on>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>所属集群</td>
|
||||||
|
<td>
|
||||||
|
{{domain.cluster.name}}<link-icon :href="'/ns/clusters/cluster?clusterId=' + domain.cluster.id"></link-icon>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>所属用户</td>
|
||||||
|
<td>
|
||||||
|
<span v-if="domain.user != null">
|
||||||
|
{{domain.user.fullname}} ({{domain.user.username}})
|
||||||
|
</span>
|
||||||
|
<span v-else class="disabled">-</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
48
web/views/@default/ns/domains/records/createPopup.html
Normal file
48
web/views/@default/ns/domains/records/createPopup.html
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>创建记录</h3>
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<input type="hidden" name="domainId" :value="domain.id"/>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">记录名</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" name="name" ref="focus"/>
|
||||||
|
<span class="ui label">.{{domain.name}}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>记录类型</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="type" v-model="type" @change="changeType">
|
||||||
|
<option v-for="t in types" :value="t.type">{{t.type}}</option>
|
||||||
|
</select>
|
||||||
|
<p class="comment">{{typeDescription}}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>记录值</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="value" maxlength="1024"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>TTL</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="ttl">
|
||||||
|
<option v-for="v in ttlValues" :value="v.value">{{v.name}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>备注</td>
|
||||||
|
<td>
|
||||||
|
<textarea rows="2" name="description"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
15
web/views/@default/ns/domains/records/createPopup.js
Normal file
15
web/views/@default/ns/domains/records/createPopup.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.type = "A"
|
||||||
|
this.typeDescription = ""
|
||||||
|
|
||||||
|
this.changeType = function () {
|
||||||
|
let that = this
|
||||||
|
this.types.forEach(function (v) {
|
||||||
|
if (v.type == that.type) {
|
||||||
|
that.typeDescription = v.description
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeType()
|
||||||
|
})
|
||||||
37
web/views/@default/ns/domains/records/index.html
Normal file
37
web/views/@default/ns/domains/records/index.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "../domain_menu"}
|
||||||
|
|
||||||
|
<second-menu>
|
||||||
|
<menu-item @click.prevent="createRecord">[创建记录]</menu-item>
|
||||||
|
</second-menu>
|
||||||
|
|
||||||
|
<p class="comment" v-if="records.length == 0">暂时还没有记录。</p>
|
||||||
|
<table class="ui table selectable celled" v-if="records.length > 0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>记录名</th>
|
||||||
|
<th>记录类型</th>
|
||||||
|
<th>记录值</th>
|
||||||
|
<th>TTL</th>
|
||||||
|
<th>线路</th>
|
||||||
|
<th>备注</th>
|
||||||
|
<th class="two op">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="record in records">
|
||||||
|
<td>{{record.name}}</td>
|
||||||
|
<td>{{record.type}}</td>
|
||||||
|
<td>{{record.value}}</td>
|
||||||
|
<td>{{formatTTL(record.ttl)}}</td>
|
||||||
|
<td>
|
||||||
|
<span class="ui label basic text tiny" v-for="route in record.routes">{{route.name}}</span>
|
||||||
|
</td>
|
||||||
|
<td>{{record.description}}</td>
|
||||||
|
<td>
|
||||||
|
<a href="" @click.prevent="updateRecord(record.id)">修改</a>
|
||||||
|
<a href="" @click.prevent="deleteRecord(record.id)">删除</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="page" v-html="page"></div>
|
||||||
50
web/views/@default/ns/domains/records/index.js
Normal file
50
web/views/@default/ns/domains/records/index.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.createRecord = function () {
|
||||||
|
teaweb.popup("/ns/domains/records/createPopup?domainId=" + this.domain.id, {
|
||||||
|
callback: function () {
|
||||||
|
teaweb.success("保存成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateRecord = function (recordId) {
|
||||||
|
teaweb.popup("/ns/domains/records/updatePopup?recordId=" + recordId, {
|
||||||
|
callback: function () {
|
||||||
|
teaweb.success("保存成功", function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.deleteRecord = function (recordId) {
|
||||||
|
let that = this
|
||||||
|
teaweb.confirm("确定要删除此记录吗?", function () {
|
||||||
|
that.$post(".delete")
|
||||||
|
.params({
|
||||||
|
recordId: recordId
|
||||||
|
})
|
||||||
|
.success(function () {
|
||||||
|
teaweb.reload()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.formatTTL = function (ttl) {
|
||||||
|
if (ttl % 86400 == 0) {
|
||||||
|
let days = ttl / 86400
|
||||||
|
return days + "天"
|
||||||
|
}
|
||||||
|
if (ttl % 3600 == 0) {
|
||||||
|
let hours = ttl / 3600
|
||||||
|
return hours + "小时"
|
||||||
|
}
|
||||||
|
if (ttl % 60 == 0) {
|
||||||
|
let minutes = ttl / 60
|
||||||
|
return minutes + "分钟"
|
||||||
|
}
|
||||||
|
return ttl + "秒"
|
||||||
|
}
|
||||||
|
})
|
||||||
48
web/views/@default/ns/domains/records/updatePopup.html
Normal file
48
web/views/@default/ns/domains/records/updatePopup.html
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{$layout "layout_popup"}
|
||||||
|
|
||||||
|
<h3>创建记录</h3>
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<input type="hidden" name="recordId" :value="record.id"/>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td class="title">记录名</td>
|
||||||
|
<td>
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" name="name" ref="focus" v-model="record.name"/>
|
||||||
|
<span class="ui label">.{{domain.name}}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>记录类型</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="type" v-model="type" @change="changeType">
|
||||||
|
<option v-for="t in types" :value="t.type">{{t.type}}</option>
|
||||||
|
</select>
|
||||||
|
<p class="comment">{{typeDescription}}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>记录值</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="value" maxlength="1024" v-model="record.value"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>TTL</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" name="ttl" v-model="record.ttl">
|
||||||
|
<option v-for="v in ttlValues" :value="v.value">{{v.name}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>备注</td>
|
||||||
|
<td>
|
||||||
|
<textarea rows="2" name="description" v-model="record.description"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
15
web/views/@default/ns/domains/records/updatePopup.js
Normal file
15
web/views/@default/ns/domains/records/updatePopup.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.type = this.record.type
|
||||||
|
this.typeDescription = ""
|
||||||
|
|
||||||
|
this.changeType = function () {
|
||||||
|
let that = this
|
||||||
|
this.types.forEach(function (v) {
|
||||||
|
if (v.type == that.type) {
|
||||||
|
that.typeDescription = v.description
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeType()
|
||||||
|
})
|
||||||
39
web/views/@default/ns/domains/update.html
Normal file
39
web/views/@default/ns/domains/update.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{$layout}
|
||||||
|
{$template "domain_menu"}
|
||||||
|
|
||||||
|
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||||
|
<csrf-token></csrf-token>
|
||||||
|
<input type="hidden" name="domainId" :value="domain.id"/>
|
||||||
|
<table class="ui table definition selectable">
|
||||||
|
<tr>
|
||||||
|
<td>域名 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="name" maxlength="255" ref="focus" v-model="domain.name"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="title">所属集群 *</td>
|
||||||
|
<td>
|
||||||
|
<ns-cluster-selector :v-cluster-id="domain.clusterId"></ns-cluster-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>所属用户</td>
|
||||||
|
<td>
|
||||||
|
<ns-user-selector :v-user-id="domain.userId"></ns-user-selector>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
|
</tr>
|
||||||
|
<tbody v-show="moreOptionsVisible">
|
||||||
|
<tr>
|
||||||
|
<td>是否启用</td>
|
||||||
|
<td>
|
||||||
|
<checkbox name="isOn" value="1" v-model="domain.isOn"></checkbox>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<submit-btn></submit-btn>
|
||||||
|
</form>
|
||||||
3
web/views/@default/ns/domains/update.js
Normal file
3
web/views/@default/ns/domains/update.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tea.context(function () {
|
||||||
|
this.success = NotifySuccess("保存成功", "/ns/domains/domain?domainId=" + this.domain.id)
|
||||||
|
})
|
||||||
@@ -1 +1,61 @@
|
|||||||
{$layout}
|
{$layout}
|
||||||
|
{$template "menu"}
|
||||||
|
|
||||||
|
<div v-if="countClusters == 0">
|
||||||
|
<not-found-box>
|
||||||
|
暂时还没有集群,请先 <a href="/ns/clusters">创建集群</a>。
|
||||||
|
</not-found-box>
|
||||||
|
</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 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>{{domain.name}}</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/index.js
Normal file
14
web/views/@default/ns/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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
<first-menu>
|
<first-menu>
|
||||||
<menu-item><more-options-indicator>选择省份/自治区</more-options-indicator></menu-item>
|
<menu-item><more-options-indicator>选择省份/自治区</more-options-indicator></menu-item>
|
||||||
<div class="item right" v-if="moreOptionsVisible">
|
<div class="item right" v-show="moreOptionsVisible">
|
||||||
<div class="ui checkbox" @click.prevent="checkAll">
|
<div class="ui checkbox" @click.prevent="checkAll">
|
||||||
<input type="checkbox" v-model="isCheckingAll"/>
|
<input type="checkbox" v-model="isCheckingAll"/>
|
||||||
<label>全选</label>
|
<label>全选</label>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tbody v-if="moreOptionsVisible">
|
<tbody v-show="moreOptionsVisible">
|
||||||
<tr>
|
<tr>
|
||||||
<td>子条件之间关系</td>
|
<td>子条件之间关系</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<first-menu>
|
<first-menu>
|
||||||
<menu-item><more-options-indicator>选择省份/自治区</more-options-indicator></menu-item>
|
<menu-item><more-options-indicator>选择省份/自治区</more-options-indicator></menu-item>
|
||||||
<div class="item right" v-if="moreOptionsVisible">
|
<div class="item right" v-show="moreOptionsVisible">
|
||||||
<div class="ui checkbox" @click.prevent="checkAll">
|
<div class="ui checkbox" @click.prevent="checkAll">
|
||||||
<input type="checkbox" v-model="isCheckingAll"/>
|
<input type="checkbox" v-model="isCheckingAll"/>
|
||||||
<label>全选</label>
|
<label>全选</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user