Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab3b32fda1 | ||
|
|
cafab78ab4 | ||
|
|
2d497dee7d | ||
|
|
280ecd9aea | ||
|
|
3a980a3bc0 | ||
|
|
556a5bdd4e | ||
|
|
eca26a345f | ||
|
|
eacff7232d | ||
|
|
3c071db207 | ||
|
|
6609c56063 | ||
|
|
f7ae3de914 | ||
|
|
d82bc4e77e | ||
|
|
31e1df0afd | ||
|
|
700e9236f9 | ||
|
|
ee1e62aff0 | ||
|
|
aa0c38d66f | ||
|
|
4e4d9e33f0 | ||
|
|
f78daa98bc | ||
|
|
dad8802fb0 | ||
|
|
529b7041e7 | ||
|
|
5de1eecf92 | ||
|
|
08ee301f89 | ||
|
|
4154904b21 | ||
|
|
79282809e3 | ||
|
|
108c2533c2 | ||
|
|
fd7309cd17 | ||
|
|
c5f871edf6 | ||
|
|
3f2d2b238d | ||
|
|
e6a30b99d3 | ||
|
|
08ce2b7799 | ||
|
|
dbe7336f32 |
@@ -22,6 +22,7 @@ const (
|
|||||||
AdminModuleCodePlan AdminModuleCode = "plan" // 套餐
|
AdminModuleCodePlan AdminModuleCode = "plan" // 套餐
|
||||||
AdminModuleCodeLog AdminModuleCode = "log" // 日志
|
AdminModuleCodeLog AdminModuleCode = "log" // 日志
|
||||||
AdminModuleCodeSetting AdminModuleCode = "setting" // 设置
|
AdminModuleCodeSetting AdminModuleCode = "setting" // 设置
|
||||||
|
AdminModuleCodeTicket AdminModuleCode = "ticket" // 工单
|
||||||
AdminModuleCodeCommon AdminModuleCode = "common" // 只要登录就可以访问的模块
|
AdminModuleCodeCommon AdminModuleCode = "common" // 只要登录就可以访问的模块
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ func UpdateAdminTheme(adminId int64, theme string) {
|
|||||||
|
|
||||||
// AllModuleMaps 所有权限列表
|
// AllModuleMaps 所有权限列表
|
||||||
func AllModuleMaps() []maps.Map {
|
func AllModuleMaps() []maps.Map {
|
||||||
m := []maps.Map{
|
var m = []maps.Map{
|
||||||
{
|
{
|
||||||
"name": "看板",
|
"name": "看板",
|
||||||
"code": AdminModuleCodeDashboard,
|
"code": AdminModuleCodeDashboard,
|
||||||
@@ -204,11 +205,24 @@ func AllModuleMaps() []maps.Map {
|
|||||||
"code": AdminModuleCodeFinance,
|
"code": AdminModuleCodeFinance,
|
||||||
"url": "/finance",
|
"url": "/finance",
|
||||||
},
|
},
|
||||||
{
|
}...)
|
||||||
"name": "套餐管理",
|
|
||||||
"code": AdminModuleCodePlan,
|
if teaconst.IsPlus {
|
||||||
"url": "/plans",
|
m = append(m, []maps.Map{
|
||||||
},
|
{
|
||||||
|
"name": "套餐管理",
|
||||||
|
"code": AdminModuleCodePlan,
|
||||||
|
"url": "/plans",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "工单系统",
|
||||||
|
"code": AdminModuleCodeTicket,
|
||||||
|
"url": "/tickets",
|
||||||
|
},
|
||||||
|
}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
m = append(m, []maps.Map{
|
||||||
{
|
{
|
||||||
"name": "日志审计",
|
"name": "日志审计",
|
||||||
"code": AdminModuleCodeLog,
|
"code": AdminModuleCodeLog,
|
||||||
|
|||||||
@@ -26,6 +26,15 @@ func LoadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
|
|||||||
return &v, nil
|
return &v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReloadAdminUIConfig() error {
|
||||||
|
locker.Lock()
|
||||||
|
defer locker.Unlock()
|
||||||
|
|
||||||
|
sharedAdminUIConfig = nil
|
||||||
|
_, err := loadAdminUIConfig()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
|
func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
|
||||||
locker.Lock()
|
locker.Lock()
|
||||||
defer locker.Unlock()
|
defer locker.Unlock()
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
@@ -34,7 +33,7 @@ func LoadAPIConfig() (*APIConfig, error) {
|
|||||||
var data []byte
|
var data []byte
|
||||||
var err error
|
var err error
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
data, err = ioutil.ReadFile(path)
|
data, err = os.ReadFile(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if path == localFile {
|
if path == localFile {
|
||||||
isFromLocal = true
|
isFromLocal = true
|
||||||
@@ -54,7 +53,7 @@ func LoadAPIConfig() (*APIConfig, error) {
|
|||||||
|
|
||||||
if !isFromLocal {
|
if !isFromLocal {
|
||||||
// 恢复文件
|
// 恢复文件
|
||||||
_ = ioutil.WriteFile(localFile, data, 0666)
|
_ = os.WriteFile(localFile, data, 0666)
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
@@ -110,41 +109,48 @@ func (this *APIConfig) WriteFile(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(path, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// 写入 ~/ 和 /etc/ 目录,因为是备份需要,所以不需要提示错误信息
|
// 写入 ~/ 和 /etc/ 目录,因为是备份需要,所以不需要提示错误信息
|
||||||
// 写入 ~/.edge-admin/
|
// 写入 ~/.edge-admin/
|
||||||
filename := filepath.Base(path)
|
// 这个用来判断用户是否为重装,所以比较重要
|
||||||
|
var filename = filepath.Base(path)
|
||||||
homeDir, homeErr := os.UserHomeDir()
|
homeDir, homeErr := os.UserHomeDir()
|
||||||
if homeErr == nil {
|
if homeErr == nil {
|
||||||
dir := homeDir + "/." + teaconst.ProcessName
|
dir := homeDir + "/." + teaconst.ProcessName
|
||||||
stat, err := os.Stat(dir)
|
stat, err := os.Stat(dir)
|
||||||
if err == nil && stat.IsDir() {
|
if err == nil && stat.IsDir() {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
err = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else if err != nil && os.IsNotExist(err) {
|
} else if err != nil && os.IsNotExist(err) {
|
||||||
err = os.Mkdir(dir, 0777)
|
err = os.Mkdir(dir, 0777)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
err = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入 /etc/edge-admin
|
// 写入 /etc/edge-admin
|
||||||
{
|
{
|
||||||
dir := "/etc/" + teaconst.ProcessName
|
var dir = "/etc/" + teaconst.ProcessName
|
||||||
stat, err := os.Stat(dir)
|
stat, err := os.Stat(dir)
|
||||||
if err == nil && stat.IsDir() {
|
if err == nil && stat.IsDir() {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
_ = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
} else if err != nil && os.IsNotExist(err) {
|
} else if err != nil && os.IsNotExist(err) {
|
||||||
err = os.Mkdir(dir, 0777)
|
err = os.Mkdir(dir, 0777)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = ioutil.WriteFile(dir+"/"+filename, data, 0666)
|
_ = os.WriteFile(dir+"/"+filename, data, 0666)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(path, data, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package configs
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"io/ioutil"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var plusConfigFile = "plus.cache.json"
|
var plusConfigFile = "plus.cache.json"
|
||||||
@@ -17,7 +17,7 @@ type PlusConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ReadPlusConfig() *PlusConfig {
|
func ReadPlusConfig() *PlusConfig {
|
||||||
data, err := ioutil.ReadFile(Tea.ConfigFile(plusConfigFile))
|
data, err := os.ReadFile(Tea.ConfigFile(plusConfigFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &PlusConfig{IsPlus: false}
|
return &PlusConfig{IsPlus: false}
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ func WritePlusConfig(config *PlusConfig) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(Tea.ConfigFile(plusConfigFile), configJSON, 0777)
|
err = os.WriteFile(Tea.ConfigFile(plusConfigFile), configJSON, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
// +build !plus
|
//go:build !plus
|
||||||
|
|
||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.4.10"
|
Version = "0.5.0"
|
||||||
|
|
||||||
APINodeVersion = "0.4.10"
|
APINodeVersion = "0.5.0"
|
||||||
|
|
||||||
ProductName = "Edge Admin"
|
ProductName = "Edge Admin"
|
||||||
ProcessName = "edge-admin"
|
ProcessName = "edge-admin"
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package teaconst
|
package teaconst
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
"github.com/iwind/gosock/pkg/gosock"
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@@ -173,9 +172,9 @@ func (this *AdminNode) checkServer() error {
|
|||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// 创建文件
|
// 创建文件
|
||||||
templateFile := Tea.ConfigFile("server.template.yaml")
|
templateFile := Tea.ConfigFile("server.template.yaml")
|
||||||
data, err := ioutil.ReadFile(templateFile)
|
data, err := os.ReadFile(templateFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(configFile, data, 0666)
|
err = os.WriteFile(configFile, data, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create config file failed: " + err.Error())
|
return errors.New("create config file failed: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -195,7 +194,7 @@ https:
|
|||||||
cert: ""
|
cert: ""
|
||||||
key: ""
|
key: ""
|
||||||
`
|
`
|
||||||
err = ioutil.WriteFile(configFile, []byte(templateYAML), 0666)
|
err = os.WriteFile(configFile, []byte(templateYAML), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("create config file failed: " + err.Error())
|
return errors.New("create config file failed: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -210,7 +209,7 @@ https:
|
|||||||
// 添加端口到防火墙
|
// 添加端口到防火墙
|
||||||
func (this *AdminNode) addPortsToFirewall() {
|
func (this *AdminNode) addPortsToFirewall() {
|
||||||
var configFile = Tea.ConfigFile("server.yaml")
|
var configFile = Tea.ConfigFile("server.yaml")
|
||||||
data, err := ioutil.ReadFile(configFile)
|
data, err := os.ReadFile(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -263,9 +262,9 @@ func (this *AdminNode) startAPINode() {
|
|||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
_, err = os.Stat(path)
|
_, err = os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(configPath, data, 0666)
|
err = os.WriteFile(configPath, data, 0666)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logs.Println("[NODE]recover 'edge-api/configs/api.yaml' from '" + path + "'")
|
logs.Println("[NODE]recover 'edge-api/configs/api.yaml' from '" + path + "'")
|
||||||
canStart = true
|
canStart = true
|
||||||
@@ -289,9 +288,9 @@ func (this *AdminNode) startAPINode() {
|
|||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
_, err = os.Stat(path)
|
_, err = os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = ioutil.WriteFile(dbPath, data, 0666)
|
err = os.WriteFile(dbPath, data, 0666)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
logs.Println("[NODE]recover 'edge-api/configs/db.yaml' from '" + path + "'")
|
logs.Println("[NODE]recover 'edge-api/configs/db.yaml' from '" + path + "'")
|
||||||
break
|
break
|
||||||
@@ -316,12 +315,12 @@ func (this *AdminNode) startAPINode() {
|
|||||||
// 生成Secret
|
// 生成Secret
|
||||||
func (this *AdminNode) genSecret() string {
|
func (this *AdminNode) genSecret() string {
|
||||||
tmpFile := os.TempDir() + "/edge-admin-secret.tmp"
|
tmpFile := os.TempDir() + "/edge-admin-secret.tmp"
|
||||||
data, err := ioutil.ReadFile(tmpFile)
|
data, err := os.ReadFile(tmpFile)
|
||||||
if err == nil && len(data) == 32 {
|
if err == nil && len(data) == 32 {
|
||||||
return string(data)
|
return string(data)
|
||||||
}
|
}
|
||||||
secret := rands.String(32)
|
secret := rands.String(32)
|
||||||
_ = ioutil.WriteFile(tmpFile, []byte(secret), 0666)
|
_ = os.WriteFile(tmpFile, []byte(secret), 0666)
|
||||||
return secret
|
return secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -316,22 +316,14 @@ func (this *RPCClient) IPLibraryRPC() pb.IPLibraryServiceClient {
|
|||||||
return pb.NewIPLibraryServiceClient(this.pickConn())
|
return pb.NewIPLibraryServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) IPLibraryFileRPC() pb.IPLibraryFileServiceClient {
|
||||||
|
return pb.NewIPLibraryFileServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) IPListRPC() pb.IPListServiceClient {
|
func (this *RPCClient) IPListRPC() pb.IPListServiceClient {
|
||||||
return pb.NewIPListServiceClient(this.pickConn())
|
return pb.NewIPListServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCClient) ReportNodeRPC() pb.ReportNodeServiceClient {
|
|
||||||
return pb.NewReportNodeServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) ReportNodeGroupRPC() pb.ReportNodeGroupServiceClient {
|
|
||||||
return pb.NewReportNodeGroupServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) ReportResultRPC() pb.ReportResultServiceClient {
|
|
||||||
return pb.NewReportResultServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) IPItemRPC() pb.IPItemServiceClient {
|
func (this *RPCClient) IPItemRPC() pb.IPItemServiceClient {
|
||||||
return pb.NewIPItemServiceClient(this.pickConn())
|
return pb.NewIPItemServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -356,6 +348,10 @@ func (this *RPCClient) RegionCityRPC() pb.RegionCityServiceClient {
|
|||||||
return pb.NewRegionCityServiceClient(this.pickConn())
|
return pb.NewRegionCityServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *RPCClient) RegionTownRPC() pb.RegionTownServiceClient {
|
||||||
|
return pb.NewRegionTownServiceClient(this.pickConn())
|
||||||
|
}
|
||||||
|
|
||||||
func (this *RPCClient) RegionProviderRPC() pb.RegionProviderServiceClient {
|
func (this *RPCClient) RegionProviderRPC() pb.RegionProviderServiceClient {
|
||||||
return pb.NewRegionProviderServiceClient(this.pickConn())
|
return pb.NewRegionProviderServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
@@ -448,42 +444,6 @@ func (this *RPCClient) LatestItemRPC() pb.LatestItemServiceClient {
|
|||||||
return pb.NewLatestItemServiceClient(this.pickConn())
|
return pb.NewLatestItemServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *RPCClient) NSClusterRPC() pb.NSClusterServiceClient {
|
|
||||||
return pb.NewNSClusterServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSNodeRPC() pb.NSNodeServiceClient {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSKeyRPC() pb.NSKeyServiceClient {
|
|
||||||
return pb.NewNSKeyServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSRouteRPC() pb.NSRouteServiceClient {
|
|
||||||
return pb.NewNSRouteServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSAccessLogRPC() pb.NSAccessLogServiceClient {
|
|
||||||
return pb.NewNSAccessLogServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSRPC() pb.NSServiceClient {
|
|
||||||
return pb.NewNSServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) NSQuestionOptionRPC() pb.NSQuestionOptionServiceClient {
|
|
||||||
return pb.NewNSQuestionOptionServiceClient(this.pickConn())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
|
||||||
return pb.NewMetricItemServiceClient(this.pickConn())
|
return pb.NewMetricItemServiceClient(this.pickConn())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -95,7 +95,7 @@ func (this *CheckUpdatesTask) Loop() error {
|
|||||||
defer func() {
|
defer func() {
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
data, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("read api failed: " + err.Error())
|
return errors.New("read api failed: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package nodelogutils
|
package nodelogutils
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build linux
|
//go:build linux
|
||||||
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/files"
|
"github.com/iwind/TeaGo/files"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -16,7 +15,7 @@ import (
|
|||||||
var systemdServiceFile = "/etc/systemd/system/edge-admin.service"
|
var systemdServiceFile = "/etc/systemd/system/edge-admin.service"
|
||||||
var initServiceFile = "/etc/init.d/" + teaconst.SystemdServiceName
|
var initServiceFile = "/etc/init.d/" + teaconst.SystemdServiceName
|
||||||
|
|
||||||
// 安装服务
|
// Install 安装服务
|
||||||
func (this *ServiceManager) Install(exePath string, args []string) error {
|
func (this *ServiceManager) Install(exePath string, args []string) error {
|
||||||
if os.Getgid() != 0 {
|
if os.Getgid() != 0 {
|
||||||
return errors.New("only root users can install the service")
|
return errors.New("only root users can install the service")
|
||||||
@@ -30,7 +29,7 @@ func (this *ServiceManager) Install(exePath string, args []string) error {
|
|||||||
return this.installSystemdService(systemd, exePath, args)
|
return this.installSystemdService(systemd, exePath, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动服务
|
// Start 启动服务
|
||||||
func (this *ServiceManager) Start() error {
|
func (this *ServiceManager) Start() error {
|
||||||
if os.Getgid() != 0 {
|
if os.Getgid() != 0 {
|
||||||
return errors.New("only root users can start the service")
|
return errors.New("only root users can start the service")
|
||||||
@@ -47,7 +46,7 @@ func (this *ServiceManager) Start() error {
|
|||||||
return exec.Command("service", teaconst.ProcessName, "start").Start()
|
return exec.Command("service", teaconst.ProcessName, "start").Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除服务
|
// Uninstall 删除服务
|
||||||
func (this *ServiceManager) Uninstall() error {
|
func (this *ServiceManager) Uninstall() error {
|
||||||
if os.Getgid() != 0 {
|
if os.Getgid() != 0 {
|
||||||
return errors.New("only root users can uninstall the service")
|
return errors.New("only root users can uninstall the service")
|
||||||
@@ -83,13 +82,13 @@ func (this *ServiceManager) installInitService(exePath string, args []string) er
|
|||||||
return errors.New("'scripts/" + shortName + "' file not exists")
|
return errors.New("'scripts/" + shortName + "' file not exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(scriptFile)
|
data, err := os.ReadFile(scriptFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
data = regexp.MustCompile("INSTALL_DIR=.+").ReplaceAll(data, []byte("INSTALL_DIR="+Tea.Root))
|
data = regexp.MustCompile("INSTALL_DIR=.+").ReplaceAll(data, []byte("INSTALL_DIR="+Tea.Root))
|
||||||
err = ioutil.WriteFile(initServiceFile, data, 0777)
|
err = os.WriteFile(initServiceFile, data, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -137,7 +136,7 @@ ExecReload=` + exePath + ` reload
|
|||||||
WantedBy=multi-user.target`
|
WantedBy=multi-user.target`
|
||||||
|
|
||||||
// write file
|
// write file
|
||||||
err := ioutil.WriteFile(systemdServiceFile, []byte(desc), 0777)
|
err := os.WriteFile(systemdServiceFile, []byte(desc), 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build !linux,!windows
|
//go:build !linux && !windows
|
||||||
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build windows
|
//go:build windows
|
||||||
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ func (this *Page) AsHTML() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 每页数
|
// 每页数
|
||||||
result = append(result, `<select class="ui dropdown" style="height:34px;padding-top:0;padding-bottom:0;margin-left:1em;color:#666" onchange="ChangePageSize(this.value)">
|
result = append(result, `<select class="ui dropdown" style="padding-top:0;padding-bottom:0;margin-left:1em;color:#666" onchange="ChangePageSize(this.value)">
|
||||||
<option value="10">[每页]</option>`+this.renderSizeOption(10)+
|
<option value="10">[每页]</option>`+this.renderSizeOption(10)+
|
||||||
this.renderSizeOption(20)+
|
this.renderSizeOption(20)+
|
||||||
this.renderSizeOption(30)+
|
this.renderSizeOption(30)+
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -68,7 +67,7 @@ func FailPage(action actions.ActionWrapper, err error) {
|
|||||||
var issuesHTML = ""
|
var issuesHTML = ""
|
||||||
if isLocalAPI {
|
if isLocalAPI {
|
||||||
// 读取本地API节点的issues
|
// 读取本地API节点的issues
|
||||||
issuesData, issuesErr := ioutil.ReadFile(Tea.Root + "/edge-api/logs/issues.log")
|
issuesData, issuesErr := os.ReadFile(Tea.Root + "/edge-api/logs/issues.log")
|
||||||
if issuesErr == nil {
|
if issuesErr == nil {
|
||||||
var issueMaps = []maps.Map{}
|
var issueMaps = []maps.Map{}
|
||||||
issuesErr = json.Unmarshal(issuesData, &issueMaps)
|
issuesErr = json.Unmarshal(issuesData, &issueMaps)
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 添加地址
|
// CreateAddrPopupAction 添加地址
|
||||||
type CreateAddrPopupAction struct {
|
type CreateAddrPopupAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
@@ -30,12 +33,31 @@ func (this *CreateAddrPopupAction) RunPost(params struct {
|
|||||||
Field("addr", params.Addr).
|
Field("addr", params.Addr).
|
||||||
Require("请输入访问地址")
|
Require("请输入访问地址")
|
||||||
|
|
||||||
|
// 兼容URL
|
||||||
|
if regexp.MustCompile(`^(?i)(http|https)://`).MatchString(params.Addr) {
|
||||||
|
u, err := url.Parse(params.Addr)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("addr", "错误的访问地址,不需要添加http://或https://")
|
||||||
|
}
|
||||||
|
params.Addr = u.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动添加端口
|
||||||
|
if !strings.Contains(params.Addr, ":") {
|
||||||
|
switch params.Protocol {
|
||||||
|
case "http":
|
||||||
|
params.Addr += ":80"
|
||||||
|
case "https":
|
||||||
|
params.Addr += ":443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host, port, err := net.SplitHostPort(params.Addr)
|
host, port, err := net.SplitHostPort(params.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.FailField("addr", "错误的访问地址")
|
this.FailField("addr", "错误的访问地址")
|
||||||
}
|
}
|
||||||
|
|
||||||
addrConfig := &serverconfigs.NetworkAddressConfig{
|
var addrConfig = &serverconfigs.NetworkAddressConfig{
|
||||||
Protocol: serverconfigs.Protocol(params.Protocol),
|
Protocol: serverconfigs.Protocol(params.Protocol),
|
||||||
Host: host,
|
Host: host,
|
||||||
PortRange: port,
|
PortRange: port,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@ func (this *InstallAction) RunGet(params struct {
|
|||||||
"isNotFound": false,
|
"isNotFound": false,
|
||||||
}
|
}
|
||||||
dbConfigFile := Tea.ConfigFile("api_db.yaml")
|
dbConfigFile := Tea.ConfigFile("api_db.yaml")
|
||||||
data, err := ioutil.ReadFile(dbConfigFile)
|
data, err := os.ReadFile(dbConfigFile)
|
||||||
dbConfigMap["config"] = string(data)
|
dbConfigMap["config"] = string(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
dbConfigMap["error"] = err.Error()
|
dbConfigMap["error"] = err.Error()
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdateAddrPopupAction struct {
|
type UpdateAddrPopupAction struct {
|
||||||
@@ -27,6 +30,26 @@ func (this *UpdateAddrPopupAction) RunPost(params struct {
|
|||||||
params.Must.
|
params.Must.
|
||||||
Field("addr", params.Addr).
|
Field("addr", params.Addr).
|
||||||
Require("请输入访问地址")
|
Require("请输入访问地址")
|
||||||
|
|
||||||
|
// 兼容URL
|
||||||
|
if regexp.MustCompile(`^(?i)(http|https)://`).MatchString(params.Addr) {
|
||||||
|
u, err := url.Parse(params.Addr)
|
||||||
|
if err != nil {
|
||||||
|
this.FailField("addr", "错误的访问地址,不需要添加http://或https://")
|
||||||
|
}
|
||||||
|
params.Addr = u.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动添加端口
|
||||||
|
if !strings.Contains(params.Addr, ":") {
|
||||||
|
switch params.Protocol {
|
||||||
|
case "http":
|
||||||
|
params.Addr += ":80"
|
||||||
|
case "https":
|
||||||
|
params.Addr += ":443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host, port, err := net.SplitHostPort(params.Addr)
|
host, port, err := net.SplitHostPort(params.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.FailField("addr", "错误的访问地址")
|
this.FailField("addr", "错误的访问地址")
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package nodeutils
|
package nodeutils
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package node
|
package node
|
||||||
|
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
this.Data["groups"] = groupMaps
|
this.Data["groups"] = groupMaps
|
||||||
|
|
||||||
// 所有区域
|
// 所有区域
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.AdminContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package clusterutils
|
package clusterutils
|
||||||
|
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
this.Data["groups"] = groupMaps
|
this.Data["groups"] = groupMaps
|
||||||
|
|
||||||
// 所有区域
|
// 所有区域
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.AdminContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func (this *PricesAction) Init() {
|
|||||||
|
|
||||||
func (this *PricesAction) RunGet(params struct{}) {
|
func (this *PricesAction) RunGet(params struct{}) {
|
||||||
// 所有价格项目
|
// 所有价格项目
|
||||||
itemsResp, err := this.RPC().NodePriceItemRPC().FindAllEnabledAndOnNodePriceItems(this.AdminContext(), &pb.FindAllEnabledAndOnNodePriceItemsRequest{Type: regionutils.PriceTypeTraffic})
|
itemsResp, err := this.RPC().NodePriceItemRPC().FindAllAvailableNodePriceItems(this.AdminContext(), &pb.FindAllAvailableNodePriceItemsRequest{Type: regionutils.PriceTypeTraffic})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func (this *SelectPopupAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *SelectPopupAction) RunGet(params struct{}) {
|
func (this *SelectPopupAction) RunGet(params struct{}) {
|
||||||
regionsResp, err := this.RPC().NodeRegionRPC().FindAllEnabledAndOnNodeRegions(this.AdminContext(), &pb.FindAllEnabledAndOnNodeRegionsRequest{})
|
regionsResp, err := this.RPC().NodeRegionRPC().FindAllAvailableNodeRegions(this.AdminContext(), &pb.FindAllAvailableNodeRegionsRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ func (this *RestartLocalAPINodeAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 停止1秒等待命令运行完毕
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
// 检查是否已启动
|
// 检查是否已启动
|
||||||
var countTries = 120
|
var countTries = 120
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package providers
|
package providers
|
||||||
|
|
||||||
@@ -43,19 +42,7 @@ func (this *CreatePopupAction) RunGet(params struct{}) {
|
|||||||
this.Data["paramCustomHTTPSecret"] = rands.HexString(32)
|
this.Data["paramCustomHTTPSecret"] = rands.HexString(32)
|
||||||
|
|
||||||
// EdgeDNS集群列表
|
// EdgeDNS集群列表
|
||||||
nsClustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
|
this.Data["nsClusters"] = []maps.Map{}
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nsClusterMaps := []maps.Map{}
|
|
||||||
for _, nsCluster := range nsClustersResp.NsClusters {
|
|
||||||
nsClusterMaps = append(nsClusterMaps, maps.Map{
|
|
||||||
"id": nsCluster.Id,
|
|
||||||
"name": nsCluster.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["nsClusters"] = nsClusterMaps
|
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -82,9 +69,6 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
ParamCloudFlareAPIKey string
|
ParamCloudFlareAPIKey string
|
||||||
ParamCloudFlareEmail string
|
ParamCloudFlareEmail string
|
||||||
|
|
||||||
// Local EdgeDNS
|
|
||||||
ParamLocalEdgeDNSClusterId int64
|
|
||||||
|
|
||||||
// CustomHTTP
|
// CustomHTTP
|
||||||
ParamCustomHTTPURL string
|
ParamCustomHTTPURL string
|
||||||
ParamCustomHTTPSecret string
|
ParamCustomHTTPSecret string
|
||||||
@@ -137,11 +121,6 @@ func (this *CreatePopupAction) RunPost(params struct {
|
|||||||
Email("请输入正确格式的邮箱地址")
|
Email("请输入正确格式的邮箱地址")
|
||||||
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
||||||
apiParams["email"] = params.ParamCloudFlareEmail
|
apiParams["email"] = params.ParamCloudFlareEmail
|
||||||
case "localEdgeDNS":
|
|
||||||
params.Must.
|
|
||||||
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).
|
|
||||||
Gt(0, "请选择域名服务集群")
|
|
||||||
apiParams["clusterId"] = params.ParamLocalEdgeDNSClusterId
|
|
||||||
case "customHTTP":
|
case "customHTTP":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
||||||
|
|||||||
@@ -40,21 +40,10 @@ func (this *ProviderAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 本地EdgeDNS相关
|
// 本地EdgeDNS相关
|
||||||
var localEdgeDNSMap = maps.Map{}
|
localEdgeDNSMap, err := this.readEdgeDNS(provider, apiParams)
|
||||||
if provider.Type == "localEdgeDNS" {
|
if err != nil {
|
||||||
nsClusterId := apiParams.GetInt64("clusterId")
|
this.ErrorPage(err)
|
||||||
nsClusterResp, err := this.RPC().NSClusterRPC().FindEnabledNSCluster(this.AdminContext(), &pb.FindEnabledNSClusterRequest{NsClusterId: nsClusterId})
|
return
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nsCluster := nsClusterResp.NsCluster
|
|
||||||
if nsCluster != nil {
|
|
||||||
localEdgeDNSMap = maps.Map{
|
|
||||||
"id": nsCluster.Id,
|
|
||||||
"name": nsCluster.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["provider"] = maps.Map{
|
this.Data["provider"] = maps.Map{
|
||||||
|
|||||||
13
internal/web/actions/default/dns/providers/provider_ext.go
Normal file
13
internal/web/actions/default/dns/providers/provider_ext.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this *ProviderAction) readEdgeDNS(provider *pb.DNSProvider, apiParams maps.Map) (maps.Map, error) {
|
||||||
|
return maps.Map{}, nil
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package providers
|
package providers
|
||||||
|
|
||||||
@@ -68,19 +67,7 @@ func (this *UpdatePopupAction) RunGet(params struct {
|
|||||||
this.Data["types"] = typeMaps
|
this.Data["types"] = typeMaps
|
||||||
|
|
||||||
// EdgeDNS集群列表
|
// EdgeDNS集群列表
|
||||||
nsClustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
|
this.Data["nsClusters"] = []maps.Map{}
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nsClusterMaps := []maps.Map{}
|
|
||||||
for _, nsCluster := range nsClustersResp.NsClusters {
|
|
||||||
nsClusterMaps = append(nsClusterMaps, maps.Map{
|
|
||||||
"id": nsCluster.Id,
|
|
||||||
"name": nsCluster.Name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["nsClusters"] = nsClusterMaps
|
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -109,9 +96,6 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
ParamCloudFlareAPIKey string
|
ParamCloudFlareAPIKey string
|
||||||
ParamCloudFlareEmail string
|
ParamCloudFlareEmail string
|
||||||
|
|
||||||
// Local EdgeDNS
|
|
||||||
ParamLocalEdgeDNSClusterId int64
|
|
||||||
|
|
||||||
// CustomHTTP
|
// CustomHTTP
|
||||||
ParamCustomHTTPURL string
|
ParamCustomHTTPURL string
|
||||||
ParamCustomHTTPSecret string
|
ParamCustomHTTPSecret string
|
||||||
@@ -166,11 +150,6 @@ func (this *UpdatePopupAction) RunPost(params struct {
|
|||||||
Email("请输入正确格式的邮箱地址")
|
Email("请输入正确格式的邮箱地址")
|
||||||
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
apiParams["apiKey"] = params.ParamCloudFlareAPIKey
|
||||||
apiParams["email"] = params.ParamCloudFlareEmail
|
apiParams["email"] = params.ParamCloudFlareEmail
|
||||||
case "localEdgeDNS":
|
|
||||||
params.Must.
|
|
||||||
Field("ParamLocalEdgeDNSClusterId", params.ParamLocalEdgeDNSClusterId).
|
|
||||||
Gt(0, "请选择域名服务集群")
|
|
||||||
apiParams["clusterId"] = params.ParamLocalEdgeDNSClusterId
|
|
||||||
case "customHTTP":
|
case "customHTTP":
|
||||||
params.Must.
|
params.Must.
|
||||||
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
Field("paramCustomHTTPURL", params.ParamCustomHTTPURL).
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func (this *AddPortPopupAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
this.Data["from"] = params.From
|
this.Data["from"] = params.From
|
||||||
|
|
||||||
protocols := serverconfigs.AllServerProtocolsForType(params.ServerType)
|
protocols := serverconfigs.FindAllServerProtocolsForType(params.ServerType)
|
||||||
if len(params.Protocol) > 0 {
|
if len(params.Protocol) > 0 {
|
||||||
result := []maps.Map{}
|
result := []maps.Map{}
|
||||||
for _, p := range protocols {
|
for _, p := range protocols {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
|
|||||||
Must *actions.Must
|
Must *actions.Must
|
||||||
}) {
|
}) {
|
||||||
if params.Mode == "single" {
|
if params.Mode == "single" {
|
||||||
var serverName = params.ServerName
|
var serverName = strings.ToLower(params.ServerName)
|
||||||
|
|
||||||
// 去除空格
|
// 去除空格
|
||||||
serverName = regexp.MustCompile(`\s+`).ReplaceAllString(serverName, "")
|
serverName = regexp.MustCompile(`\s+`).ReplaceAllString(serverName, "")
|
||||||
@@ -72,6 +72,9 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 转成小写
|
||||||
|
serverName = strings.ToLower(serverName)
|
||||||
|
|
||||||
serverNames = append(serverNames, serverName)
|
serverNames = append(serverNames, serverName)
|
||||||
}
|
}
|
||||||
this.Data["serverName"] = maps.Map{
|
this.Data["serverName"] = maps.Map{
|
||||||
|
|||||||
@@ -36,15 +36,11 @@ func (this *DeleteAction) RunPost(params struct {
|
|||||||
this.Fail("此证书正在被某些API节点引用,请先修改API节点后再删除")
|
this.Fail("此证书正在被某些API节点引用,请先修改API节点后再删除")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是否正在被用户节点使用
|
err = this.filterDelete(params.CertId)
|
||||||
countResp, err = this.RPC().UserNodeRPC().CountAllEnabledUserNodesWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledUserNodesWithSSLCertIdRequest{SslCertId: params.CertId})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if countResp.Count > 0 {
|
|
||||||
this.Fail("此证书正在被某些用户节点引用,请先修改用户节点后再删除")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = this.RPC().SSLCertRPC().DeleteSSLCert(this.AdminContext(), &pb.DeleteSSLCertRequest{SslCertId: params.CertId})
|
_, err = this.RPC().SSLCertRPC().DeleteSSLCert(this.AdminContext(), &pb.DeleteSSLCertRequest{SslCertId: params.CertId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
8
internal/web/actions/default/servers/certs/delete_ext.go
Normal file
8
internal/web/actions/default/servers/certs/delete_ext.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
//go:build !plus
|
||||||
|
|
||||||
|
package certs
|
||||||
|
|
||||||
|
func (this *DeleteAction) filterDelete(certId int64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -41,7 +41,7 @@ func (this *IndexAction) RunGet(params struct {
|
|||||||
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
||||||
}
|
}
|
||||||
|
|
||||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllEnabledRegionCountries(this.AdminContext(), &pb.FindAllEnabledRegionCountriesRequest{})
|
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
||||||
}
|
}
|
||||||
|
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllEnabledRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllEnabledRegionProvincesWithCountryIdRequest{
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
|
||||||
RegionCountryId: int64(ChinaCountryId),
|
RegionCountryId: int64(ChinaCountryId),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package servergrouputils
|
package servergrouputils
|
||||||
|
|
||||||
|
|||||||
@@ -46,13 +46,13 @@ func (this *CountriesAction) RunGet(params struct {
|
|||||||
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
||||||
}
|
}
|
||||||
|
|
||||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllEnabledRegionCountries(this.AdminContext(), &pb.FindAllEnabledRegionCountriesRequest{})
|
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
countryMaps := []maps.Map{}
|
countryMaps := []maps.Map{}
|
||||||
for _, country := range countriesResp.Countries {
|
for _, country := range countriesResp.RegionCountries {
|
||||||
countryMaps = append(countryMaps, maps.Map{
|
countryMaps = append(countryMaps, maps.Map{
|
||||||
"id": country.Id,
|
"id": country.Id,
|
||||||
"name": country.Name,
|
"name": country.Name,
|
||||||
|
|||||||
@@ -46,15 +46,15 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
||||||
}
|
}
|
||||||
|
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllEnabledRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllEnabledRegionProvincesWithCountryIdRequest{
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithCountryIdRequest{
|
||||||
CountryId: int64(ChinaCountryId),
|
RegionCountryId: int64(ChinaCountryId),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
provinceMaps := []maps.Map{}
|
provinceMaps := []maps.Map{}
|
||||||
for _, province := range provincesResp.Provinces {
|
for _, province := range provincesResp.RegionProvinces {
|
||||||
provinceMaps = append(provinceMaps, maps.Map{
|
provinceMaps = append(provinceMaps, maps.Map{
|
||||||
"id": province.Id,
|
"id": province.Id,
|
||||||
"name": province.Name,
|
"name": province.Name,
|
||||||
|
|||||||
@@ -179,6 +179,13 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
|
|||||||
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.RemoteAddr != nil && locationConfig.Web.RemoteAddr.IsOn,
|
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.RemoteAddr != nil && locationConfig.Web.RemoteAddr.IsOn,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
menuItems = append(menuItems, maps.Map{
|
||||||
|
"name": "请求限制",
|
||||||
|
"url": "/servers/server/settings/locations/requestLimit?serverId=" + serverIdString + "&locationId=" + locationIdString,
|
||||||
|
"isActive": secondMenuItem == "requestLimit",
|
||||||
|
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.RequestLimit != nil && locationConfig.Web.RequestLimit.IsOn,
|
||||||
|
})
|
||||||
|
|
||||||
return menuItems
|
return menuItems
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,12 +194,12 @@ func (this *LocationHelper) hasHTTPHeaders(web *serverconfigs.HTTPWebConfig) boo
|
|||||||
if web == nil {
|
if web == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if web.RequestHeaderPolicyRef != nil {
|
if web.RequestHeaderPolicyRef != nil && web.RequestHeaderPolicyRef.IsPrior {
|
||||||
if web.RequestHeaderPolicyRef.IsOn && web.RequestHeaderPolicy != nil && !web.RequestHeaderPolicy.IsEmpty() {
|
if web.RequestHeaderPolicyRef.IsOn && web.RequestHeaderPolicy != nil && !web.RequestHeaderPolicy.IsEmpty() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if web.ResponseHeaderPolicyRef != nil {
|
if web.ResponseHeaderPolicyRef != nil && web.ResponseHeaderPolicyRef.IsPrior {
|
||||||
if web.ResponseHeaderPolicyRef.IsOn && web.ResponseHeaderPolicy != nil && !web.ResponseHeaderPolicy.IsEmpty() {
|
if web.ResponseHeaderPolicyRef.IsOn && web.ResponseHeaderPolicy != nil && !web.ResponseHeaderPolicy.IsEmpty() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package locationutils
|
package locationutils
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
|
|
||||||
|
package requestlimit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
|
"github.com/iwind/TeaGo/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IndexAction struct {
|
||||||
|
actionutils.ParentAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) Init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunGet(params struct {
|
||||||
|
ServerId int64
|
||||||
|
LocationId int64
|
||||||
|
}) {
|
||||||
|
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithLocationId(this.AdminContext(), params.LocationId)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["webId"] = webConfig.Id
|
||||||
|
this.Data["requestLimitConfig"] = webConfig.RequestLimit
|
||||||
|
|
||||||
|
this.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *IndexAction) RunPost(params struct {
|
||||||
|
WebId int64
|
||||||
|
RequestLimitJSON []byte
|
||||||
|
|
||||||
|
Must *actions.Must
|
||||||
|
CSRF *actionutils.CSRF
|
||||||
|
}) {
|
||||||
|
defer this.CreateLogInfo("修改Web %d 请求限制", params.WebId)
|
||||||
|
|
||||||
|
_, err := this.RPC().HTTPWebRPC().UpdateHTTPWebRequestLimit(this.AdminContext(), &pb.UpdateHTTPWebRequestLimitRequest{
|
||||||
|
HttpWebId: params.WebId,
|
||||||
|
RequestLimitJSON: params.RequestLimitJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Success()
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package requestlimit
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/locationutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/serverutils"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||||
|
"github.com/iwind/TeaGo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
|
server.
|
||||||
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||||
|
Helper(locationutils.NewLocationHelper()).
|
||||||
|
Helper(serverutils.NewServerHelper()).
|
||||||
|
Data("tinyMenuItem", "requestLimit").
|
||||||
|
Prefix("/servers/server/settings/locations/requestLimit").
|
||||||
|
GetPost("", new(IndexAction)).
|
||||||
|
EndAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ func (this *CountriesAction) RunGet(params struct {
|
|||||||
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
selectedCountryIds = policyConfig.Inbound.Region.DenyCountryIds
|
||||||
}
|
}
|
||||||
|
|
||||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllEnabledRegionCountries(this.AdminContext(), &pb.FindAllEnabledRegionCountriesRequest{})
|
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func (this *ProvincesAction) RunGet(params struct {
|
|||||||
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
selectedProvinceIds = policyConfig.Inbound.Region.DenyProvinceIds
|
||||||
}
|
}
|
||||||
|
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllEnabledRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllEnabledRegionProvincesWithCountryIdRequest{
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{
|
||||||
RegionCountryId: int64(ChinaCountryId),
|
RegionCountryId: int64(ChinaCountryId),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package serverutils
|
package serverutils
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ func (this *OptionsAction) RunPost(params struct {
|
|||||||
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{
|
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{
|
||||||
Keyword: params.Keyword,
|
Keyword: params.Keyword,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
Size: 10000, // TODO 改进 <plan-user-selector> 组件
|
Size: 100,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userMaps := []maps.Map{}
|
var userMaps = []maps.Map{}
|
||||||
for _, user := range usersResp.Users {
|
for _, user := range usersResp.Users {
|
||||||
userMaps = append(userMaps, maps.Map{
|
userMaps = append(userMaps, maps.Map{
|
||||||
"id": user.Id,
|
"id": user.Id,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
this.Data["error"] = ""
|
this.Data["error"] = ""
|
||||||
|
|
||||||
configFile := Tea.ConfigFile("api_db.yaml")
|
configFile := Tea.ConfigFile("api_db.yaml")
|
||||||
data, err := ioutil.ReadFile(configFile)
|
data, err := os.ReadFile(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Data["error"] = "read config file failed: api_db.yaml: " + err.Error()
|
this.Data["error"] = "read config file failed: api_db.yaml: " + err.Error()
|
||||||
this.Show()
|
this.Show()
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"github.com/iwind/TeaGo/dbs"
|
"github.com/iwind/TeaGo/dbs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -34,7 +34,7 @@ func (this *UpdateAction) RunGet(params struct{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configFile := Tea.ConfigFile("api_db.yaml")
|
configFile := Tea.ConfigFile("api_db.yaml")
|
||||||
data, err := ioutil.ReadFile(configFile)
|
data, err := os.ReadFile(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ dbs:
|
|||||||
models:
|
models:
|
||||||
package: internal/web/models
|
package: internal/web/models
|
||||||
`
|
`
|
||||||
err := ioutil.WriteFile(configFile, []byte(template), 0666)
|
err := os.WriteFile(configFile, []byte(template), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("保存配置失败:" + err.Error())
|
this.Fail("保存配置失败:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
package iplibrary
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
|
||||||
"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 {
|
|
||||||
LibraryId int64
|
|
||||||
}) {
|
|
||||||
// 创建日志
|
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "删除IP库 %d", params.LibraryId)
|
|
||||||
|
|
||||||
_, err := this.RPC().IPLibraryRPC().DeleteIPLibrary(this.AdminContext(), &pb.DeleteIPLibraryRequest{IpLibraryId: params.LibraryId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package iplibrary
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DownloadAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *DownloadAction) Init() {
|
|
||||||
this.Nav("", "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *DownloadAction) RunGet(params struct {
|
|
||||||
LibraryId int64
|
|
||||||
}) {
|
|
||||||
// 日志
|
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "下载IP库 %d", params.LibraryId)
|
|
||||||
|
|
||||||
libraryResp, err := this.RPC().IPLibraryRPC().FindEnabledIPLibrary(this.AdminContext(), &pb.FindEnabledIPLibraryRequest{IpLibraryId: params.LibraryId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if libraryResp.IpLibrary == nil || libraryResp.IpLibrary.File == nil {
|
|
||||||
this.NotFound("ipLibrary", params.LibraryId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
file := libraryResp.IpLibrary.File
|
|
||||||
chunkIdsResp, err := this.RPC().FileChunkRPC().FindAllFileChunkIds(this.AdminContext(), &pb.FindAllFileChunkIdsRequest{FileId: file.Id})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+file.Filename+"\";")
|
|
||||||
for _, chunkId := range chunkIdsResp.FileChunkIds {
|
|
||||||
chunkResp, err := this.RPC().FileChunkRPC().DownloadFileChunk(this.AdminContext(), &pb.DownloadFileChunkRequest{FileChunkId: chunkId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if chunkResp.FileChunk != nil {
|
|
||||||
this.Write(chunkResp.FileChunk.Data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package iplibrary
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Helper struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHelper() *Helper {
|
|
||||||
return &Helper{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *Helper) BeforeAction(action *actions.ActionObject) {
|
|
||||||
if action.Request.Method != http.MethodGet {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
action.Data["mainTab"] = "component"
|
|
||||||
action.Data["secondMenuItem"] = "ip-library"
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package iplibrary
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
|
||||||
"github.com/iwind/TeaGo/maps"
|
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IndexAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *IndexAction) Init() {
|
|
||||||
this.FirstMenu("index")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *IndexAction) RunGet(params struct {
|
|
||||||
Type string
|
|
||||||
}) {
|
|
||||||
if len(params.Type) == 0 {
|
|
||||||
params.Type = serverconfigs.IPLibraryTypes[0].GetString("code")
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Data["types"] = serverconfigs.IPLibraryTypes
|
|
||||||
this.Data["selectedType"] = params.Type
|
|
||||||
|
|
||||||
// 列表
|
|
||||||
listResp, err := this.RPC().IPLibraryRPC().FindAllEnabledIPLibrariesWithType(this.AdminContext(), &pb.FindAllEnabledIPLibrariesWithTypeRequest{Type: params.Type})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
libraryMaps := []maps.Map{}
|
|
||||||
for _, library := range listResp.IpLibraries {
|
|
||||||
var fileMap maps.Map = nil
|
|
||||||
if library.File != nil {
|
|
||||||
fileMap = maps.Map{
|
|
||||||
"id": library.File.Id,
|
|
||||||
"filename": library.File.Filename,
|
|
||||||
"sizeMB": fmt.Sprintf("%.2f", float64(library.File.Size)/1024/1024),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libraryMaps = append(libraryMaps, maps.Map{
|
|
||||||
"id": library.Id,
|
|
||||||
"file": fileMap,
|
|
||||||
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", library.CreatedAt),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.Data["libraries"] = libraryMaps
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package iplibrary
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
|
||||||
"github.com/iwind/TeaGo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
|
||||||
server.
|
|
||||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeSetting)).
|
|
||||||
Helper(NewHelper()).
|
|
||||||
Helper(settingutils.NewHelper("ipLibrary")).
|
|
||||||
Prefix("/settings/ip-library").
|
|
||||||
Get("", new(IndexAction)).
|
|
||||||
GetPost("/uploadPopup", new(UploadPopupAction)).
|
|
||||||
Post("/delete", new(DeleteAction)).
|
|
||||||
Get("/download", new(DownloadAction)).
|
|
||||||
EndAll()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package iplibrary
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
|
||||||
"github.com/iwind/TeaGo/actions"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UploadPopupAction struct {
|
|
||||||
actionutils.ParentAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UploadPopupAction) Init() {
|
|
||||||
this.Nav("", "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UploadPopupAction) RunGet(params struct{}) {
|
|
||||||
this.Data["types"] = serverconfigs.IPLibraryTypes
|
|
||||||
|
|
||||||
this.Show()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *UploadPopupAction) RunPost(params struct {
|
|
||||||
Type string
|
|
||||||
File *actions.File
|
|
||||||
|
|
||||||
Must *actions.Must
|
|
||||||
}) {
|
|
||||||
libraryType := serverconfigs.FindIPLibraryWithType(params.Type)
|
|
||||||
if libraryType == nil {
|
|
||||||
this.Fail("错误的IP类型")
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.File == nil {
|
|
||||||
this.Fail("请选择要上传的文件")
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.File.Size == 0 {
|
|
||||||
this.Fail("文件内容不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.File.Ext != libraryType.GetString("ext") {
|
|
||||||
this.Fail("IP库文件扩展名错误,应该为:" + libraryType.GetString("ext"))
|
|
||||||
}
|
|
||||||
|
|
||||||
reader, err := params.File.OriginFile.Open()
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
_ = reader.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 创建文件
|
|
||||||
fileResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
|
||||||
Filename: params.File.Filename,
|
|
||||||
Size: params.File.Size,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fileId := fileResp.FileId
|
|
||||||
|
|
||||||
// 上传内容
|
|
||||||
buf := make([]byte, 512*1024)
|
|
||||||
for {
|
|
||||||
n, err := reader.Read(buf)
|
|
||||||
if n > 0 {
|
|
||||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
|
||||||
FileId: fileId,
|
|
||||||
Data: buf[:n],
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.Fail("上传失败:" + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
this.Fail("上传失败:" + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 置为已完成
|
|
||||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存
|
|
||||||
createResp, err := this.RPC().IPLibraryRPC().CreateIPLibrary(this.AdminContext(), &pb.CreateIPLibraryRequest{
|
|
||||||
Type: params.Type,
|
|
||||||
FileId: fileId,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
this.ErrorPage(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建日志
|
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "上传IP库 %d", createResp.IpLibraryId)
|
|
||||||
|
|
||||||
this.Success()
|
|
||||||
}
|
|
||||||
@@ -31,7 +31,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
// 国家和地区
|
// 国家和地区
|
||||||
var countryMaps = []maps.Map{}
|
var countryMaps = []maps.Map{}
|
||||||
for _, countryId := range config.AllowCountryIds {
|
for _, countryId := range config.AllowCountryIds {
|
||||||
countryResp, err := this.RPC().RegionCountryRPC().FindEnabledRegionCountry(this.AdminContext(), &pb.FindEnabledRegionCountryRequest{RegionCountryId: countryId})
|
countryResp, err := this.RPC().RegionCountryRPC().FindRegionCountry(this.AdminContext(), &pb.FindRegionCountryRequest{RegionCountryId: countryId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -49,7 +49,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
|||||||
// 省份
|
// 省份
|
||||||
var provinceMaps = []maps.Map{}
|
var provinceMaps = []maps.Map{}
|
||||||
for _, provinceId := range config.AllowProvinceIds {
|
for _, provinceId := range config.AllowProvinceIds {
|
||||||
provinceResp, err := this.RPC().RegionProvinceRPC().FindEnabledRegionProvince(this.AdminContext(), &pb.FindEnabledRegionProvinceRequest{RegionProvinceId: provinceId})
|
provinceResp, err := this.RPC().RegionProvinceRPC().FindRegionProvince(this.AdminContext(), &pb.FindRegionProvinceRequest{RegionProvinceId: provinceId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdateHTTPSPopupAction struct {
|
type UpdateHTTPSPopupAction struct {
|
||||||
@@ -31,12 +31,12 @@ func (this *UpdateHTTPSPopupAction) RunGet(params struct{}) {
|
|||||||
// 证书
|
// 证书
|
||||||
certConfigs := []*sslconfigs.SSLCertConfig{}
|
certConfigs := []*sslconfigs.SSLCertConfig{}
|
||||||
if len(serverConfig.Https.Cert) > 0 && len(serverConfig.Https.Key) > 0 {
|
if len(serverConfig.Https.Cert) > 0 && len(serverConfig.Https.Key) > 0 {
|
||||||
certData, err := ioutil.ReadFile(Tea.Root + "/" + serverConfig.Https.Cert)
|
certData, err := os.ReadFile(Tea.Root + "/" + serverConfig.Https.Cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keyData, err := ioutil.ReadFile(Tea.Root + "/" + serverConfig.Https.Key)
|
keyData, err := os.ReadFile(Tea.Root + "/" + serverConfig.Https.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -120,11 +120,11 @@ func (this *UpdateHTTPSPopupAction) RunPost(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(Tea.ConfigFile("https.key.pem"), certConfig.KeyData, 0666)
|
err = os.WriteFile(Tea.ConfigFile("https.key.pem"), certConfig.KeyData, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("保存密钥失败:" + err.Error())
|
this.Fail("保存密钥失败:" + err.Error())
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(Tea.ConfigFile("https.cert.pem"), certConfig.CertData, 0666)
|
err = os.WriteFile(Tea.ConfigFile("https.cert.pem"), certConfig.CertData, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("保存证书失败:" + err.Error())
|
this.Fail("保存证书失败:" + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var serverConfigIsChanged = false
|
var serverConfigIsChanged = false
|
||||||
@@ -12,7 +12,7 @@ var serverConfigIsChanged = false
|
|||||||
// 读取当前服务配置
|
// 读取当前服务配置
|
||||||
func loadServerConfig() (*TeaGo.ServerConfig, error) {
|
func loadServerConfig() (*TeaGo.ServerConfig, error) {
|
||||||
configFile := Tea.ConfigFile("server.yaml")
|
configFile := Tea.ConfigFile("server.yaml")
|
||||||
data, err := ioutil.ReadFile(configFile)
|
data, err := os.ReadFile(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ func writeServerConfig(serverConfig *TeaGo.ServerConfig) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(Tea.ConfigFile("server.yaml"), data, 0666)
|
err = os.WriteFile(Tea.ConfigFile("server.yaml"), data, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package settingutils
|
package settingutils
|
||||||
|
|
||||||
@@ -22,14 +21,14 @@ func NewAdvancedHelper(tab string) *AdvancedHelper {
|
|||||||
func (this *AdvancedHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
func (this *AdvancedHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||||
goNext = true
|
goNext = true
|
||||||
|
|
||||||
action := actionPtr.Object()
|
var action = actionPtr.Object()
|
||||||
|
|
||||||
// 左侧菜单
|
// 左侧菜单
|
||||||
action.Data["teaMenu"] = "settings"
|
action.Data["teaMenu"] = "settings"
|
||||||
action.Data["teaSubMenu"] = "advanced"
|
action.Data["teaSubMenu"] = "advanced"
|
||||||
|
|
||||||
// 标签栏
|
// 标签栏
|
||||||
tabbar := actionutils.NewTabbar()
|
var tabbar = actionutils.NewTabbar()
|
||||||
var session = action.Session()
|
var session = action.Session()
|
||||||
var adminId = session.GetInt64("adminId")
|
var adminId = session.GetInt64("adminId")
|
||||||
if configloaders.AllowModule(adminId, configloaders.AdminModuleCodeSetting) {
|
if configloaders.AllowModule(adminId, configloaders.AdminModuleCodeSetting) {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
//go:build !plus
|
||||||
|
|
||||||
package settingutils
|
package settingutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
)
|
)
|
||||||
@@ -20,23 +21,19 @@ func NewHelper(tab string) *Helper {
|
|||||||
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool) {
|
||||||
goNext = true
|
goNext = true
|
||||||
|
|
||||||
action := actionPtr.Object()
|
var action = actionPtr.Object()
|
||||||
|
|
||||||
// 左侧菜单
|
// 左侧菜单
|
||||||
action.Data["teaMenu"] = "settings"
|
action.Data["teaMenu"] = "settings"
|
||||||
|
|
||||||
// 标签栏
|
// 标签栏
|
||||||
tabbar := actionutils.NewTabbar()
|
var tabbar = actionutils.NewTabbar()
|
||||||
var session = action.Session()
|
var session = action.Session()
|
||||||
var adminId = session.GetInt64("adminId")
|
var adminId = session.GetInt64("adminId")
|
||||||
if configloaders.AllowModule(adminId, configloaders.AdminModuleCodeSetting) {
|
if configloaders.AllowModule(adminId, configloaders.AdminModuleCodeSetting) {
|
||||||
tabbar.Add("Web服务", "", "/settings/server", "", this.tab == "server")
|
tabbar.Add("Web服务", "", "/settings/server", "", this.tab == "server")
|
||||||
tabbar.Add("管理界面设置", "", "/settings/ui", "", this.tab == "ui")
|
tabbar.Add("管理界面设置", "", "/settings/ui", "", this.tab == "ui")
|
||||||
if teaconst.IsPlus {
|
|
||||||
tabbar.Add("用户界面设置", "", "/settings/user-ui", "", this.tab == "userUI")
|
|
||||||
}
|
|
||||||
tabbar.Add("安全设置", "", "/settings/security", "", this.tab == "security")
|
tabbar.Add("安全设置", "", "/settings/security", "", this.tab == "security")
|
||||||
//tabbar.Add("IP库", "", "/settings/ip-library", "", this.tab == "ipLibrary")
|
|
||||||
tabbar.Add("检查更新", "", "/settings/updates", "", this.tab == "updates")
|
tabbar.Add("检查更新", "", "/settings/updates", "", this.tab == "updates")
|
||||||
}
|
}
|
||||||
tabbar.Add("个人资料", "", "/settings/profile", "", this.tab == "profile")
|
tabbar.Add("个人资料", "", "/settings/profile", "", this.tab == "profile")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -70,7 +70,7 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
defer func() {
|
defer func() {
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}()
|
}()
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
data, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Data["result"] = maps.Map{
|
this.Data["result"] = maps.Map{
|
||||||
"isOk": false,
|
"isOk": false,
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"github.com/iwind/gosock/pkg/gosock"
|
"github.com/iwind/gosock/pkg/gosock"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
@@ -102,7 +101,7 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("生成数据库配置失败:" + err.Error())
|
this.Fail("生成数据库配置失败:" + err.Error())
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(apiNodeDir+"/configs/db.yaml", dbConfigData, 0666)
|
err = os.WriteFile(apiNodeDir+"/configs/db.yaml", dbConfigData, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("保存数据库配置失败:" + err.Error())
|
this.Fail("保存数据库配置失败:" + err.Error())
|
||||||
}
|
}
|
||||||
@@ -116,16 +115,16 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
for _, backupDir := range backupDirs {
|
for _, backupDir := range backupDirs {
|
||||||
stat, err := os.Stat(backupDir)
|
stat, err := os.Stat(backupDir)
|
||||||
if err == nil && stat.IsDir() {
|
if err == nil && stat.IsDir() {
|
||||||
_ = ioutil.WriteFile(backupDir+"/db.yaml", dbConfigData, 0666)
|
_ = os.WriteFile(backupDir+"/db.yaml", dbConfigData, 0666)
|
||||||
} else if err != nil && os.IsNotExist(err) {
|
} else if err != nil && os.IsNotExist(err) {
|
||||||
err = os.Mkdir(backupDir, 0777)
|
err = os.Mkdir(backupDir, 0777)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = ioutil.WriteFile(backupDir+"/db.yaml", dbConfigData, 0666)
|
_ = os.WriteFile(backupDir+"/db.yaml", dbConfigData, 0666)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(Tea.ConfigFile("/api_db.yaml"), dbConfigData, 0666)
|
err = os.WriteFile(Tea.ConfigFile("/api_db.yaml"), dbConfigData, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.Fail("保存数据库配置失败:" + err.Error())
|
this.Fail("保存数据库配置失败:" + err.Error())
|
||||||
}
|
}
|
||||||
@@ -138,11 +137,11 @@ func (this *InstallAction) RunPost(params struct {
|
|||||||
for _, backupDir := range backupDirs {
|
for _, backupDir := range backupDirs {
|
||||||
stat, err := os.Stat(backupDir)
|
stat, err := os.Stat(backupDir)
|
||||||
if err == nil && stat.IsDir() {
|
if err == nil && stat.IsDir() {
|
||||||
_ = ioutil.WriteFile(backupDir+"/api_db.yaml", dbConfigData, 0666)
|
_ = os.WriteFile(backupDir+"/api_db.yaml", dbConfigData, 0666)
|
||||||
} else if err != nil && os.IsNotExist(err) {
|
} else if err != nil && os.IsNotExist(err) {
|
||||||
err = os.Mkdir(backupDir, 0777)
|
err = os.Mkdir(backupDir, 0777)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = ioutil.WriteFile(backupDir+"/api_db.yaml", dbConfigData, 0666)
|
_ = os.WriteFile(backupDir+"/api_db.yaml", dbConfigData, 0666)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type CityOptionsAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *CityOptionsAction) RunPost(params struct{}) {
|
func (this *CityOptionsAction) RunPost(params struct{}) {
|
||||||
citiesResp, err := this.RPC().RegionCityRPC().FindAllEnabledRegionCities(this.AdminContext(), &pb.FindAllEnabledRegionCitiesRequest{
|
citiesResp, err := this.RPC().RegionCityRPC().FindAllRegionCities(this.AdminContext(), &pb.FindAllRegionCitiesRequest{
|
||||||
IncludeRegionProvince: true,
|
IncludeRegionProvince: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type CountryOptionsAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *CountryOptionsAction) RunPost(params struct{}) {
|
func (this *CountryOptionsAction) RunPost(params struct{}) {
|
||||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllEnabledRegionCountries(this.AdminContext(), &pb.FindAllEnabledRegionCountriesRequest{})
|
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"io/ioutil"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HideTipAction struct {
|
type HideTipAction struct {
|
||||||
@@ -23,7 +23,7 @@ func (this *HideTipAction) RunPost(params struct {
|
|||||||
// 保存到文件
|
// 保存到文件
|
||||||
tipJSON, err := json.Marshal(tipKeyMap)
|
tipJSON, err := json.Marshal(tipKeyMap)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_ = ioutil.WriteFile(Tea.ConfigFile(tipConfigFile), tipJSON, 0666)
|
_ = os.WriteFile(Tea.ConfigFile(tipConfigFile), tipJSON, 0666)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Success()
|
this.Success()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type ProviderOptionsAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *ProviderOptionsAction) RunPost(params struct{}) {
|
func (this *ProviderOptionsAction) RunPost(params struct{}) {
|
||||||
providersResp, err := this.RPC().RegionProviderRPC().FindAllEnabledRegionProviders(this.AdminContext(), &pb.FindAllEnabledRegionProvidersRequest{})
|
providersResp, err := this.RPC().RegionProviderRPC().FindAllRegionProviders(this.AdminContext(), &pb.FindAllRegionProvidersRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type ProvinceOptionsAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *ProvinceOptionsAction) RunPost(params struct{}) {
|
func (this *ProvinceOptionsAction) RunPost(params struct{}) {
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllEnabledRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllEnabledRegionProvincesWithCountryIdRequest{RegionCountryId: ChinaCountryId})
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{RegionCountryId: ChinaCountryId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func (this *SelectCountriesPopupAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
var selectedCountryIds = utils.SplitNumbers(params.CountryIds)
|
var selectedCountryIds = utils.SplitNumbers(params.CountryIds)
|
||||||
|
|
||||||
countriesResp, err := this.RPC().RegionCountryRPC().FindAllEnabledRegionCountries(this.AdminContext(), &pb.FindAllEnabledRegionCountriesRequest{})
|
countriesResp, err := this.RPC().RegionCountryRPC().FindAllRegionCountries(this.AdminContext(), &pb.FindAllRegionCountriesRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -50,7 +50,7 @@ func (this *SelectCountriesPopupAction) RunPost(params struct {
|
|||||||
}) {
|
}) {
|
||||||
var countryMaps = []maps.Map{}
|
var countryMaps = []maps.Map{}
|
||||||
for _, countryId := range params.CountryIds {
|
for _, countryId := range params.CountryIds {
|
||||||
countryResp, err := this.RPC().RegionCountryRPC().FindEnabledRegionCountry(this.AdminContext(), &pb.FindEnabledRegionCountryRequest{RegionCountryId: countryId})
|
countryResp, err := this.RPC().RegionCountryRPC().FindRegionCountry(this.AdminContext(), &pb.FindRegionCountryRequest{RegionCountryId: countryId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func (this *SelectProvincesPopupAction) RunGet(params struct {
|
|||||||
}) {
|
}) {
|
||||||
var selectedProvinceIds = utils.SplitNumbers(params.ProvinceIds)
|
var selectedProvinceIds = utils.SplitNumbers(params.ProvinceIds)
|
||||||
|
|
||||||
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllEnabledRegionProvincesWithCountryId(this.AdminContext(), &pb.FindAllEnabledRegionProvincesWithCountryIdRequest{RegionCountryId: ChinaCountryId})
|
provincesResp, err := this.RPC().RegionProvinceRPC().FindAllRegionProvincesWithRegionCountryId(this.AdminContext(), &pb.FindAllRegionProvincesWithRegionCountryIdRequest{RegionCountryId: ChinaCountryId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -50,7 +50,7 @@ func (this *SelectProvincesPopupAction) RunPost(params struct {
|
|||||||
}) {
|
}) {
|
||||||
var provinceMaps = []maps.Map{}
|
var provinceMaps = []maps.Map{}
|
||||||
for _, provinceId := range params.ProvinceIds {
|
for _, provinceId := range params.ProvinceIds {
|
||||||
provinceResp, err := this.RPC().RegionProvinceRPC().FindEnabledRegionProvince(this.AdminContext(), &pb.FindEnabledRegionProvinceRequest{RegionProvinceId: provinceId})
|
provinceResp, err := this.RPC().RegionProvinceRPC().FindRegionProvince(this.AdminContext(), &pb.FindRegionProvinceRequest{RegionProvinceId: provinceId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/iwind/TeaGo"
|
"github.com/iwind/TeaGo"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ var tipConfigFile = "tip.cache.json"
|
|||||||
func init() {
|
func init() {
|
||||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||||
// 从配置文件中加载已关闭的tips
|
// 从配置文件中加载已关闭的tips
|
||||||
data, err := ioutil.ReadFile(Tea.ConfigFile(tipConfigFile))
|
data, err := os.ReadFile(Tea.ConfigFile(tipConfigFile))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var m = map[string]bool{}
|
var m = map[string]bool{}
|
||||||
err = json.Unmarshal(data, &m)
|
err = json.Unmarshal(data, &m)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||||
//go:build !plus
|
//go:build !plus
|
||||||
// +build !plus
|
|
||||||
|
|
||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package helpers
|
|||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||||
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/events"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/goman"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/actions"
|
"github.com/iwind/TeaGo/actions"
|
||||||
@@ -17,6 +19,63 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var nodeLogsCountChanges = make(chan bool, 1)
|
||||||
|
var ipItemsCountChanges = make(chan bool, 1)
|
||||||
|
|
||||||
|
// 运行日志
|
||||||
|
var countUnreadNodeLogs int64 = 0
|
||||||
|
var nodeLogsType = ""
|
||||||
|
|
||||||
|
// IP名单
|
||||||
|
var countUnreadIPItems int64 = 0
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
events.On(events.EventStart, func() {
|
||||||
|
// 节点日志数量
|
||||||
|
goman.New(func() {
|
||||||
|
for range nodeLogsCountChanges {
|
||||||
|
rpcClient, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
countNodeLogsResp, err := rpcClient.NodeLogRPC().CountNodeLogs(rpcClient.Context(0), &pb.CountNodeLogsRequest{
|
||||||
|
Role: nodeconfigs.NodeRoleNode,
|
||||||
|
IsUnread: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
} else {
|
||||||
|
countUnreadNodeLogs = countNodeLogsResp.Count
|
||||||
|
if countUnreadNodeLogs > 0 {
|
||||||
|
if countUnreadNodeLogs >= 100 {
|
||||||
|
countUnreadNodeLogs = 99
|
||||||
|
}
|
||||||
|
nodeLogsType = "unread"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 服务数量
|
||||||
|
goman.New(func() {
|
||||||
|
for range ipItemsCountChanges {
|
||||||
|
rpcClient, err := rpc.SharedRPC()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
countUnreadIPItemsResp, err := rpcClient.IPItemRPC().CountAllEnabledIPItems(rpcClient.Context(0), &pb.CountAllEnabledIPItemsRequest{Unread: true})
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
} else {
|
||||||
|
countUnreadIPItems = countUnreadIPItemsResp.Count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 认证拦截
|
// 认证拦截
|
||||||
type userMustAuth struct {
|
type userMustAuth struct {
|
||||||
AdminId int64
|
AdminId int64
|
||||||
@@ -81,7 +140,6 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 检查系统是否已经配置过
|
// 检查系统是否已经配置过
|
||||||
if !setup.IsConfigured() {
|
if !setup.IsConfigured() {
|
||||||
action.RedirectURL("/setup")
|
action.RedirectURL("/setup")
|
||||||
@@ -178,44 +236,20 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
|
|||||||
|
|
||||||
// 菜单配置
|
// 菜单配置
|
||||||
func (this *userMustAuth) modules(actionPtr actions.ActionWrapper, adminId int64) []maps.Map {
|
func (this *userMustAuth) modules(actionPtr actions.ActionWrapper, adminId int64) []maps.Map {
|
||||||
// 运行日志
|
|
||||||
var countUnreadNodeLogs int64 = 0
|
|
||||||
var nodeLogsType = ""
|
|
||||||
|
|
||||||
// IP名单
|
|
||||||
var countUnreadIPItems int64 = 0
|
|
||||||
|
|
||||||
// 父级动作
|
// 父级动作
|
||||||
parentAction, ok := actionPtr.(actionutils.ActionInterface)
|
var action = actionPtr.Object()
|
||||||
if ok {
|
|
||||||
var action = actionPtr.Object()
|
|
||||||
|
|
||||||
// 未读日志数
|
// 未读日志数
|
||||||
var mainMenu = action.Data.GetString("teaMenu")
|
var mainMenu = action.Data.GetString("teaMenu")
|
||||||
if mainMenu == "clusters" {
|
if mainMenu == "clusters" {
|
||||||
countNodeLogsResp, err := parentAction.RPC().NodeLogRPC().CountNodeLogs(parentAction.AdminContext(), &pb.CountNodeLogsRequest{
|
select {
|
||||||
Role: nodeconfigs.NodeRoleNode,
|
case nodeLogsCountChanges <- true:
|
||||||
IsUnread: true,
|
default:
|
||||||
})
|
}
|
||||||
if err != nil {
|
} else if mainMenu == "servers" {
|
||||||
logs.Error(err)
|
select {
|
||||||
} else {
|
case ipItemsCountChanges <- true:
|
||||||
var countNodeLogs = countNodeLogsResp.Count
|
default:
|
||||||
if countNodeLogs > 0 {
|
|
||||||
countUnreadNodeLogs = countNodeLogs
|
|
||||||
if countUnreadNodeLogs >= 100 {
|
|
||||||
countUnreadNodeLogs = 99
|
|
||||||
}
|
|
||||||
nodeLogsType = "unread"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if mainMenu == "servers" {
|
|
||||||
countUnreadIPItemsResp, err := parentAction.RPC().IPItemRPC().CountAllEnabledIPItems(parentAction.AdminContext(), &pb.CountAllEnabledIPItemsRequest{Unread: true})
|
|
||||||
if err != nil {
|
|
||||||
logs.Error(err)
|
|
||||||
} else {
|
|
||||||
countUnreadIPItems = countUnreadIPItemsResp.Count
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/location"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/location"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/pages"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/pages"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/remoteAddr"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/remoteAddr"
|
||||||
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/requestLimit"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/reverseProxy"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/reverseProxy"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/rewrite"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/rewrite"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/stat"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/stat"
|
||||||
@@ -114,7 +115,6 @@ import (
|
|||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/backup"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/backup"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/database"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/database"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ip-library"
|
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/login"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/login"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/profile"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/profile"
|
||||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/security"
|
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/security"
|
||||||
|
|||||||
@@ -295,10 +295,20 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
</div>`}),Vue.component("ns-routes-selector",{props:["v-routes"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRoutes;return{routeCode:"default",routes:[],isAdding:!1,routeType:"default",selectedRoutes:e=null==e?[]:e}},watch:{routeType:function(t){this.routeCode="";let i=this;this.routes.forEach(function(e){e.type==t&&0==i.routeCode.length&&(i.routeCode=e.code)})}},methods:{add:function(){this.isAdding=!0,this.routeType="default",this.routeCode="default"},cancel:function(){this.isAdding=!1},confirm:function(){if(0!=this.routeCode.length){let t=this;this.routes.forEach(function(e){e.code==t.routeCode&&t.selectedRoutes.push(e)}),this.cancel()}},remove:function(e){this.selectedRoutes.$remove(e)}},template:`<div>
|
</div>`}),Vue.component("ns-domain-group-selector",{props:["v-domain-group-id"],data:function(){let e=this.vDomainGroupId;return{userId:0,groupId:e=null==e?0:e}},methods:{change:function(e){null!=e?this.$emit("change",e.id):this.$emit("change",0)},reload:function(e){this.userId=e,this.$refs.comboBox.clear(),this.$refs.comboBox.setDataURL("/ns/domains/groups/options?userId="+e),this.$refs.comboBox.reloadData()}},template:`<div>
|
||||||
<div>
|
<combo-box
|
||||||
|
data-url="/ns/domains/groups/options"
|
||||||
|
placeholder="选择分组"
|
||||||
|
data-key="groups"
|
||||||
|
name="groupId"
|
||||||
|
:v-value="groupId"
|
||||||
|
@change="change"
|
||||||
|
ref="comboBox">
|
||||||
|
</combo-box>
|
||||||
|
</div>`}),Vue.component("ns-routes-selector",{props:["v-routes","name"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRoutes,t=(null==e&&(e=[]),this.name);return{routeCode:"default",inputName:t="string"==typeof t&&0!=t.length?t:"routeCodes",routes:[],isAdding:!1,routeType:"default",selectedRoutes:e}},watch:{routeType:function(t){this.routeCode="";let i=this;this.routes.forEach(function(e){e.type==t&&0==i.routeCode.length&&(i.routeCode=e.code)})}},methods:{add:function(){this.isAdding=!0,this.routeType="default",this.routeCode="default",this.$emit("add")},cancel:function(){this.isAdding=!1,this.$emit("cancel")},confirm:function(){if(0!=this.routeCode.length){let t=this;this.routes.forEach(function(e){e.code==t.routeCode&&t.selectedRoutes.push(e)}),this.$emit("change",this.selectedRoutes),this.cancel()}},remove:function(e){this.selectedRoutes.$remove(e),this.$emit("change",this.selectedRoutes)}},template:`<div>
|
||||||
|
<div v-show="selectedRoutes.length > 0">
|
||||||
<div class="ui label basic text small" v-for="(route, index) in selectedRoutes" style="margin-bottom: 0.3em">
|
<div class="ui label basic text small" v-for="(route, index) in selectedRoutes" style="margin-bottom: 0.3em">
|
||||||
<input type="hidden" name="routeCodes" :value="route.code"/>
|
<input type="hidden" :name="inputName" :value="route.code"/>
|
||||||
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
@@ -603,6 +613,46 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<button class="ui button tiny" type="button" @click.prevent="addRegions">添加区域</button>
|
<button class="ui button tiny" type="button" @click.prevent="addRegions">添加区域</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>`}),Vue.component("ns-create-records-table",{props:["v-types"],data:function(){let e=this.vTypes;return{types:e=null==e?[]:e,records:[{name:"",type:"A",value:"",routeCodes:[],ttl:600,index:0}],lastIndex:0,isAddingRoutes:!1}},methods:{add:function(){this.records.push({name:"",type:"A",value:"",routeCodes:[],ttl:600,index:++this.lastIndex});let e=this;setTimeout(function(){e.$refs.nameInputs.$last().focus()},100)},remove:function(e){this.records.$remove(e)},addRoutes:function(){this.isAddingRoutes=!0},cancelRoutes:function(){let e=this;setTimeout(function(){e.isAddingRoutes=!1},1e3)},changeRoutes:function(e,t){e.routeCodes=null==t?[]:t.map(function(e){return e.code})}},template:`<div>
|
||||||
|
<input type="hidden" name="recordsJSON" :value="JSON.stringify(records)"/>
|
||||||
|
<table class="ui table selectable celled" style="max-width: 60em">
|
||||||
|
<thead class="full-width">
|
||||||
|
<tr>
|
||||||
|
<th style="width:10em">记录名</th>
|
||||||
|
<th style="width:7em">记录类型</th>
|
||||||
|
<th>线路</th>
|
||||||
|
<th v-if="!isAddingRoutes">记录值</th>
|
||||||
|
<th v-if="!isAddingRoutes">TTL</th>
|
||||||
|
<th class="one op" v-if="!isAddingRoutes">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="(record, index) in records" :key="record.index">
|
||||||
|
<td>
|
||||||
|
<input type="text" style="width:10em" v-model="record.name" ref="nameInputs"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" v-model="record.type">
|
||||||
|
<option v-for="type in types" :value="type.type">{{type.type}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ns-routes-selector @add="addRoutes" @cancel="cancelRoutes" @change="changeRoutes(record, $event)"></ns-routes-selector>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<input type="text" style="width:10em" maxlength="512" v-model="record.value"/>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" v-model="record.ttl" style="width:5em" maxlength="8"/>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove"></i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
|
||||||
</div>`}),Vue.component("ns-route-selector",{props:["v-route-code"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRouteCode;return{routeCode:e=null==e?"":e,routes:[]}},template:`<div>
|
</div>`}),Vue.component("ns-route-selector",{props:["v-route-code"],mounted:function(){let t=this;Tea.action("/ns/routes/options").post().success(function(e){t.routes=e.data.routes})},data:function(){let e=this.vRouteCode;return{routeCode:e=null==e?"":e,routes:[]}},template:`<div>
|
||||||
<div v-if="routes.length > 0">
|
<div v-if="routes.length > 0">
|
||||||
<select class="ui dropdown" name="routeCode" v-model="routeCode">
|
<select class="ui dropdown" name="routeCode" v-model="routeCode">
|
||||||
@@ -610,13 +660,15 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<option v-for="route in routes" :value="route.code">{{route.name}}</option>
|
<option v-for="route in routes" :value="route.code">{{route.name}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>`}),Vue.component("ns-user-selector",{mounted:function(){let t=this;Tea.action("/ns/users/options").post().success(function(e){t.users=e.data.users})},props:["v-user-id"],data:function(){let e=this.vUserId;return{users:[],userId:e=null==e?0:e}},template:`<div>
|
</div>`}),Vue.component("ns-user-selector",{props:["v-user-id"],data:function(){return{}},methods:{change:function(e){this.$emit("change",e)}},template:`<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/ns/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`}),Vue.component("ns-access-log-box",{props:["v-access-log","v-keyword"],data:function(){return{accessLog:this.vAccessLog}},methods:{showLog:function(){let e=this;var t=this.accessLog.requestId;this.$parent.$children.forEach(function(e){null!=e.deselect&&e.deselect()}),this.select(),teaweb.popup("/ns/clusters/accessLogs/viewPopup?requestId="+t,{width:"50em",height:"24em",onClose:function(){e.deselect()}})},select:function(){this.$refs.box.parentNode.style.cssText="background: rgba(0, 0, 0, 0.1)"},deselect:function(){this.$refs.box.parentNode.style.cssText=""}},template:`<div class="access-log-row" :style="{'color': (!accessLog.isRecursive && (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) || (accessLog.isRecursive && accessLog.recordValue != null && accessLog.recordValue.length == 0)) ? '#dc143c' : ''}" ref="box">
|
</div>`}),Vue.component("ns-access-log-box",{props:["v-access-log","v-keyword"],data:function(){return{accessLog:this.vAccessLog}},methods:{showLog:function(){let e=this;var t=this.accessLog.requestId;this.$parent.$children.forEach(function(e){null!=e.deselect&&e.deselect()}),this.select(),teaweb.popup("/ns/clusters/accessLogs/viewPopup?requestId="+t,{width:"50em",height:"24em",onClose:function(){e.deselect()}})},select:function(){this.$refs.box.parentNode.style.cssText="background: rgba(0, 0, 0, 0.1)"},deselect:function(){this.$refs.box.parentNode.style.cssText=""}},template:`<div class="access-log-row" :style="{'color': (!accessLog.isRecursive && (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) || (accessLog.isRecursive && accessLog.recordValue != null && accessLog.recordValue.length == 0)) ? '#dc143c' : ''}" ref="box">
|
||||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> -> <em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em><!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> ->
|
||||||
|
|
||||||
|
<span v-if="accessLog.recordType != null && accessLog.recordType.length > 0"><em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em></span>
|
||||||
|
<span v-else class="disabled"> [没有记录]</span>
|
||||||
|
|
||||||
|
<!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
||||||
<div v-if="(accessLog.nsRoutes != null && accessLog.nsRoutes.length > 0) || accessLog.isRecursive" style="margin-top: 0.3em">
|
<div v-if="(accessLog.nsRoutes != null && accessLog.nsRoutes.length > 0) || accessLog.isRecursive" style="margin-top: 0.3em">
|
||||||
<span class="ui label tiny basic grey" v-for="route in accessLog.nsRoutes">线路: {{route.name}}</span>
|
<span class="ui label tiny basic grey" v-for="route in accessLog.nsRoutes">线路: {{route.name}}</span>
|
||||||
<span class="ui label tiny basic grey" v-if="accessLog.isRecursive">递归DNS</span>
|
<span class="ui label tiny basic grey" v-if="accessLog.isRecursive">递归DNS</span>
|
||||||
@@ -629,11 +681,10 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<option value="0">[选择集群]</option>
|
<option value="0">[选择集群]</option>
|
||||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>`}),Vue.component("plan-user-selector",{mounted:function(){let t=this;Tea.action("/plans/users/options").post().success(function(e){t.users=e.data.users})},props:["v-user-id"],data:function(){let e=this.vUserId;return{users:[],userId:e=null==e?0:e}},watch:{userId:function(e){this.$emit("change",e)}},template:`<div>
|
</div>`}),Vue.component("ns-cluster-combo-box",{props:["v-cluster-id"],data:function(){let t=this;return Tea.action("/ns/clusters/options").post().success(function(e){t.clusters=e.data.clusters}),{clusters:[]}},methods:{change:function(e){null==e?this.$emit("change",0):this.$emit("change",e.value)}},template:`<div v-if="clusters.length > 0" style="min-width: 10.4em">
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<combo-box title="集群" placeholder="集群名称" :v-items="clusters" name="clusterId" :v-value="vClusterId" @change="change"></combo-box>
|
||||||
<option value="0">[选择用户]</option>
|
</div>`}),Vue.component("plan-user-selector",{props:["v-user-id"],data:function(){return{}},methods:{change:function(e){this.$emit("change",e)}},template:`<div>
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
<user-selector :v-user-id="vUserId" data-url="/plans/users/options" @change="change"></user-selector>
|
||||||
</select>
|
|
||||||
</div>`}),Vue.component("plan-price-view",{props:["v-plan"],data:function(){return{plan:this.vPlan}},template:`<div>
|
</div>`}),Vue.component("plan-price-view",{props:["v-plan"],data:function(){return{plan:this.vPlan}},template:`<div>
|
||||||
<span v-if="plan.priceType == 'period'">
|
<span v-if="plan.priceType == 'period'">
|
||||||
按时间周期计费
|
按时间周期计费
|
||||||
@@ -720,7 +771,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<div v-if="!isAdding">
|
<div v-if="!isAdding">
|
||||||
<button class="ui button small" type="button" @click.prevent="add">+</button>
|
<button class="ui button small" type="button" @click.prevent="add">+</button>
|
||||||
</div>
|
</div>
|
||||||
</div>`}),Vue.component("plan-price-config-box",{props:["v-price-type","v-monthly-price","v-seasonally-price","v-yearly-price","v-traffic-price","v-bandwidth-price","v-disable-period"],data:function(){let e=this.vPriceType,t=(null==e&&(e="bandwidth"),0),i=this.vMonthlyPrice,s=(null==i||i<=0?i="":(i=i.toString(),t=parseFloat(i),isNaN(t)&&(t=0)),0),n=this.vSeasonallyPrice,o=(null==n||n<=0?n="":(n=n.toString(),s=parseFloat(n),isNaN(s)&&(s=0)),0),a=this.vYearlyPrice,l=(null==a||a<=0?a="":(a=a.toString(),o=parseFloat(a),isNaN(o)&&(o=0)),this.vTrafficPrice),r=0,c=(null!=l?r=l.base:l={base:0},""),d=(0<r&&(c=r.toString()),this.vBandwidthPrice);return null==d?d={percentile:95,ranges:[]}:null==d.ranges&&(d.ranges=[]),{priceType:e,monthlyPrice:i,seasonallyPrice:n,yearlyPrice:a,monthlyPriceNumber:t,seasonallyPriceNumber:s,yearlyPriceNumber:o,trafficPriceBase:c,trafficPrice:l,bandwidthPrice:d,bandwidthPercentile:d.percentile}},methods:{changeBandwidthPriceRanges:function(e){this.bandwidthPrice.ranges=e}},watch:{monthlyPrice:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.monthlyPriceNumber=t},seasonallyPrice:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.seasonallyPriceNumber=t},yearlyPrice:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.yearlyPriceNumber=t},trafficPriceBase:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.trafficPrice.base=t},bandwidthPercentile:function(e){let t=parseInt(e);isNaN(t)||t<=0?t=95:100<t&&(t=100),this.bandwidthPrice.percentile=t}},template:`<div>
|
</div>`}),Vue.component("plan-price-config-box",{props:["v-price-type","v-monthly-price","v-seasonally-price","v-yearly-price","v-traffic-price","v-bandwidth-price","v-disable-period"],data:function(){let e=this.vPriceType,t=(null==e&&(e="bandwidth"),0),i=this.vMonthlyPrice,s=(null==i||i<=0?i="":(i=i.toString(),t=parseFloat(i),isNaN(t)&&(t=0)),0),n=this.vSeasonallyPrice,o=(null==n||n<=0?n="":(n=n.toString(),s=parseFloat(n),isNaN(s)&&(s=0)),0),a=this.vYearlyPrice,l=(null==a||a<=0?a="":(a=a.toString(),o=parseFloat(a),isNaN(o)&&(o=0)),this.vTrafficPrice),c=0,r=(null!=l?c=l.base:l={base:0},""),d=(0<c&&(r=c.toString()),this.vBandwidthPrice);return null==d?d={percentile:95,ranges:[]}:null==d.ranges&&(d.ranges=[]),{priceType:e,monthlyPrice:i,seasonallyPrice:n,yearlyPrice:a,monthlyPriceNumber:t,seasonallyPriceNumber:s,yearlyPriceNumber:o,trafficPriceBase:r,trafficPrice:l,bandwidthPrice:d,bandwidthPercentile:d.percentile}},methods:{changeBandwidthPriceRanges:function(e){this.bandwidthPrice.ranges=e}},watch:{monthlyPrice:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.monthlyPriceNumber=t},seasonallyPrice:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.seasonallyPriceNumber=t},yearlyPrice:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.yearlyPriceNumber=t},trafficPriceBase:function(e){let t=parseFloat(e);isNaN(t)&&(t=0),this.trafficPrice.base=t},bandwidthPercentile:function(e){let t=parseInt(e);isNaN(t)||t<=0?t=95:100<t&&(t=100),this.bandwidthPrice.percentile=t}},template:`<div>
|
||||||
<input type="hidden" name="priceType" :value="priceType"/>
|
<input type="hidden" name="priceType" :value="priceType"/>
|
||||||
<input type="hidden" name="monthlyPrice" :value="monthlyPriceNumber"/>
|
<input type="hidden" name="monthlyPrice" :value="monthlyPriceNumber"/>
|
||||||
<input type="hidden" name="seasonallyPrice" :value="seasonallyPriceNumber"/>
|
<input type="hidden" name="seasonallyPrice" :value="seasonallyPriceNumber"/>
|
||||||
@@ -1133,6 +1184,8 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
||||||
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
||||||
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfNoneMatch">If-None-Match</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfModifiedSince">If-Modified-Since</grey-label>
|
||||||
</td>
|
</td>
|
||||||
<td :class="{disabled: !cacheRef.isOn}">
|
<td :class="{disabled: !cacheRef.isOn}">
|
||||||
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
||||||
@@ -1218,7 +1271,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<p class="comment" v-if="redirects.length > 1">所有规则匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。</p>
|
<p class="comment" v-if="redirects.length > 1">所有规则匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
</div>`}),Vue.component("http-cache-ref-box",{props:["v-cache-ref","v-is-reverse"],mounted:function(){this.$refs.variablesDescriber.update(this.ref.key)},data:function(){let e=this.vCacheRef;return null==(e=null==e?{isOn:!0,cachePolicyId:0,key:"${scheme}://${host}${requestPath}${isArgs}${args}",life:{count:2,unit:"hour"},status:[200],maxSize:{count:32,unit:"mb"},minSize:{count:0,unit:"kb"},skipCacheControlValues:["private","no-cache","no-store"],skipSetCookie:!0,enableRequestCachePragma:!1,conds:null,allowChunkedEncoding:!0,allowPartialContent:!1,isReverse:this.vIsReverse,methods:[],expiresTime:{isPrior:!1,isOn:!1,overwrite:!0,autoCalculate:!0,duration:{count:-1,unit:"hour"}}}:e).key&&(e.key=""),null==e.methods&&(e.methods=[]),null==e.life&&(e.life={count:2,unit:"hour"}),null==e.maxSize&&(e.maxSize={count:32,unit:"mb"}),null==e.minSize&&(e.minSize={count:0,unit:"kb"}),{ref:e,moreOptionsVisible:!1}},methods:{changeOptionsVisible:function(e){this.moreOptionsVisible=e},changeLife:function(e){this.ref.life=e},changeMaxSize:function(e){this.ref.maxSize=e},changeMinSize:function(e){this.ref.minSize=e},changeConds:function(e){this.ref.conds=e},changeStatusList:function(e){let t=[];e.forEach(function(e){e=parseInt(e);isNaN(e)||e<100||999<e||t.push(e)}),this.ref.status=t},changeMethods:function(e){this.ref.methods=e.map(function(e){return e.toUpperCase()})},changeKey:function(e){this.$refs.variablesDescriber.update(e)},changeExpiresTime:function(e){this.ref.expiresTime=e}},template:`<tbody>
|
</div>`}),Vue.component("http-cache-ref-box",{props:["v-cache-ref","v-is-reverse"],mounted:function(){this.$refs.variablesDescriber.update(this.ref.key)},data:function(){let e=this.vCacheRef;return null==(e=null==e?{isOn:!0,cachePolicyId:0,key:"${scheme}://${host}${requestPath}${isArgs}${args}",life:{count:2,unit:"hour"},status:[200],maxSize:{count:32,unit:"mb"},minSize:{count:0,unit:"kb"},skipCacheControlValues:["private","no-cache","no-store"],skipSetCookie:!0,enableRequestCachePragma:!1,conds:null,allowChunkedEncoding:!0,allowPartialContent:!1,enableIfNoneMatch:!1,enableIfModifiedSince:!1,isReverse:this.vIsReverse,methods:[],expiresTime:{isPrior:!1,isOn:!1,overwrite:!0,autoCalculate:!0,duration:{count:-1,unit:"hour"}}}:e).key&&(e.key=""),null==e.methods&&(e.methods=[]),null==e.life&&(e.life={count:2,unit:"hour"}),null==e.maxSize&&(e.maxSize={count:32,unit:"mb"}),null==e.minSize&&(e.minSize={count:0,unit:"kb"}),{ref:e,moreOptionsVisible:!1}},methods:{changeOptionsVisible:function(e){this.moreOptionsVisible=e},changeLife:function(e){this.ref.life=e},changeMaxSize:function(e){this.ref.maxSize=e},changeMinSize:function(e){this.ref.minSize=e},changeConds:function(e){this.ref.conds=e},changeStatusList:function(e){let t=[];e.forEach(function(e){e=parseInt(e);isNaN(e)||e<100||999<e||t.push(e)}),this.ref.status=t},changeMethods:function(e){this.ref.methods=e.map(function(e){return e.toUpperCase()})},changeKey:function(e){this.$refs.variablesDescriber.update(e)},changeExpiresTime:function(e){this.ref.expiresTime=e}},template:`<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">匹配条件分组 *</td>
|
<td class="title">匹配条件分组 *</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -1318,13 +1371,27 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||||
|
<td>允许If-None-Match回源</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="ref.enableIfNoneMatch"></checkbox>
|
||||||
|
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||||
|
<td>允许If-Modified-Since回源</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="ref.enableIfModifiedSince"></checkbox>
|
||||||
|
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>`}),Vue.component("http-request-limit-config-box",{props:["v-request-limit-config","v-is-group","v-is-location"],data:function(){let e=this.vRequestLimitConfig;return{config:e=null==e?{isPrior:!1,isOn:!1,maxConns:0,maxConnsPerIP:0,maxBodySize:{count:-1,unit:"kb"},outBandwidthPerConn:{count:-1,unit:"kb"}}:e,maxConns:e.maxConns,maxConnsPerIP:e.maxConnsPerIP}},watch:{maxConns:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConns=0:this.config.maxConns=e<0?0:e},maxConnsPerIP:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConnsPerIP=0:this.config.maxConnsPerIP=e<0?0:e}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`<div>
|
</tbody>`}),Vue.component("http-request-limit-config-box",{props:["v-request-limit-config","v-is-group","v-is-location"],data:function(){let e=this.vRequestLimitConfig;return{config:e=null==e?{isPrior:!1,isOn:!1,maxConns:0,maxConnsPerIP:0,maxBodySize:{count:-1,unit:"kb"},outBandwidthPerConn:{count:-1,unit:"kb"}}:e,maxConns:e.maxConns,maxConnsPerIP:e.maxConnsPerIP}},watch:{maxConns:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConns=0:this.config.maxConns=e<0?0:e},maxConnsPerIP:function(e){e=parseInt(e,10);isNaN(e)?this.config.maxConnsPerIP=0:this.config.maxConnsPerIP=e<0?0:e}},methods:{isOn:function(){return(!this.vIsLocation&&!this.vIsGroup||this.config.isPrior)&&this.config.isOn}},template:`<div>
|
||||||
<input type="hidden" name="requestLimitJSON" :value="JSON.stringify(config)"/>
|
<input type="hidden" name="requestLimitJSON" :value="JSON.stringify(config)"/>
|
||||||
<table class="ui table selectable definition">
|
<table class="ui table selectable definition">
|
||||||
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">是否启用</td>
|
<td class="title">启用</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox v-model="config.isOn"></checkbox>
|
<checkbox v-model="config.isOn"></checkbox>
|
||||||
</td>
|
</td>
|
||||||
@@ -1335,14 +1402,14 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<td>最大并发连接数</td>
|
<td>最大并发连接数</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" maxlength="6" v-model="maxConns"/>
|
<input type="text" maxlength="6" v-model="maxConns"/>
|
||||||
<p class="comment">当前服务最大并发连接数。为0表示不限制。</p>
|
<p class="comment">当前服务最大并发连接数,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>单IP最大并发连接数</td>
|
<td>单IP最大并发连接数</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
||||||
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务。为0表示不限制。</p>
|
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -1590,7 +1657,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<td>忽略常见文件</td>
|
<td>忽略常见文件</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox v-model="ignoreCommonFiles"></checkbox>
|
<checkbox v-model="ignoreCommonFiles"></checkbox>
|
||||||
<p class="comment">忽略js、css、jpg等常见文件名。</p>
|
<p class="comment">忽略js、css、jpg等常见在网页里被引用的文件名。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -1655,6 +1722,8 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
||||||
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
||||||
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfNoneMatch">If-None-Match</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfModifiedSince">If-Modified-Since</grey-label>
|
||||||
</td>
|
</td>
|
||||||
<td :class="{disabled: !cacheRef.isOn}">
|
<td :class="{disabled: !cacheRef.isOn}">
|
||||||
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
||||||
@@ -1696,7 +1765,8 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="origin in vOrigins">
|
<tr v-for="origin in vOrigins">
|
||||||
<td :class="{disabled:!origin.isOn}"><a href="" @click.prevent="updateOrigin(origin.id)">{{origin.addr}} <i class="icon expand small"></i></a>
|
<td :class="{disabled:!origin.isOn}">
|
||||||
|
<a href="" @click.prevent="updateOrigin(origin.id)" :class="{disabled:!origin.isOn}">{{origin.addr}} <i class="icon expand small"></i></a>
|
||||||
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || origin.followPort || (origin.domains != null && origin.domains.length > 0)">
|
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || origin.followPort || (origin.domains != null && origin.domains.length > 0)">
|
||||||
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
|
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
|
||||||
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
|
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
|
||||||
@@ -2323,11 +2393,8 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<button class="ui button small" type="button" @click.prevent="add">+添加认证方式</button>
|
<button class="ui button small" type="button" @click.prevent="add">+添加认证方式</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
</div>`}),Vue.component("user-selector",{mounted:function(){let t=this;Tea.action("/servers/users/options").post().success(function(e){t.users=e.data.users})},props:["v-user-id"],data:function(){let e=this.vUserId;return{users:[],userId:e=null==e?0:e}},watch:{userId:function(e){this.$emit("change",e)}},template:`<div>
|
</div>`}),Vue.component("user-selector",{props:["v-user-id","data-url"],data:function(){let e=this.vUserId,t=(null==e&&(e=0),this.dataUrl);return null!=t&&0!=t.length||(t="/servers/users/options"),{users:[],userId:e,dataURL:t}},methods:{change:function(e){null!=e?this.$emit("change",e.id):this.$emit("change",0)}},template:`<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<combo-box placeholder="选择用户" :data-url="dataURL" :data-key="'users'" data-search="on" name="userId" :v-value="userId" @change="change"></combo-box>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`}),Vue.component("uam-config-box",{props:["v-uam-config","v-is-location","v-is-group"],data:function(){let e=this.vUamConfig;return{config:e=null==e?{isPrior:!1,isOn:!1}:e}},template:`<div>
|
</div>`}),Vue.component("uam-config-box",{props:["v-uam-config","v-is-location","v-is-group"],data:function(){let e=this.vUamConfig;return{config:e=null==e?{isPrior:!1,isOn:!1}:e}},template:`<div>
|
||||||
<input type="hidden" name="uamJSON" :value="JSON.stringify(config)"/>
|
<input type="hidden" name="uamJSON" :value="JSON.stringify(config)"/>
|
||||||
<table class="ui table definition selectable">
|
<table class="ui table definition selectable">
|
||||||
@@ -2957,6 +3024,12 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<!-- 请求脚本 -->
|
<!-- 请求脚本 -->
|
||||||
<http-location-labels-label v-if="location.web != null && location.web.requestScripts != null && ((location.web.requestScripts.initGroup != null && location.web.requestScripts.initGroup.isPrior) || (location.web.requestScripts.requestGroup != null && location.web.requestScripts.requestGroup.isPrior))" :href="url('/requestScripts')">请求脚本</http-location-labels-label>
|
<http-location-labels-label v-if="location.web != null && location.web.requestScripts != null && ((location.web.requestScripts.initGroup != null && location.web.requestScripts.initGroup.isPrior) || (location.web.requestScripts.requestGroup != null && location.web.requestScripts.requestGroup.isPrior))" :href="url('/requestScripts')">请求脚本</http-location-labels-label>
|
||||||
|
|
||||||
|
<!-- 自定义访客IP地址 -->
|
||||||
|
<http-location-labels-label v-if="location.web != null && location.web.remoteAddr != null && location.web.remoteAddr.isPrior" :href="url('/remoteAddr')" :class="{disabled: !location.web.remoteAddr.isOn}">访客IP地址</http-location-labels-label>
|
||||||
|
|
||||||
|
<!-- 请求限制 -->
|
||||||
|
<http-location-labels-label v-if="location.web != null && location.web.requestLimit != null && location.web.requestLimit.isPrior" :href="url('/requestLimit')" :class="{disabled: !location.web.requestLimit.isOn}">请求限制</http-location-labels-label>
|
||||||
|
|
||||||
<!-- 自定义页面 -->
|
<!-- 自定义页面 -->
|
||||||
<div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0">
|
<div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0">
|
||||||
<div v-for="page in location.web.pages" :key="page.id"><http-location-labels-label :href="url('/pages')">PAGE [状态码{{page.status[0]}}] -> {{page.url}}</http-location-labels-label></div>
|
<div v-for="page in location.web.pages" :key="page.id"><http-location-labels-label :href="url('/pages')">PAGE [状态码{{page.status[0]}}] -> {{page.url}}</http-location-labels-label></div>
|
||||||
@@ -4229,7 +4302,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
</div>
|
</div>
|
||||||
</div>`}),Vue.component("page-box",{data:function(){return{page:""}},created:function(){let e=this;setTimeout(function(){e.page=Tea.Vue.page})},template:`<div>
|
</div>`}),Vue.component("page-box",{data:function(){return{page:""}},created:function(){let e=this;setTimeout(function(){e.page=Tea.Vue.page})},template:`<div>
|
||||||
<div class="page" v-html="page"></div>
|
<div class="page" v-html="page"></div>
|
||||||
</div>`}),Vue.component("network-addresses-box",{props:["v-server-type","v-addresses","v-protocol","v-name","v-from","v-support-range"],data:function(){let e=this.vAddresses,t=(null==e&&(e=[]),this.vProtocol),i=(null==t&&(t=""),this.vName),s=(null==i&&(i="addresses"),this.vFrom);return null==s&&(s=""),{addresses:e,protocol:t,name:i,from:s}},watch:{vServerType:function(){this.addresses=[]},vAddresses:function(){null!=this.vAddresses&&(this.addresses=this.vAddresses)}},methods:{addAddr:function(){let t=this;window.UPDATING_ADDR=null,teaweb.popup("/servers/addPortPopup?serverType="+this.vServerType+"&protocol="+this.protocol+"&from="+this.from+"&supportRange="+(this.supportRange()?1:0),{height:"18em",callback:function(e){var i=e.data.address;null!=t.addresses.$find(function(e,t){return i.host==t.host&&i.portRange==t.portRange&&i.protocol==t.protocol})?teaweb.warn("要添加的网络地址已经存在"):(t.addresses.push(i),["https","https4","https6"].$contains(i.protocol)?this.tlsProtocolName="HTTPS":["tls","tls4","tls6"].$contains(i.protocol)&&(this.tlsProtocolName="TLS"),t.$emit("change",t.addresses))}})},removeAddr:function(e){this.addresses.$remove(e),this.$emit("change",this.addresses)},updateAddr:function(t,e){let i=this;window.UPDATING_ADDR=e,teaweb.popup("/servers/addPortPopup?serverType="+this.vServerType+"&protocol="+this.protocol+"&from="+this.from+"&supportRange="+(this.supportRange()?1:0),{height:"18em",callback:function(e){e=e.data.address;Vue.set(i.addresses,t,e),["https","https4","https6"].$contains(e.protocol)?this.tlsProtocolName="HTTPS":["tls","tls4","tls6"].$contains(e.protocol)&&(this.tlsProtocolName="TLS"),i.$emit("change",i.addresses)}}),this.$emit("change",this.addresses)},supportRange:function(){return this.vSupportRange||"tcpProxy"==this.vServerType||"udpProxy"==this.vServerType}},template:`<div>
|
</div>`}),Vue.component("network-addresses-box",{props:["v-server-type","v-addresses","v-protocol","v-name","v-from","v-support-range","v-url"],data:function(){let e=this.vAddresses,t=(null==e&&(e=[]),this.vProtocol),i=(null==t&&(t=""),this.vName),s=(null==i&&(i="addresses"),this.vFrom);return null==s&&(s=""),{addresses:e,protocol:t,name:i,from:s}},watch:{vServerType:function(){this.addresses=[]},vAddresses:function(){null!=this.vAddresses&&(this.addresses=this.vAddresses)}},methods:{addAddr:function(){let t=this,e=(window.UPDATING_ADDR=null,this.vUrl);null==e&&(e="/servers/addPortPopup"),teaweb.popup(e+"?serverType="+this.vServerType+"&protocol="+this.protocol+"&from="+this.from+"&supportRange="+(this.supportRange()?1:0),{height:"18em",callback:function(e){var i=e.data.address;null!=t.addresses.$find(function(e,t){return i.host==t.host&&i.portRange==t.portRange&&i.protocol==t.protocol})?teaweb.warn("要添加的网络地址已经存在"):(t.addresses.push(i),["https","https4","https6"].$contains(i.protocol)?this.tlsProtocolName="HTTPS":["tls","tls4","tls6"].$contains(i.protocol)&&(this.tlsProtocolName="TLS"),t.$emit("change",t.addresses))}})},removeAddr:function(e){this.addresses.$remove(e),this.$emit("change",this.addresses)},updateAddr:function(t,e){let i=this,s=(window.UPDATING_ADDR=e,this.vUrl);null==s&&(s="/servers/addPortPopup"),teaweb.popup(s+"?serverType="+this.vServerType+"&protocol="+this.protocol+"&from="+this.from+"&supportRange="+(this.supportRange()?1:0),{height:"18em",callback:function(e){e=e.data.address;Vue.set(i.addresses,t,e),["https","https4","https6"].$contains(e.protocol)?this.tlsProtocolName="HTTPS":["tls","tls4","tls6"].$contains(e.protocol)&&(this.tlsProtocolName="TLS"),i.$emit("change",i.addresses)}}),this.$emit("change",this.addresses)},supportRange:function(){return this.vSupportRange||"tcpProxy"==this.vServerType||"udpProxy"==this.vServerType}},template:`<div>
|
||||||
<input type="hidden" :name="name" :value="JSON.stringify(addresses)"/>
|
<input type="hidden" :name="name" :value="JSON.stringify(addresses)"/>
|
||||||
<div v-if="addresses.length > 0">
|
<div v-if="addresses.length > 0">
|
||||||
<div class="ui label small basic" v-for="(addr, index) in addresses">
|
<div class="ui label small basic" v-for="(addr, index) in addresses">
|
||||||
@@ -4252,14 +4325,14 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><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></td>
|
<td colspan="2"><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></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>`}),Vue.component("download-link",{props:["v-element","v-file","v-value"],created:function(){let e=this;setTimeout(function(){e.url=e.composeURL()},1e3)},data:function(){let e=this.vFile;return{file:e=null!=e&&0!=e.length?e:"unknown-file",url:this.composeURL()}},methods:{composeURL:function(){let e="";if(null!=this.vValue)e=this.vValue;else{var t=document.getElementById(this.vElement);if(null==t)return void teaweb.warn("找不到要下载的内容");null==(e=t.innerText)&&(e=t.textContent)}return Tea.url("/ui/download",{file:this.file,text:e})}},template:'<a :href="url" target="_blank" style="font-weight: normal"><slot></slot></a>'}),Vue.component("values-box",{props:["values","size","maxlength","name","placeholder"],data:function(){let e=this.values;return{vValues:e=null==e?[]:e,isUpdating:!1,isAdding:!1,index:0,value:"",isEditing:!1}},methods:{create:function(){this.isAdding=!0;var e=this;setTimeout(function(){e.$refs.value.focus()},200)},update:function(e){this.cancel(),this.isUpdating=!0,this.index=e,this.value=this.vValues[e];var t=this;setTimeout(function(){t.$refs.value.focus()},200)},confirm:function(){0!=this.value.length&&(this.isUpdating?Vue.set(this.vValues,this.index,this.value):this.vValues.push(this.value),this.cancel(),this.$emit("change",this.vValues))},remove:function(e){this.vValues.$remove(e),this.$emit("change",this.vValues)},cancel:function(){this.isUpdating=!1,this.isAdding=!1,this.value=""},updateAll:function(e){this.vValeus=e},addValue:function(e){this.vValues.push(e)},startEditing:function(){this.isEditing=!this.isEditing}},template:`<div>
|
</tbody>`}),Vue.component("download-link",{props:["v-element","v-file","v-value"],created:function(){let e=this;setTimeout(function(){e.url=e.composeURL()},1e3)},data:function(){let e=this.vFile;return{file:e=null!=e&&0!=e.length?e:"unknown-file",url:this.composeURL()}},methods:{composeURL:function(){let e="";if(null!=this.vValue)e=this.vValue;else{var t=document.getElementById(this.vElement);if(null==t)return void teaweb.warn("找不到要下载的内容");null==(e=t.innerText)&&(e=t.textContent)}return Tea.url("/ui/download",{file:this.file,text:e})}},template:'<a :href="url" target="_blank" style="font-weight: normal"><slot></slot></a>'}),Vue.component("values-box",{props:["values","v-values","size","maxlength","name","placeholder"],data:function(){let e=this.values;return null==e&&(e=[]),{realValues:e=null!=this.vValues&&"object"==typeof this.vValues?this.vValues:e,isUpdating:!1,isAdding:!1,index:0,value:"",isEditing:!1}},methods:{create:function(){this.isAdding=!0;var e=this;setTimeout(function(){e.$refs.value.focus()},200)},update:function(e){this.cancel(),this.isUpdating=!0,this.index=e,this.value=this.realValues[e];var t=this;setTimeout(function(){t.$refs.value.focus()},200)},confirm:function(){0!=this.value.length&&(this.isUpdating?Vue.set(this.realValues,this.index,this.value):this.realValues.push(this.value),this.cancel(),this.$emit("change",this.realValues))},remove:function(e){this.realValues.$remove(e),this.$emit("change",this.realValues)},cancel:function(){this.isUpdating=!1,this.isAdding=!1,this.value=""},updateAll:function(e){this.realValues=e},addValue:function(e){this.realValues.push(e)},startEditing:function(){this.isEditing=!this.isEditing}},template:`<div>
|
||||||
<div v-show="!isEditing && vValues.length > 0">
|
<div v-show="!isEditing && realValues.length > 0">
|
||||||
<div class="ui label tiny basic" v-for="(value, index) in vValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}</div>
|
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}</div>
|
||||||
<a href="" @click.prevent="startEditing" style="font-size: 0.8em; margin-left: 0.2em">[修改]</a>
|
<a href="" @click.prevent="startEditing" style="font-size: 0.8em; margin-left: 0.2em">[修改]</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isEditing || vValues.length == 0">
|
<div v-show="isEditing || realValues.length == 0">
|
||||||
<div style="margin-bottom: 1em" v-if="vValues.length > 0">
|
<div style="margin-bottom: 1em" v-if="realValues.length > 0">
|
||||||
<div class="ui label tiny basic" v-for="(value, index) in vValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}
|
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}
|
||||||
<input type="hidden" :name="name" :value="value"/>
|
<input type="hidden" :name="name" :value="value"/>
|
||||||
<a href="" @click.prevent="update(index)" title="修改"><i class="icon pencil small" ></i></a>
|
<a href="" @click.prevent="update(index)" title="修改"><i class="icon pencil small" ></i></a>
|
||||||
<a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
<a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
||||||
@@ -4450,7 +4523,7 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
<div class="margin"></div>
|
<div class="margin"></div>
|
||||||
</div>`}),Vue.component("request-variables-describer",{data:function(){return{vars:[]}},methods:{update:function(e){this.vars=[];let i=this;e.replace(/\${.+?}/g,function(e){var t=i.findVar(e);if(null==t)return e;i.vars.push(t)})},findVar:function(t){let i=null;return window.REQUEST_VARIABLES.forEach(function(e){e.code==t&&(i=e)}),i}},template:`<span>
|
</div>`}),Vue.component("request-variables-describer",{data:function(){return{vars:[]}},methods:{update:function(e){this.vars=[];let i=this;e.replace(/\${.+?}/g,function(e){var t=i.findVar(e);if(null==t)return e;i.vars.push(t)})},findVar:function(t){let i=null;return window.REQUEST_VARIABLES.forEach(function(e){e.code==t&&(i=e)}),i}},template:`<span>
|
||||||
<span v-for="(v, index) in vars"><code-label :title="v.description">{{v.code}}</code-label> - {{v.name}}<span v-if="index < vars.length-1">;</span></span>
|
<span v-for="(v, index) in vars"><code-label :title="v.description">{{v.code}}</code-label> - {{v.name}}<span v-if="index < vars.length-1">;</span></span>
|
||||||
</span>`}),Vue.component("combo-box",{props:["name","title","placeholder","size","v-items","v-value","data-url","data-key","width"],mounted:function(){var e=this.dataUrl;let i=this.dataKey,s=this;null!=e&&0<e.length&&null!=i&&Tea.action(e).post().success(function(t){if(null!=t.data&&"object"==typeof t.data[i]){let e=s.formatItems(t.data[i]);s.allItems=e,s.items=e.$copy(),null!=s.vValue&&e.forEach(function(e){e.value==s.vValue&&(s.selectedItem=e)})}});var e=this.$refs.searchBox;null!=e&&(null!=(e=e.offsetWidth)&&0<e?this.$refs.menu.style.width=e+"px":0<this.styleWidth.length&&(this.$refs.menu.style.width=this.styleWidth))},data:function(){let e=this.vItems,i=(null!=e&&e instanceof Array||(e=[]),e=this.formatItems(e),null);if(null!=this.vValue){let t=this;e.forEach(function(e){e.value==t.vValue&&(i=e)})}let t=this.width;return null==t||0==t.length?t="11em":/\d+$/.test(t)&&(t+="em"),{allItems:e,items:e.$copy(),selectedItem:i,keyword:"",visible:!1,hideTimer:null,hoverIndex:0,styleWidth:t}},methods:{formatItems:function(e){return e.forEach(function(e){null==e.value&&(e.value=e.id)}),e},reset:function(){this.selectedItem=null,this.change(),this.hoverIndex=0;let e=this;setTimeout(function(){e.$refs.searchBox&&e.$refs.searchBox.focus()})},clear:function(){this.selectedItem=null,this.change(),this.hoverIndex=0},changeKeyword:function(){this.hoverIndex=0;let t=this.keyword;0==t.length?this.items=this.allItems.$copy():this.items=this.allItems.$copy().filter(function(e){return!!(null!=e.fullname&&0<e.fullname.length&&teaweb.match(e.fullname,t))||teaweb.match(e.name,t)})},selectItem:function(e){this.selectedItem=e,this.change(),this.hoverIndex=0,this.keyword="",this.changeKeyword()},confirm:function(){this.items.length>this.hoverIndex&&this.selectItem(this.items[this.hoverIndex])},show:function(){this.visible=!0},hide:function(){let e=this;this.hideTimer=setTimeout(function(){e.visible=!1},500)},downItem:function(){this.hoverIndex++,this.hoverIndex>this.items.length-1&&(this.hoverIndex=0),this.focusItem()},upItem:function(){this.hoverIndex--,this.hoverIndex<0&&(this.hoverIndex=0),this.focusItem()},focusItem:function(){if(this.hoverIndex<this.items.length){this.$refs.itemRef[this.hoverIndex].focus();let e=this;setTimeout(function(){e.$refs.searchBox.focus(),null!=e.hideTimer&&(clearTimeout(e.hideTimer),e.hideTimer=null)})}},change:function(){this.$emit("change",this.selectedItem);let e=this;setTimeout(function(){null!=e.$refs.selectedLabel&&e.$refs.selectedLabel.focus()})},submitForm:function(e){if("A"==e.target.tagName){let e=this.$refs.selectedLabel.parentNode;for(;;){if(null==(e=e.parentNode)||"BODY"==e.tagName)return;if("FORM"==e.tagName){e.submit();break}}}}},template:`<div style="display: inline; z-index: 10; background: white" class="combo-box">
|
</span>`}),Vue.component("combo-box",{props:["name","title","placeholder","size","v-items","v-value","data-url","data-key","data-search","width"],mounted:function(){0<this.dataURL.length&&this.search("");var e=this.$refs.searchBox;null!=e&&(null!=(e=e.offsetWidth)&&0<e?this.$refs.menu.style.width=e+"px":0<this.styleWidth.length&&(this.$refs.menu.style.width=this.styleWidth))},data:function(){let e=this.vItems,i=(null!=e&&e instanceof Array||(e=[]),e=this.formatItems(e),null);if(null!=this.vValue){let t=this;e.forEach(function(e){e.value==t.vValue&&(i=e)})}let t=this.width,s=(null==t||0==t.length?t="11em":/\d+$/.test(t)&&(t+="em"),"");return"string"==typeof this.dataUrl&&0<this.dataUrl.length&&(s=this.dataUrl),{allItems:e,items:e.$copy(),selectedItem:i,keyword:"",visible:!1,hideTimer:null,hoverIndex:0,styleWidth:t,isInitial:!0,dataURL:s,urlRequestId:0}},methods:{search:function(e){var t=this.dataURL;let i=this.dataKey,s=this,n=Math.random();this.urlRequestId=n,Tea.action(t).params({keyword:null==e?"":e}).post().success(function(t){if(n==s.urlRequestId&&null!=t.data&&"object"==typeof t.data[i]){let e=s.formatItems(t.data[i]);s.allItems=e,s.items=e.$copy(),s.isInitial&&(s.isInitial=!1,null!=s.vValue&&e.forEach(function(e){e.value==s.vValue&&(s.selectedItem=e)}))}})},formatItems:function(e){return e.forEach(function(e){null==e.value&&(e.value=e.id)}),e},reset:function(){this.selectedItem=null,this.change(),this.hoverIndex=0;let e=this;setTimeout(function(){e.$refs.searchBox&&e.$refs.searchBox.focus()})},clear:function(){this.selectedItem=null,this.change(),this.hoverIndex=0},changeKeyword:function(){var e=0<this.dataURL.length&&("on"==this.dataSearch||"true"==this.dataSearch);this.hoverIndex=0;let t=this.keyword;0==t.length?e?this.search(t):this.items=this.allItems.$copy():e?this.search(t):this.items=this.allItems.$copy().filter(function(e){return!!(null!=e.fullname&&0<e.fullname.length&&teaweb.match(e.fullname,t))||teaweb.match(e.name,t)})},selectItem:function(e){this.selectedItem=e,this.change(),this.hoverIndex=0,this.keyword="",this.changeKeyword()},confirm:function(){this.items.length>this.hoverIndex&&this.selectItem(this.items[this.hoverIndex])},show:function(){this.visible=!0},hide:function(){let e=this;this.hideTimer=setTimeout(function(){e.visible=!1},500)},downItem:function(){this.hoverIndex++,this.hoverIndex>this.items.length-1&&(this.hoverIndex=0),this.focusItem()},upItem:function(){this.hoverIndex--,this.hoverIndex<0&&(this.hoverIndex=0),this.focusItem()},focusItem:function(){if(this.hoverIndex<this.items.length){this.$refs.itemRef[this.hoverIndex].focus();let e=this;setTimeout(function(){e.$refs.searchBox.focus(),null!=e.hideTimer&&(clearTimeout(e.hideTimer),e.hideTimer=null)})}},change:function(){this.$emit("change",this.selectedItem);let e=this;setTimeout(function(){null!=e.$refs.selectedLabel&&e.$refs.selectedLabel.focus()})},submitForm:function(e){if("A"==e.target.tagName){let e=this.$refs.selectedLabel.parentNode;for(;;){if(null==(e=e.parentNode)||"BODY"==e.tagName)return;if("FORM"==e.tagName){e.submit();break}}}},setDataURL:function(e){this.dataURL=e},reloadData:function(){this.search("")}},template:`<div style="display: inline; z-index: 10; background: white" class="combo-box">
|
||||||
<!-- 搜索框 -->
|
<!-- 搜索框 -->
|
||||||
<div v-if="selectedItem == null">
|
<div v-if="selectedItem == null">
|
||||||
<input type="text" v-model="keyword" :placeholder="placeholder" :size="size" :style="{'width': styleWidth}" @input="changeKeyword" @focus="show" @blur="hide" @keyup.enter="confirm()" @keypress.enter.prevent="1" ref="searchBox" @keyup.down="downItem" @keyup.up="upItem"/>
|
<input type="text" v-model="keyword" :placeholder="placeholder" :size="size" :style="{'width': styleWidth}" @input="changeKeyword" @focus="show" @blur="hide" @keyup.enter="confirm()" @keypress.enter.prevent="1" ref="searchBox" @keyup.down="downItem" @keyup.up="upItem"/>
|
||||||
@@ -4570,11 +4643,8 @@ Vue.component("traffic-map-box",{props:["v-stats","v-is-attack"],mounted:functio
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`}),Vue.component("finance-user-selector",{mounted:function(){let t=this;Tea.action("/finance/users/options").post().success(function(e){t.users=e.data.users})},props:["v-user-id"],data:function(){let e=this.vUserId;return{users:[],userId:e=null==e?0:e}},watch:{userId:function(e){this.$emit("change",e)}},template:`<div>
|
</div>`}),Vue.component("finance-user-selector",{props:["v-user-id"],data:function(){return{}},methods:{change:function(e){this.$emit("change",e)}},template:`<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/finance/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`}),Vue.component("node-login-suggest-ports",{data:function(){return{ports:[],availablePorts:[],autoSelected:!1,isLoading:!1}},methods:{reload:function(e){let t=this;this.autoSelected=!1,this.isLoading=!0,Tea.action("/clusters/cluster/suggestLoginPorts").params({host:e}).success(function(e){null!=e.data.availablePorts&&(t.availablePorts=e.data.availablePorts,0<t.availablePorts.length&&(t.autoSelectPort(t.availablePorts[0]),t.autoSelected=!0)),null!=e.data.ports&&(t.ports=e.data.ports,0<t.ports.length&&!t.autoSelected&&(t.autoSelectPort(t.ports[0]),t.autoSelected=!0))}).done(function(){t.isLoading=!1}).post()},selectPort:function(e){this.$emit("select",e)},autoSelectPort:function(e){this.$emit("auto-select",e)}},template:`<span>
|
</div>`}),Vue.component("node-login-suggest-ports",{data:function(){return{ports:[],availablePorts:[],autoSelected:!1,isLoading:!1}},methods:{reload:function(e){let t=this;this.autoSelected=!1,this.isLoading=!0,Tea.action("/clusters/cluster/suggestLoginPorts").params({host:e}).success(function(e){null!=e.data.availablePorts&&(t.availablePorts=e.data.availablePorts,0<t.availablePorts.length&&(t.autoSelectPort(t.availablePorts[0]),t.autoSelected=!0)),null!=e.data.ports&&(t.ports=e.data.ports,0<t.ports.length&&!t.autoSelected&&(t.autoSelectPort(t.ports[0]),t.autoSelected=!0))}).done(function(){t.isLoading=!1}).post()},selectPort:function(e){this.$emit("select",e)},autoSelectPort:function(e){this.$emit("auto-select",e)}},template:`<span>
|
||||||
<span v-if="isLoading">正在检查端口...</span>
|
<span v-if="isLoading">正在检查端口...</span>
|
||||||
<span v-if="availablePorts.length > 0">
|
<span v-if="availablePorts.length > 0">
|
||||||
|
|||||||
@@ -1119,9 +1119,49 @@ Vue.component("message-row", {
|
|||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Vue.component("ns-domain-group-selector", {
|
||||||
|
props: ["v-domain-group-id"],
|
||||||
|
data: function () {
|
||||||
|
let groupId = this.vDomainGroupId
|
||||||
|
if (groupId == null) {
|
||||||
|
groupId = 0
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
userId: 0,
|
||||||
|
groupId: groupId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
change: function (group) {
|
||||||
|
if (group != null) {
|
||||||
|
this.$emit("change", group.id)
|
||||||
|
} else {
|
||||||
|
this.$emit("change", 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reload: function (userId) {
|
||||||
|
this.userId = userId
|
||||||
|
this.$refs.comboBox.clear()
|
||||||
|
this.$refs.comboBox.setDataURL("/ns/domains/groups/options?userId=" + userId)
|
||||||
|
this.$refs.comboBox.reloadData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<combo-box
|
||||||
|
data-url="/ns/domains/groups/options"
|
||||||
|
placeholder="选择分组"
|
||||||
|
data-key="groups"
|
||||||
|
name="groupId"
|
||||||
|
:v-value="groupId"
|
||||||
|
@change="change"
|
||||||
|
ref="comboBox">
|
||||||
|
</combo-box>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
|
|
||||||
// 选择多个线路
|
// 选择多个线路
|
||||||
Vue.component("ns-routes-selector", {
|
Vue.component("ns-routes-selector", {
|
||||||
props: ["v-routes"],
|
props: ["v-routes", "name"],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
let that = this
|
let that = this
|
||||||
Tea.action("/ns/routes/options")
|
Tea.action("/ns/routes/options")
|
||||||
@@ -1136,12 +1176,18 @@ Vue.component("ns-routes-selector", {
|
|||||||
selectedRoutes = []
|
selectedRoutes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inputName = this.name
|
||||||
|
if (typeof inputName != "string" || inputName.length == 0) {
|
||||||
|
inputName = "routeCodes"
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
routeCode: "default",
|
routeCode: "default",
|
||||||
|
inputName: inputName,
|
||||||
routes: [],
|
routes: [],
|
||||||
isAdding: false,
|
isAdding: false,
|
||||||
routeType: "default",
|
routeType: "default",
|
||||||
selectedRoutes: selectedRoutes
|
selectedRoutes: selectedRoutes,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -1160,9 +1206,11 @@ Vue.component("ns-routes-selector", {
|
|||||||
this.isAdding = true
|
this.isAdding = true
|
||||||
this.routeType = "default"
|
this.routeType = "default"
|
||||||
this.routeCode = "default"
|
this.routeCode = "default"
|
||||||
|
this.$emit("add")
|
||||||
},
|
},
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
this.isAdding = false
|
this.isAdding = false
|
||||||
|
this.$emit("cancel")
|
||||||
},
|
},
|
||||||
confirm: function () {
|
confirm: function () {
|
||||||
if (this.routeCode.length == 0) {
|
if (this.routeCode.length == 0) {
|
||||||
@@ -1175,17 +1223,19 @@ Vue.component("ns-routes-selector", {
|
|||||||
that.selectedRoutes.push(v)
|
that.selectedRoutes.push(v)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.$emit("change", this.selectedRoutes)
|
||||||
this.cancel()
|
this.cancel()
|
||||||
},
|
},
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
this.selectedRoutes.$remove(index)
|
this.selectedRoutes.$remove(index)
|
||||||
|
this.$emit("change", this.selectedRoutes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<div>
|
<div v-show="selectedRoutes.length > 0">
|
||||||
<div class="ui label basic text small" v-for="(route, index) in selectedRoutes" style="margin-bottom: 0.3em">
|
<div class="ui label basic text small" v-for="(route, index) in selectedRoutes" style="margin-bottom: 0.3em">
|
||||||
<input type="hidden" name="routeCodes" :value="route.code"/>
|
<input type="hidden" :name="inputName" :value="route.code"/>
|
||||||
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
@@ -1972,6 +2022,109 @@ Vue.component("ns-route-ranges-box", {
|
|||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Vue.component("ns-create-records-table", {
|
||||||
|
props: ["v-types"],
|
||||||
|
data: function () {
|
||||||
|
let types = this.vTypes
|
||||||
|
if (types == null) {
|
||||||
|
types = []
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
types: types,
|
||||||
|
records: [
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
type: "A",
|
||||||
|
value: "",
|
||||||
|
routeCodes: [],
|
||||||
|
ttl: 600,
|
||||||
|
index: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
lastIndex: 0,
|
||||||
|
isAddingRoutes: false // 是否正在添加线路
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.records.push({
|
||||||
|
name: "",
|
||||||
|
type: "A",
|
||||||
|
value: "",
|
||||||
|
routeCodes: [],
|
||||||
|
ttl: 600,
|
||||||
|
index: ++this.lastIndex
|
||||||
|
})
|
||||||
|
let that = this
|
||||||
|
setTimeout(function () {
|
||||||
|
that.$refs.nameInputs.$last().focus()
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
remove: function (index) {
|
||||||
|
this.records.$remove(index)
|
||||||
|
},
|
||||||
|
addRoutes: function () {
|
||||||
|
this.isAddingRoutes = true
|
||||||
|
},
|
||||||
|
cancelRoutes: function () {
|
||||||
|
let that = this
|
||||||
|
setTimeout(function () {
|
||||||
|
that.isAddingRoutes = false
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
changeRoutes: function (record, routes) {
|
||||||
|
if (routes == null) {
|
||||||
|
record.routeCodes = []
|
||||||
|
} else {
|
||||||
|
record.routeCodes = routes.map(function (route) {
|
||||||
|
return route.code
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="recordsJSON" :value="JSON.stringify(records)"/>
|
||||||
|
<table class="ui table selectable celled" style="max-width: 60em">
|
||||||
|
<thead class="full-width">
|
||||||
|
<tr>
|
||||||
|
<th style="width:10em">记录名</th>
|
||||||
|
<th style="width:7em">记录类型</th>
|
||||||
|
<th>线路</th>
|
||||||
|
<th v-if="!isAddingRoutes">记录值</th>
|
||||||
|
<th v-if="!isAddingRoutes">TTL</th>
|
||||||
|
<th class="one op" v-if="!isAddingRoutes">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="(record, index) in records" :key="record.index">
|
||||||
|
<td>
|
||||||
|
<input type="text" style="width:10em" v-model="record.name" ref="nameInputs"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" v-model="record.type">
|
||||||
|
<option v-for="type in types" :value="type.type">{{type.type}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ns-routes-selector @add="addRoutes" @cancel="cancelRoutes" @change="changeRoutes(record, $event)"></ns-routes-selector>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<input type="text" style="width:10em" maxlength="512" v-model="record.value"/>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" v-model="record.ttl" style="width:5em" maxlength="8"/>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove"></i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
|
||||||
|
</div>`,
|
||||||
|
})
|
||||||
|
|
||||||
// 选择单一线路
|
// 选择单一线路
|
||||||
Vue.component("ns-route-selector", {
|
Vue.component("ns-route-selector", {
|
||||||
props: ["v-route-code"],
|
props: ["v-route-code"],
|
||||||
@@ -2004,31 +2157,17 @@ Vue.component("ns-route-selector", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("ns-user-selector", {
|
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"],
|
props: ["v-user-id"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
return {}
|
||||||
if (userId == null) {
|
},
|
||||||
userId = 0
|
methods: {
|
||||||
}
|
change: function (userId) {
|
||||||
return {
|
this.$emit("change", userId)
|
||||||
users: [],
|
|
||||||
userId: userId
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/ns/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -2067,7 +2206,12 @@ Vue.component("ns-access-log-box", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div class="access-log-row" :style="{'color': (!accessLog.isRecursive && (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) || (accessLog.isRecursive && accessLog.recordValue != null && accessLog.recordValue.length == 0)) ? '#dc143c' : ''}" ref="box">
|
template: `<div class="access-log-row" :style="{'color': (!accessLog.isRecursive && (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) || (accessLog.isRecursive && accessLog.recordValue != null && accessLog.recordValue.length == 0)) ? '#dc143c' : ''}" ref="box">
|
||||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> -> <em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em><!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> ->
|
||||||
|
|
||||||
|
<span v-if="accessLog.recordType != null && accessLog.recordType.length > 0"><em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em></span>
|
||||||
|
<span v-else class="disabled"> [没有记录]</span>
|
||||||
|
|
||||||
|
<!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
||||||
<div v-if="(accessLog.nsRoutes != null && accessLog.nsRoutes.length > 0) || accessLog.isRecursive" style="margin-top: 0.3em">
|
<div v-if="(accessLog.nsRoutes != null && accessLog.nsRoutes.length > 0) || accessLog.isRecursive" style="margin-top: 0.3em">
|
||||||
<span class="ui label tiny basic grey" v-for="route in accessLog.nsRoutes">线路: {{route.name}}</span>
|
<span class="ui label tiny basic grey" v-for="route in accessLog.nsRoutes">线路: {{route.name}}</span>
|
||||||
<span class="ui label tiny basic grey" v-if="accessLog.isRecursive">递归DNS</span>
|
<span class="ui label tiny basic grey" v-if="accessLog.isRecursive">递归DNS</span>
|
||||||
@@ -2107,37 +2251,45 @@ Vue.component("ns-cluster-selector", {
|
|||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("plan-user-selector", {
|
Vue.component("ns-cluster-combo-box", {
|
||||||
mounted: function () {
|
props: ["v-cluster-id"],
|
||||||
|
data: function () {
|
||||||
let that = this
|
let that = this
|
||||||
|
Tea.action("/ns/clusters/options")
|
||||||
Tea.action("/plans/users/options")
|
|
||||||
.post()
|
.post()
|
||||||
.success(function (resp) {
|
.success(function (resp) {
|
||||||
that.users = resp.data.users
|
that.clusters = resp.data.clusters
|
||||||
})
|
})
|
||||||
|
return {
|
||||||
|
clusters: []
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
change: function (item) {
|
||||||
|
if (item == null) {
|
||||||
|
this.$emit("change", 0)
|
||||||
|
} else {
|
||||||
|
this.$emit("change", item.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div v-if="clusters.length > 0" style="min-width: 10.4em">
|
||||||
|
<combo-box title="集群" placeholder="集群名称" :v-items="clusters" name="clusterId" :v-value="vClusterId" @change="change"></combo-box>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
|
|
||||||
|
Vue.component("plan-user-selector", {
|
||||||
props: ["v-user-id"],
|
props: ["v-user-id"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
return {}
|
||||||
if (userId == null) {
|
|
||||||
userId = 0
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
users: [],
|
|
||||||
userId: userId
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
methods: {
|
||||||
userId: function (v) {
|
change: function (userId) {
|
||||||
this.$emit("change", v)
|
this.$emit("change", userId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/plans/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -3388,6 +3540,8 @@ Vue.component("http-cache-refs-box", {
|
|||||||
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
||||||
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
||||||
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfNoneMatch">If-None-Match</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfModifiedSince">If-Modified-Since</grey-label>
|
||||||
</td>
|
</td>
|
||||||
<td :class="{disabled: !cacheRef.isOn}">
|
<td :class="{disabled: !cacheRef.isOn}">
|
||||||
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
||||||
@@ -3680,6 +3834,8 @@ Vue.component("http-cache-ref-box", {
|
|||||||
conds: null,
|
conds: null,
|
||||||
allowChunkedEncoding: true,
|
allowChunkedEncoding: true,
|
||||||
allowPartialContent: false,
|
allowPartialContent: false,
|
||||||
|
enableIfNoneMatch: false,
|
||||||
|
enableIfModifiedSince: false,
|
||||||
isReverse: this.vIsReverse,
|
isReverse: this.vIsReverse,
|
||||||
methods: [],
|
methods: [],
|
||||||
expiresTime: {
|
expiresTime: {
|
||||||
@@ -3851,6 +4007,20 @@ Vue.component("http-cache-ref-box", {
|
|||||||
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||||
|
<td>允许If-None-Match回源</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="ref.enableIfNoneMatch"></checkbox>
|
||||||
|
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||||
|
<td>允许If-Modified-Since回源</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="ref.enableIfModifiedSince"></checkbox>
|
||||||
|
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>`
|
</tbody>`
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -3918,7 +4088,7 @@ Vue.component("http-request-limit-config-box", {
|
|||||||
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">是否启用</td>
|
<td class="title">启用</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox v-model="config.isOn"></checkbox>
|
<checkbox v-model="config.isOn"></checkbox>
|
||||||
</td>
|
</td>
|
||||||
@@ -3929,14 +4099,14 @@ Vue.component("http-request-limit-config-box", {
|
|||||||
<td>最大并发连接数</td>
|
<td>最大并发连接数</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" maxlength="6" v-model="maxConns"/>
|
<input type="text" maxlength="6" v-model="maxConns"/>
|
||||||
<p class="comment">当前服务最大并发连接数。为0表示不限制。</p>
|
<p class="comment">当前服务最大并发连接数,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>单IP最大并发连接数</td>
|
<td>单IP最大并发连接数</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
||||||
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务。为0表示不限制。</p>
|
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -4948,7 +5118,7 @@ Vue.component("http-firewall-checkpoint-cc", {
|
|||||||
<td>忽略常见文件</td>
|
<td>忽略常见文件</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox v-model="ignoreCommonFiles"></checkbox>
|
<checkbox v-model="ignoreCommonFiles"></checkbox>
|
||||||
<p class="comment">忽略js、css、jpg等常见文件名。</p>
|
<p class="comment">忽略js、css、jpg等常见在网页里被引用的文件名。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -5312,6 +5482,8 @@ Vue.component("http-cache-refs-config-box", {
|
|||||||
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
||||||
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
||||||
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfNoneMatch">If-None-Match</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfModifiedSince">If-Modified-Since</grey-label>
|
||||||
</td>
|
</td>
|
||||||
<td :class="{disabled: !cacheRef.isOn}">
|
<td :class="{disabled: !cacheRef.isOn}">
|
||||||
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
||||||
@@ -5424,7 +5596,8 @@ Vue.component("origin-list-table", {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="origin in vOrigins">
|
<tr v-for="origin in vOrigins">
|
||||||
<td :class="{disabled:!origin.isOn}"><a href="" @click.prevent="updateOrigin(origin.id)">{{origin.addr}} <i class="icon expand small"></i></a>
|
<td :class="{disabled:!origin.isOn}">
|
||||||
|
<a href="" @click.prevent="updateOrigin(origin.id)" :class="{disabled:!origin.isOn}">{{origin.addr}} <i class="icon expand small"></i></a>
|
||||||
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || origin.followPort || (origin.domains != null && origin.domains.length > 0)">
|
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || origin.followPort || (origin.domains != null && origin.domains.length > 0)">
|
||||||
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
|
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
|
||||||
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
|
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
|
||||||
@@ -7073,36 +7246,35 @@ Vue.component("http-auth-config-box", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("user-selector", {
|
Vue.component("user-selector", {
|
||||||
mounted: function () {
|
props: ["v-user-id", "data-url"],
|
||||||
let that = this
|
|
||||||
|
|
||||||
Tea.action("/servers/users/options")
|
|
||||||
.post()
|
|
||||||
.success(function (resp) {
|
|
||||||
that.users = resp.data.users
|
|
||||||
})
|
|
||||||
},
|
|
||||||
props: ["v-user-id"],
|
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
let userId = this.vUserId
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
userId = 0
|
userId = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dataURL = this.dataUrl
|
||||||
|
if (dataURL == null || dataURL.length == 0) {
|
||||||
|
dataURL = "/servers/users/options"
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users: [],
|
users: [],
|
||||||
userId: userId
|
userId: userId,
|
||||||
|
dataURL: dataURL
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
methods: {
|
||||||
userId: function (v) {
|
change: function(item) {
|
||||||
this.$emit("change", v)
|
if (item != null) {
|
||||||
|
this.$emit("change", item.id)
|
||||||
|
} else {
|
||||||
|
this.$emit("change", 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<combo-box placeholder="选择用户" :data-url="dataURL" :data-key="'users'" data-search="on" name="userId" :v-value="userId" @change="change"></combo-box>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -8531,6 +8703,12 @@ Vue.component("http-location-labels", {
|
|||||||
<!-- 请求脚本 -->
|
<!-- 请求脚本 -->
|
||||||
<http-location-labels-label v-if="location.web != null && location.web.requestScripts != null && ((location.web.requestScripts.initGroup != null && location.web.requestScripts.initGroup.isPrior) || (location.web.requestScripts.requestGroup != null && location.web.requestScripts.requestGroup.isPrior))" :href="url('/requestScripts')">请求脚本</http-location-labels-label>
|
<http-location-labels-label v-if="location.web != null && location.web.requestScripts != null && ((location.web.requestScripts.initGroup != null && location.web.requestScripts.initGroup.isPrior) || (location.web.requestScripts.requestGroup != null && location.web.requestScripts.requestGroup.isPrior))" :href="url('/requestScripts')">请求脚本</http-location-labels-label>
|
||||||
|
|
||||||
|
<!-- 自定义访客IP地址 -->
|
||||||
|
<http-location-labels-label v-if="location.web != null && location.web.remoteAddr != null && location.web.remoteAddr.isPrior" :href="url('/remoteAddr')" :class="{disabled: !location.web.remoteAddr.isOn}">访客IP地址</http-location-labels-label>
|
||||||
|
|
||||||
|
<!-- 请求限制 -->
|
||||||
|
<http-location-labels-label v-if="location.web != null && location.web.requestLimit != null && location.web.requestLimit.isPrior" :href="url('/requestLimit')" :class="{disabled: !location.web.requestLimit.isOn}">请求限制</http-location-labels-label>
|
||||||
|
|
||||||
<!-- 自定义页面 -->
|
<!-- 自定义页面 -->
|
||||||
<div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0">
|
<div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0">
|
||||||
<div v-for="page in location.web.pages" :key="page.id"><http-location-labels-label :href="url('/pages')">PAGE [状态码{{page.status[0]}}] -> {{page.url}}</http-location-labels-label></div>
|
<div v-for="page in location.web.pages" :key="page.id"><http-location-labels-label :href="url('/pages')">PAGE [状态码{{page.status[0]}}] -> {{page.url}}</http-location-labels-label></div>
|
||||||
@@ -12062,7 +12240,7 @@ Vue.component("page-box", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("network-addresses-box", {
|
Vue.component("network-addresses-box", {
|
||||||
props: ["v-server-type", "v-addresses", "v-protocol", "v-name", "v-from", "v-support-range"],
|
props: ["v-server-type", "v-addresses", "v-protocol", "v-name", "v-from", "v-support-range", "v-url"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let addresses = this.vAddresses
|
let addresses = this.vAddresses
|
||||||
if (addresses == null) {
|
if (addresses == null) {
|
||||||
@@ -12104,7 +12282,13 @@ Vue.component("network-addresses-box", {
|
|||||||
addAddr: function () {
|
addAddr: function () {
|
||||||
let that = this
|
let that = this
|
||||||
window.UPDATING_ADDR = null
|
window.UPDATING_ADDR = null
|
||||||
teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
|
||||||
|
let url = this.vUrl
|
||||||
|
if (url == null) {
|
||||||
|
url = "/servers/addPortPopup"
|
||||||
|
}
|
||||||
|
|
||||||
|
teaweb.popup(url + "?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
||||||
height: "18em",
|
height: "18em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
var addr = resp.data.address
|
var addr = resp.data.address
|
||||||
@@ -12135,7 +12319,13 @@ Vue.component("network-addresses-box", {
|
|||||||
updateAddr: function (index, addr) {
|
updateAddr: function (index, addr) {
|
||||||
let that = this
|
let that = this
|
||||||
window.UPDATING_ADDR = addr
|
window.UPDATING_ADDR = addr
|
||||||
teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
|
||||||
|
let url = this.vUrl
|
||||||
|
if (url == null) {
|
||||||
|
url = "/servers/addPortPopup"
|
||||||
|
}
|
||||||
|
|
||||||
|
teaweb.popup(url + "?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
||||||
height: "18em",
|
height: "18em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
var addr = resp.data.address
|
var addr = resp.data.address
|
||||||
@@ -12505,14 +12695,19 @@ Vue.component("download-link", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("values-box", {
|
Vue.component("values-box", {
|
||||||
props: ["values", "size", "maxlength", "name", "placeholder"],
|
props: ["values", "v-values", "size", "maxlength", "name", "placeholder"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let values = this.values;
|
let values = this.values;
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
values = [];
|
values = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.vValues != null && typeof this.vValues == "object") {
|
||||||
|
values = this.vValues
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"vValues": values,
|
"realValues": values,
|
||||||
"isUpdating": false,
|
"isUpdating": false,
|
||||||
"isAdding": false,
|
"isAdding": false,
|
||||||
"index": 0,
|
"index": 0,
|
||||||
@@ -12532,7 +12727,7 @@ Vue.component("values-box", {
|
|||||||
this.cancel()
|
this.cancel()
|
||||||
this.isUpdating = true;
|
this.isUpdating = true;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.value = this.vValues[index];
|
this.value = this.realValues[index];
|
||||||
var that = this;
|
var that = this;
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
that.$refs.value.focus();
|
that.$refs.value.focus();
|
||||||
@@ -12544,16 +12739,16 @@ Vue.component("values-box", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.isUpdating) {
|
if (this.isUpdating) {
|
||||||
Vue.set(this.vValues, this.index, this.value);
|
Vue.set(this.realValues, this.index, this.value);
|
||||||
} else {
|
} else {
|
||||||
this.vValues.push(this.value);
|
this.realValues.push(this.value);
|
||||||
}
|
}
|
||||||
this.cancel()
|
this.cancel()
|
||||||
this.$emit("change", this.vValues)
|
this.$emit("change", this.realValues)
|
||||||
},
|
},
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
this.vValues.$remove(index)
|
this.realValues.$remove(index)
|
||||||
this.$emit("change", this.vValues)
|
this.$emit("change", this.realValues)
|
||||||
},
|
},
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
@@ -12561,10 +12756,10 @@ Vue.component("values-box", {
|
|||||||
this.value = "";
|
this.value = "";
|
||||||
},
|
},
|
||||||
updateAll: function (values) {
|
updateAll: function (values) {
|
||||||
this.vValeus = values
|
this.realValues = values
|
||||||
},
|
},
|
||||||
addValue: function (v) {
|
addValue: function (v) {
|
||||||
this.vValues.push(v)
|
this.realValues.push(v)
|
||||||
},
|
},
|
||||||
|
|
||||||
startEditing: function () {
|
startEditing: function () {
|
||||||
@@ -12572,13 +12767,13 @@ Vue.component("values-box", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<div v-show="!isEditing && vValues.length > 0">
|
<div v-show="!isEditing && realValues.length > 0">
|
||||||
<div class="ui label tiny basic" v-for="(value, index) in vValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}</div>
|
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}</div>
|
||||||
<a href="" @click.prevent="startEditing" style="font-size: 0.8em; margin-left: 0.2em">[修改]</a>
|
<a href="" @click.prevent="startEditing" style="font-size: 0.8em; margin-left: 0.2em">[修改]</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isEditing || vValues.length == 0">
|
<div v-show="isEditing || realValues.length == 0">
|
||||||
<div style="margin-bottom: 1em" v-if="vValues.length > 0">
|
<div style="margin-bottom: 1em" v-if="realValues.length > 0">
|
||||||
<div class="ui label tiny basic" v-for="(value, index) in vValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}
|
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}
|
||||||
<input type="hidden" :name="name" :value="value"/>
|
<input type="hidden" :name="name" :value="value"/>
|
||||||
<a href="" @click.prevent="update(index)" title="修改"><i class="icon pencil small" ></i></a>
|
<a href="" @click.prevent="update(index)" title="修改"><i class="icon pencil small" ></i></a>
|
||||||
<a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
<a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
||||||
@@ -13324,32 +13519,16 @@ Vue.component("request-variables-describer", {
|
|||||||
|
|
||||||
Vue.component("combo-box", {
|
Vue.component("combo-box", {
|
||||||
// data-url 和 data-key 成对出现
|
// data-url 和 data-key 成对出现
|
||||||
props: ["name", "title", "placeholder", "size", "v-items", "v-value", "data-url", "data-key", "width"],
|
props: [
|
||||||
|
"name", "title", "placeholder", "size", "v-items", "v-value",
|
||||||
|
"data-url", // 数据源URL
|
||||||
|
"data-key", // 数据源中数据的键名
|
||||||
|
"data-search", // 是否启用动态搜索,如果值为on或true,则表示启用
|
||||||
|
"width"
|
||||||
|
],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
// 从URL中获取选项数据
|
if (this.dataURL.length > 0) {
|
||||||
let dataUrl = this.dataUrl
|
this.search("")
|
||||||
let dataKey = this.dataKey
|
|
||||||
let that = this
|
|
||||||
if (dataUrl != null && dataUrl.length > 0 && dataKey != null) {
|
|
||||||
Tea.action(dataUrl)
|
|
||||||
.post()
|
|
||||||
.success(function (resp) {
|
|
||||||
if (resp.data != null) {
|
|
||||||
if (typeof (resp.data[dataKey]) == "object") {
|
|
||||||
let items = that.formatItems(resp.data[dataKey])
|
|
||||||
that.allItems = items
|
|
||||||
that.items = items.$copy()
|
|
||||||
|
|
||||||
if (that.vValue != null) {
|
|
||||||
items.forEach(function (v) {
|
|
||||||
if (v.value == that.vValue) {
|
|
||||||
that.selectedItem = v
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设定菜单宽度
|
// 设定菜单宽度
|
||||||
@@ -13390,6 +13569,12 @@ Vue.component("combo-box", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// data url
|
||||||
|
let dataURL = ""
|
||||||
|
if (typeof this.dataUrl == "string" && this.dataUrl.length > 0) {
|
||||||
|
dataURL = this.dataUrl
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allItems: items, // 原始的所有的items
|
allItems: items, // 原始的所有的items
|
||||||
items: items.$copy(), // 候选的items
|
items: items.$copy(), // 候选的items
|
||||||
@@ -13398,10 +13583,53 @@ Vue.component("combo-box", {
|
|||||||
visible: false,
|
visible: false,
|
||||||
hideTimer: null,
|
hideTimer: null,
|
||||||
hoverIndex: 0,
|
hoverIndex: 0,
|
||||||
styleWidth: width
|
styleWidth: width,
|
||||||
|
|
||||||
|
isInitial: true,
|
||||||
|
dataURL: dataURL,
|
||||||
|
urlRequestId: 0 // 记录URL请求ID,防止并行冲突
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
search: function (keyword) {
|
||||||
|
// 从URL中获取选项数据
|
||||||
|
let dataUrl = this.dataURL
|
||||||
|
let dataKey = this.dataKey
|
||||||
|
let that = this
|
||||||
|
|
||||||
|
let requestId = Math.random()
|
||||||
|
this.urlRequestId = requestId
|
||||||
|
|
||||||
|
Tea.action(dataUrl)
|
||||||
|
.params({
|
||||||
|
keyword: (keyword == null) ? "" : keyword
|
||||||
|
})
|
||||||
|
.post()
|
||||||
|
.success(function (resp) {
|
||||||
|
if (requestId != that.urlRequestId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp.data != null) {
|
||||||
|
if (typeof (resp.data[dataKey]) == "object") {
|
||||||
|
let items = that.formatItems(resp.data[dataKey])
|
||||||
|
that.allItems = items
|
||||||
|
that.items = items.$copy()
|
||||||
|
|
||||||
|
if (that.isInitial) {
|
||||||
|
that.isInitial = false
|
||||||
|
if (that.vValue != null) {
|
||||||
|
items.forEach(function (v) {
|
||||||
|
if (v.value == that.vValue) {
|
||||||
|
that.selectedItem = v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
formatItems: function (items) {
|
formatItems: function (items) {
|
||||||
items.forEach(function (v) {
|
items.forEach(function (v) {
|
||||||
if (v.value == null) {
|
if (v.value == null) {
|
||||||
@@ -13428,18 +13656,30 @@ Vue.component("combo-box", {
|
|||||||
this.hoverIndex = 0
|
this.hoverIndex = 0
|
||||||
},
|
},
|
||||||
changeKeyword: function () {
|
changeKeyword: function () {
|
||||||
|
let shouldSearch = this.dataURL.length > 0 && (this.dataSearch == "on" || this.dataSearch == "true")
|
||||||
|
|
||||||
this.hoverIndex = 0
|
this.hoverIndex = 0
|
||||||
let keyword = this.keyword
|
let keyword = this.keyword
|
||||||
if (keyword.length == 0) {
|
if (keyword.length == 0) {
|
||||||
this.items = this.allItems.$copy()
|
if (shouldSearch) {
|
||||||
|
this.search(keyword)
|
||||||
|
} else {
|
||||||
|
this.items = this.allItems.$copy()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.items = this.allItems.$copy().filter(function (v) {
|
|
||||||
if (v.fullname != null && v.fullname.length > 0 && teaweb.match(v.fullname, keyword)) {
|
|
||||||
return true
|
if (shouldSearch) {
|
||||||
}
|
this.search(keyword)
|
||||||
return teaweb.match(v.name, keyword)
|
} else {
|
||||||
})
|
this.items = this.allItems.$copy().filter(function (v) {
|
||||||
|
if (v.fullname != null && v.fullname.length > 0 && teaweb.match(v.fullname, keyword)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return teaweb.match(v.name, keyword)
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
selectItem: function (item) {
|
selectItem: function (item) {
|
||||||
this.selectedItem = item
|
this.selectedItem = item
|
||||||
@@ -13516,6 +13756,13 @@ Vue.component("combo-box", {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setDataURL: function (dataURL) {
|
||||||
|
this.dataURL = dataURL
|
||||||
|
},
|
||||||
|
reloadData: function () {
|
||||||
|
this.search("")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div style="display: inline; z-index: 10; background: white" class="combo-box">
|
template: `<div style="display: inline; z-index: 10; background: white" class="combo-box">
|
||||||
@@ -14410,36 +14657,17 @@ Vue.component("report-node-groups-selector", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Vue.component("finance-user-selector", {
|
Vue.component("finance-user-selector", {
|
||||||
mounted: function () {
|
|
||||||
let that = this
|
|
||||||
|
|
||||||
Tea.action("/finance/users/options")
|
|
||||||
.post()
|
|
||||||
.success(function (resp) {
|
|
||||||
that.users = resp.data.users
|
|
||||||
})
|
|
||||||
},
|
|
||||||
props: ["v-user-id"],
|
props: ["v-user-id"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
return {}
|
||||||
if (userId == null) {
|
|
||||||
userId = 0
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
users: [],
|
|
||||||
userId: userId
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
methods: {
|
||||||
userId: function (v) {
|
change: function (userId) {
|
||||||
this.$emit("change", v)
|
this.$emit("change", userId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/finance/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,15 @@
|
|||||||
Vue.component("combo-box", {
|
Vue.component("combo-box", {
|
||||||
// data-url 和 data-key 成对出现
|
// data-url 和 data-key 成对出现
|
||||||
props: ["name", "title", "placeholder", "size", "v-items", "v-value", "data-url", "data-key", "width"],
|
props: [
|
||||||
|
"name", "title", "placeholder", "size", "v-items", "v-value",
|
||||||
|
"data-url", // 数据源URL
|
||||||
|
"data-key", // 数据源中数据的键名
|
||||||
|
"data-search", // 是否启用动态搜索,如果值为on或true,则表示启用
|
||||||
|
"width"
|
||||||
|
],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
// 从URL中获取选项数据
|
if (this.dataURL.length > 0) {
|
||||||
let dataUrl = this.dataUrl
|
this.search("")
|
||||||
let dataKey = this.dataKey
|
|
||||||
let that = this
|
|
||||||
if (dataUrl != null && dataUrl.length > 0 && dataKey != null) {
|
|
||||||
Tea.action(dataUrl)
|
|
||||||
.post()
|
|
||||||
.success(function (resp) {
|
|
||||||
if (resp.data != null) {
|
|
||||||
if (typeof (resp.data[dataKey]) == "object") {
|
|
||||||
let items = that.formatItems(resp.data[dataKey])
|
|
||||||
that.allItems = items
|
|
||||||
that.items = items.$copy()
|
|
||||||
|
|
||||||
if (that.vValue != null) {
|
|
||||||
items.forEach(function (v) {
|
|
||||||
if (v.value == that.vValue) {
|
|
||||||
that.selectedItem = v
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设定菜单宽度
|
// 设定菜单宽度
|
||||||
@@ -66,6 +50,12 @@ Vue.component("combo-box", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// data url
|
||||||
|
let dataURL = ""
|
||||||
|
if (typeof this.dataUrl == "string" && this.dataUrl.length > 0) {
|
||||||
|
dataURL = this.dataUrl
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allItems: items, // 原始的所有的items
|
allItems: items, // 原始的所有的items
|
||||||
items: items.$copy(), // 候选的items
|
items: items.$copy(), // 候选的items
|
||||||
@@ -74,10 +64,53 @@ Vue.component("combo-box", {
|
|||||||
visible: false,
|
visible: false,
|
||||||
hideTimer: null,
|
hideTimer: null,
|
||||||
hoverIndex: 0,
|
hoverIndex: 0,
|
||||||
styleWidth: width
|
styleWidth: width,
|
||||||
|
|
||||||
|
isInitial: true,
|
||||||
|
dataURL: dataURL,
|
||||||
|
urlRequestId: 0 // 记录URL请求ID,防止并行冲突
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
search: function (keyword) {
|
||||||
|
// 从URL中获取选项数据
|
||||||
|
let dataUrl = this.dataURL
|
||||||
|
let dataKey = this.dataKey
|
||||||
|
let that = this
|
||||||
|
|
||||||
|
let requestId = Math.random()
|
||||||
|
this.urlRequestId = requestId
|
||||||
|
|
||||||
|
Tea.action(dataUrl)
|
||||||
|
.params({
|
||||||
|
keyword: (keyword == null) ? "" : keyword
|
||||||
|
})
|
||||||
|
.post()
|
||||||
|
.success(function (resp) {
|
||||||
|
if (requestId != that.urlRequestId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp.data != null) {
|
||||||
|
if (typeof (resp.data[dataKey]) == "object") {
|
||||||
|
let items = that.formatItems(resp.data[dataKey])
|
||||||
|
that.allItems = items
|
||||||
|
that.items = items.$copy()
|
||||||
|
|
||||||
|
if (that.isInitial) {
|
||||||
|
that.isInitial = false
|
||||||
|
if (that.vValue != null) {
|
||||||
|
items.forEach(function (v) {
|
||||||
|
if (v.value == that.vValue) {
|
||||||
|
that.selectedItem = v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
formatItems: function (items) {
|
formatItems: function (items) {
|
||||||
items.forEach(function (v) {
|
items.forEach(function (v) {
|
||||||
if (v.value == null) {
|
if (v.value == null) {
|
||||||
@@ -104,18 +137,30 @@ Vue.component("combo-box", {
|
|||||||
this.hoverIndex = 0
|
this.hoverIndex = 0
|
||||||
},
|
},
|
||||||
changeKeyword: function () {
|
changeKeyword: function () {
|
||||||
|
let shouldSearch = this.dataURL.length > 0 && (this.dataSearch == "on" || this.dataSearch == "true")
|
||||||
|
|
||||||
this.hoverIndex = 0
|
this.hoverIndex = 0
|
||||||
let keyword = this.keyword
|
let keyword = this.keyword
|
||||||
if (keyword.length == 0) {
|
if (keyword.length == 0) {
|
||||||
this.items = this.allItems.$copy()
|
if (shouldSearch) {
|
||||||
|
this.search(keyword)
|
||||||
|
} else {
|
||||||
|
this.items = this.allItems.$copy()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.items = this.allItems.$copy().filter(function (v) {
|
|
||||||
if (v.fullname != null && v.fullname.length > 0 && teaweb.match(v.fullname, keyword)) {
|
|
||||||
return true
|
if (shouldSearch) {
|
||||||
}
|
this.search(keyword)
|
||||||
return teaweb.match(v.name, keyword)
|
} else {
|
||||||
})
|
this.items = this.allItems.$copy().filter(function (v) {
|
||||||
|
if (v.fullname != null && v.fullname.length > 0 && teaweb.match(v.fullname, keyword)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return teaweb.match(v.name, keyword)
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
selectItem: function (item) {
|
selectItem: function (item) {
|
||||||
this.selectedItem = item
|
this.selectedItem = item
|
||||||
@@ -192,6 +237,13 @@ Vue.component("combo-box", {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setDataURL: function (dataURL) {
|
||||||
|
this.dataURL = dataURL
|
||||||
|
},
|
||||||
|
reloadData: function () {
|
||||||
|
this.search("")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div style="display: inline; z-index: 10; background: white" class="combo-box">
|
template: `<div style="display: inline; z-index: 10; background: white" class="combo-box">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Vue.component("network-addresses-box", {
|
Vue.component("network-addresses-box", {
|
||||||
props: ["v-server-type", "v-addresses", "v-protocol", "v-name", "v-from", "v-support-range"],
|
props: ["v-server-type", "v-addresses", "v-protocol", "v-name", "v-from", "v-support-range", "v-url"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let addresses = this.vAddresses
|
let addresses = this.vAddresses
|
||||||
if (addresses == null) {
|
if (addresses == null) {
|
||||||
@@ -41,7 +41,13 @@ Vue.component("network-addresses-box", {
|
|||||||
addAddr: function () {
|
addAddr: function () {
|
||||||
let that = this
|
let that = this
|
||||||
window.UPDATING_ADDR = null
|
window.UPDATING_ADDR = null
|
||||||
teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
|
||||||
|
let url = this.vUrl
|
||||||
|
if (url == null) {
|
||||||
|
url = "/servers/addPortPopup"
|
||||||
|
}
|
||||||
|
|
||||||
|
teaweb.popup(url + "?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
||||||
height: "18em",
|
height: "18em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
var addr = resp.data.address
|
var addr = resp.data.address
|
||||||
@@ -72,7 +78,13 @@ Vue.component("network-addresses-box", {
|
|||||||
updateAddr: function (index, addr) {
|
updateAddr: function (index, addr) {
|
||||||
let that = this
|
let that = this
|
||||||
window.UPDATING_ADDR = addr
|
window.UPDATING_ADDR = addr
|
||||||
teaweb.popup("/servers/addPortPopup?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
|
||||||
|
let url = this.vUrl
|
||||||
|
if (url == null) {
|
||||||
|
url = "/servers/addPortPopup"
|
||||||
|
}
|
||||||
|
|
||||||
|
teaweb.popup(url + "?serverType=" + this.vServerType + "&protocol=" + this.protocol + "&from=" + this.from + "&supportRange=" + (this.supportRange() ? 1 : 0), {
|
||||||
height: "18em",
|
height: "18em",
|
||||||
callback: function (resp) {
|
callback: function (resp) {
|
||||||
var addr = resp.data.address
|
var addr = resp.data.address
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
Vue.component("values-box", {
|
Vue.component("values-box", {
|
||||||
props: ["values", "size", "maxlength", "name", "placeholder"],
|
props: ["values", "v-values", "size", "maxlength", "name", "placeholder"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let values = this.values;
|
let values = this.values;
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
values = [];
|
values = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.vValues != null && typeof this.vValues == "object") {
|
||||||
|
values = this.vValues
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"vValues": values,
|
"realValues": values,
|
||||||
"isUpdating": false,
|
"isUpdating": false,
|
||||||
"isAdding": false,
|
"isAdding": false,
|
||||||
"index": 0,
|
"index": 0,
|
||||||
@@ -26,7 +31,7 @@ Vue.component("values-box", {
|
|||||||
this.cancel()
|
this.cancel()
|
||||||
this.isUpdating = true;
|
this.isUpdating = true;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.value = this.vValues[index];
|
this.value = this.realValues[index];
|
||||||
var that = this;
|
var that = this;
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
that.$refs.value.focus();
|
that.$refs.value.focus();
|
||||||
@@ -38,16 +43,16 @@ Vue.component("values-box", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.isUpdating) {
|
if (this.isUpdating) {
|
||||||
Vue.set(this.vValues, this.index, this.value);
|
Vue.set(this.realValues, this.index, this.value);
|
||||||
} else {
|
} else {
|
||||||
this.vValues.push(this.value);
|
this.realValues.push(this.value);
|
||||||
}
|
}
|
||||||
this.cancel()
|
this.cancel()
|
||||||
this.$emit("change", this.vValues)
|
this.$emit("change", this.realValues)
|
||||||
},
|
},
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
this.vValues.$remove(index)
|
this.realValues.$remove(index)
|
||||||
this.$emit("change", this.vValues)
|
this.$emit("change", this.realValues)
|
||||||
},
|
},
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
this.isUpdating = false;
|
this.isUpdating = false;
|
||||||
@@ -55,10 +60,10 @@ Vue.component("values-box", {
|
|||||||
this.value = "";
|
this.value = "";
|
||||||
},
|
},
|
||||||
updateAll: function (values) {
|
updateAll: function (values) {
|
||||||
this.vValeus = values
|
this.realValues = values
|
||||||
},
|
},
|
||||||
addValue: function (v) {
|
addValue: function (v) {
|
||||||
this.vValues.push(v)
|
this.realValues.push(v)
|
||||||
},
|
},
|
||||||
|
|
||||||
startEditing: function () {
|
startEditing: function () {
|
||||||
@@ -66,13 +71,13 @@ Vue.component("values-box", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<div v-show="!isEditing && vValues.length > 0">
|
<div v-show="!isEditing && realValues.length > 0">
|
||||||
<div class="ui label tiny basic" v-for="(value, index) in vValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}</div>
|
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}</div>
|
||||||
<a href="" @click.prevent="startEditing" style="font-size: 0.8em; margin-left: 0.2em">[修改]</a>
|
<a href="" @click.prevent="startEditing" style="font-size: 0.8em; margin-left: 0.2em">[修改]</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isEditing || vValues.length == 0">
|
<div v-show="isEditing || realValues.length == 0">
|
||||||
<div style="margin-bottom: 1em" v-if="vValues.length > 0">
|
<div style="margin-bottom: 1em" v-if="realValues.length > 0">
|
||||||
<div class="ui label tiny basic" v-for="(value, index) in vValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}
|
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}
|
||||||
<input type="hidden" :name="name" :value="value"/>
|
<input type="hidden" :name="name" :value="value"/>
|
||||||
<a href="" @click.prevent="update(index)" title="修改"><i class="icon pencil small" ></i></a>
|
<a href="" @click.prevent="update(index)" title="修改"><i class="icon pencil small" ></i></a>
|
||||||
<a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
<a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>
|
||||||
|
|||||||
@@ -1,33 +1,14 @@
|
|||||||
Vue.component("finance-user-selector", {
|
Vue.component("finance-user-selector", {
|
||||||
mounted: function () {
|
|
||||||
let that = this
|
|
||||||
|
|
||||||
Tea.action("/finance/users/options")
|
|
||||||
.post()
|
|
||||||
.success(function (resp) {
|
|
||||||
that.users = resp.data.users
|
|
||||||
})
|
|
||||||
},
|
|
||||||
props: ["v-user-id"],
|
props: ["v-user-id"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
return {}
|
||||||
if (userId == null) {
|
|
||||||
userId = 0
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
users: [],
|
|
||||||
userId: userId
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
methods: {
|
||||||
userId: function (v) {
|
change: function (userId) {
|
||||||
this.$emit("change", v)
|
this.$emit("change", userId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/finance/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -33,7 +33,12 @@ Vue.component("ns-access-log-box", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div class="access-log-row" :style="{'color': (!accessLog.isRecursive && (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) || (accessLog.isRecursive && accessLog.recordValue != null && accessLog.recordValue.length == 0)) ? '#dc143c' : ''}" ref="box">
|
template: `<div class="access-log-row" :style="{'color': (!accessLog.isRecursive && (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) || (accessLog.isRecursive && accessLog.recordValue != null && accessLog.recordValue.length == 0)) ? '#dc143c' : ''}" ref="box">
|
||||||
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> -> <em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em><!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
<span v-if="accessLog.region != null && accessLog.region.length > 0" class="grey">[{{accessLog.region}}]</span> <keyword :v-word="vKeyword">{{accessLog.remoteAddr}}</keyword> [{{accessLog.timeLocal}}] [{{accessLog.networking}}] <em>{{accessLog.questionType}} <keyword :v-word="vKeyword">{{accessLog.questionName}}</keyword></em> ->
|
||||||
|
|
||||||
|
<span v-if="accessLog.recordType != null && accessLog.recordType.length > 0"><em>{{accessLog.recordType}} <keyword :v-word="vKeyword">{{accessLog.recordValue}}</keyword></em></span>
|
||||||
|
<span v-else class="disabled"> [没有记录]</span>
|
||||||
|
|
||||||
|
<!-- <a href="" @click.prevent="showLog" title="查看详情"><i class="icon expand"></i></a>-->
|
||||||
<div v-if="(accessLog.nsRoutes != null && accessLog.nsRoutes.length > 0) || accessLog.isRecursive" style="margin-top: 0.3em">
|
<div v-if="(accessLog.nsRoutes != null && accessLog.nsRoutes.length > 0) || accessLog.isRecursive" style="margin-top: 0.3em">
|
||||||
<span class="ui label tiny basic grey" v-for="route in accessLog.nsRoutes">线路: {{route.name}}</span>
|
<span class="ui label tiny basic grey" v-for="route in accessLog.nsRoutes">线路: {{route.name}}</span>
|
||||||
<span class="ui label tiny basic grey" v-if="accessLog.isRecursive">递归DNS</span>
|
<span class="ui label tiny basic grey" v-if="accessLog.isRecursive">递归DNS</span>
|
||||||
|
|||||||
26
web/public/js/components/ns/ns-cluster-combo-box.js
Normal file
26
web/public/js/components/ns/ns-cluster-combo-box.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Vue.component("ns-cluster-combo-box", {
|
||||||
|
props: ["v-cluster-id"],
|
||||||
|
data: function () {
|
||||||
|
let that = this
|
||||||
|
Tea.action("/ns/clusters/options")
|
||||||
|
.post()
|
||||||
|
.success(function (resp) {
|
||||||
|
that.clusters = resp.data.clusters
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
clusters: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
change: function (item) {
|
||||||
|
if (item == null) {
|
||||||
|
this.$emit("change", 0)
|
||||||
|
} else {
|
||||||
|
this.$emit("change", item.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div v-if="clusters.length > 0" style="min-width: 10.4em">
|
||||||
|
<combo-box title="集群" placeholder="集群名称" :v-items="clusters" name="clusterId" :v-value="vClusterId" @change="change"></combo-box>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
102
web/public/js/components/ns/ns-create-records-table.js
Normal file
102
web/public/js/components/ns/ns-create-records-table.js
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
Vue.component("ns-create-records-table", {
|
||||||
|
props: ["v-types"],
|
||||||
|
data: function () {
|
||||||
|
let types = this.vTypes
|
||||||
|
if (types == null) {
|
||||||
|
types = []
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
types: types,
|
||||||
|
records: [
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
type: "A",
|
||||||
|
value: "",
|
||||||
|
routeCodes: [],
|
||||||
|
ttl: 600,
|
||||||
|
index: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
lastIndex: 0,
|
||||||
|
isAddingRoutes: false // 是否正在添加线路
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.records.push({
|
||||||
|
name: "",
|
||||||
|
type: "A",
|
||||||
|
value: "",
|
||||||
|
routeCodes: [],
|
||||||
|
ttl: 600,
|
||||||
|
index: ++this.lastIndex
|
||||||
|
})
|
||||||
|
let that = this
|
||||||
|
setTimeout(function () {
|
||||||
|
that.$refs.nameInputs.$last().focus()
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
remove: function (index) {
|
||||||
|
this.records.$remove(index)
|
||||||
|
},
|
||||||
|
addRoutes: function () {
|
||||||
|
this.isAddingRoutes = true
|
||||||
|
},
|
||||||
|
cancelRoutes: function () {
|
||||||
|
let that = this
|
||||||
|
setTimeout(function () {
|
||||||
|
that.isAddingRoutes = false
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
changeRoutes: function (record, routes) {
|
||||||
|
if (routes == null) {
|
||||||
|
record.routeCodes = []
|
||||||
|
} else {
|
||||||
|
record.routeCodes = routes.map(function (route) {
|
||||||
|
return route.code
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<input type="hidden" name="recordsJSON" :value="JSON.stringify(records)"/>
|
||||||
|
<table class="ui table selectable celled" style="max-width: 60em">
|
||||||
|
<thead class="full-width">
|
||||||
|
<tr>
|
||||||
|
<th style="width:10em">记录名</th>
|
||||||
|
<th style="width:7em">记录类型</th>
|
||||||
|
<th>线路</th>
|
||||||
|
<th v-if="!isAddingRoutes">记录值</th>
|
||||||
|
<th v-if="!isAddingRoutes">TTL</th>
|
||||||
|
<th class="one op" v-if="!isAddingRoutes">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr v-for="(record, index) in records" :key="record.index">
|
||||||
|
<td>
|
||||||
|
<input type="text" style="width:10em" v-model="record.name" ref="nameInputs"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select class="ui dropdown auto-width" v-model="record.type">
|
||||||
|
<option v-for="type in types" :value="type.type">{{type.type}}</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ns-routes-selector @add="addRoutes" @cancel="cancelRoutes" @change="changeRoutes(record, $event)"></ns-routes-selector>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<input type="text" style="width:10em" maxlength="512" v-model="record.value"/>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<div class="ui input right labeled">
|
||||||
|
<input type="text" v-model="record.ttl" style="width:5em" maxlength="8"/>
|
||||||
|
<span class="ui label">秒</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td v-if="!isAddingRoutes">
|
||||||
|
<a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove"></i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
|
||||||
|
</div>`,
|
||||||
|
})
|
||||||
39
web/public/js/components/ns/ns-domain-group-selector.js
Normal file
39
web/public/js/components/ns/ns-domain-group-selector.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
Vue.component("ns-domain-group-selector", {
|
||||||
|
props: ["v-domain-group-id"],
|
||||||
|
data: function () {
|
||||||
|
let groupId = this.vDomainGroupId
|
||||||
|
if (groupId == null) {
|
||||||
|
groupId = 0
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
userId: 0,
|
||||||
|
groupId: groupId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
change: function (group) {
|
||||||
|
if (group != null) {
|
||||||
|
this.$emit("change", group.id)
|
||||||
|
} else {
|
||||||
|
this.$emit("change", 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reload: function (userId) {
|
||||||
|
this.userId = userId
|
||||||
|
this.$refs.comboBox.clear()
|
||||||
|
this.$refs.comboBox.setDataURL("/ns/domains/groups/options?userId=" + userId)
|
||||||
|
this.$refs.comboBox.reloadData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `<div>
|
||||||
|
<combo-box
|
||||||
|
data-url="/ns/domains/groups/options"
|
||||||
|
placeholder="选择分组"
|
||||||
|
data-key="groups"
|
||||||
|
name="groupId"
|
||||||
|
:v-value="groupId"
|
||||||
|
@change="change"
|
||||||
|
ref="comboBox">
|
||||||
|
</combo-box>
|
||||||
|
</div>`
|
||||||
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// 选择多个线路
|
// 选择多个线路
|
||||||
Vue.component("ns-routes-selector", {
|
Vue.component("ns-routes-selector", {
|
||||||
props: ["v-routes"],
|
props: ["v-routes", "name"],
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
let that = this
|
let that = this
|
||||||
Tea.action("/ns/routes/options")
|
Tea.action("/ns/routes/options")
|
||||||
@@ -15,12 +15,18 @@ Vue.component("ns-routes-selector", {
|
|||||||
selectedRoutes = []
|
selectedRoutes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inputName = this.name
|
||||||
|
if (typeof inputName != "string" || inputName.length == 0) {
|
||||||
|
inputName = "routeCodes"
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
routeCode: "default",
|
routeCode: "default",
|
||||||
|
inputName: inputName,
|
||||||
routes: [],
|
routes: [],
|
||||||
isAdding: false,
|
isAdding: false,
|
||||||
routeType: "default",
|
routeType: "default",
|
||||||
selectedRoutes: selectedRoutes
|
selectedRoutes: selectedRoutes,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -39,9 +45,11 @@ Vue.component("ns-routes-selector", {
|
|||||||
this.isAdding = true
|
this.isAdding = true
|
||||||
this.routeType = "default"
|
this.routeType = "default"
|
||||||
this.routeCode = "default"
|
this.routeCode = "default"
|
||||||
|
this.$emit("add")
|
||||||
},
|
},
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
this.isAdding = false
|
this.isAdding = false
|
||||||
|
this.$emit("cancel")
|
||||||
},
|
},
|
||||||
confirm: function () {
|
confirm: function () {
|
||||||
if (this.routeCode.length == 0) {
|
if (this.routeCode.length == 0) {
|
||||||
@@ -54,17 +62,19 @@ Vue.component("ns-routes-selector", {
|
|||||||
that.selectedRoutes.push(v)
|
that.selectedRoutes.push(v)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.$emit("change", this.selectedRoutes)
|
||||||
this.cancel()
|
this.cancel()
|
||||||
},
|
},
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
this.selectedRoutes.$remove(index)
|
this.selectedRoutes.$remove(index)
|
||||||
|
this.$emit("change", this.selectedRoutes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<div>
|
<div v-show="selectedRoutes.length > 0">
|
||||||
<div class="ui label basic text small" v-for="(route, index) in selectedRoutes" style="margin-bottom: 0.3em">
|
<div class="ui label basic text small" v-for="(route, index) in selectedRoutes" style="margin-bottom: 0.3em">
|
||||||
<input type="hidden" name="routeCodes" :value="route.code"/>
|
<input type="hidden" :name="inputName" :value="route.code"/>
|
||||||
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
{{route.name}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|||||||
@@ -1,28 +1,14 @@
|
|||||||
Vue.component("ns-user-selector", {
|
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"],
|
props: ["v-user-id"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
return {}
|
||||||
if (userId == null) {
|
},
|
||||||
userId = 0
|
methods: {
|
||||||
}
|
change: function (userId) {
|
||||||
return {
|
this.$emit("change", userId)
|
||||||
users: [],
|
|
||||||
userId: userId
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/ns/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -1,33 +1,14 @@
|
|||||||
Vue.component("plan-user-selector", {
|
Vue.component("plan-user-selector", {
|
||||||
mounted: function () {
|
|
||||||
let that = this
|
|
||||||
|
|
||||||
Tea.action("/plans/users/options")
|
|
||||||
.post()
|
|
||||||
.success(function (resp) {
|
|
||||||
that.users = resp.data.users
|
|
||||||
})
|
|
||||||
},
|
|
||||||
props: ["v-user-id"],
|
props: ["v-user-id"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
return {}
|
||||||
if (userId == null) {
|
|
||||||
userId = 0
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
users: [],
|
|
||||||
userId: userId
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
methods: {
|
||||||
userId: function (v) {
|
change: function (userId) {
|
||||||
this.$emit("change", v)
|
this.$emit("change", userId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<select class="ui dropdown auto-width" name="userId" v-model="userId">
|
<user-selector :v-user-id="vUserId" data-url="/plans/users/options" @change="change"></user-selector>
|
||||||
<option value="0">[选择用户]</option>
|
|
||||||
<option v-for="user in users" :value="user.id">{{user.fullname}} ({{user.username}})</option>
|
|
||||||
</select>
|
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -21,6 +21,8 @@ Vue.component("http-cache-ref-box", {
|
|||||||
conds: null,
|
conds: null,
|
||||||
allowChunkedEncoding: true,
|
allowChunkedEncoding: true,
|
||||||
allowPartialContent: false,
|
allowPartialContent: false,
|
||||||
|
enableIfNoneMatch: false,
|
||||||
|
enableIfModifiedSince: false,
|
||||||
isReverse: this.vIsReverse,
|
isReverse: this.vIsReverse,
|
||||||
methods: [],
|
methods: [],
|
||||||
expiresTime: {
|
expiresTime: {
|
||||||
@@ -192,5 +194,19 @@ Vue.component("http-cache-ref-box", {
|
|||||||
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
<p class="comment">选中后,当请求的Header中含有Pragma: no-cache或Cache-Control: no-cache时,会跳过缓存直接读取源内容。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||||
|
<td>允许If-None-Match回源</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="ref.enableIfNoneMatch"></checkbox>
|
||||||
|
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-show="moreOptionsVisible && !vIsReverse">
|
||||||
|
<td>允许If-Modified-Since回源</td>
|
||||||
|
<td>
|
||||||
|
<checkbox v-model="ref.enableIfModifiedSince"></checkbox>
|
||||||
|
<p class="comment">特殊情况下才需要开启,可能会降低缓存命中率。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>`
|
</tbody>`
|
||||||
})
|
})
|
||||||
@@ -53,6 +53,8 @@ Vue.component("http-cache-refs-box", {
|
|||||||
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
||||||
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
||||||
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfNoneMatch">If-None-Match</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfModifiedSince">If-Modified-Since</grey-label>
|
||||||
</td>
|
</td>
|
||||||
<td :class="{disabled: !cacheRef.isOn}">
|
<td :class="{disabled: !cacheRef.isOn}">
|
||||||
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ Vue.component("http-cache-refs-config-box", {
|
|||||||
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
<grey-label v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</grey-label>
|
||||||
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
<grey-label v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码:{{cacheRef.status.map(function(v) {return v.toString()}).join(", ")}}</grey-label>
|
||||||
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
<grey-label v-if="cacheRef.allowPartialContent">区间缓存</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfNoneMatch">If-None-Match</grey-label>
|
||||||
|
<grey-label v-if="cacheRef.enableIfModifiedSince">If-Modified-Since</grey-label>
|
||||||
</td>
|
</td>
|
||||||
<td :class="{disabled: !cacheRef.isOn}">
|
<td :class="{disabled: !cacheRef.isOn}">
|
||||||
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
<span v-if="cacheRef.conds.connector == 'and'">和</span>
|
||||||
|
|||||||
@@ -71,6 +71,12 @@ Vue.component("http-location-labels", {
|
|||||||
<!-- 请求脚本 -->
|
<!-- 请求脚本 -->
|
||||||
<http-location-labels-label v-if="location.web != null && location.web.requestScripts != null && ((location.web.requestScripts.initGroup != null && location.web.requestScripts.initGroup.isPrior) || (location.web.requestScripts.requestGroup != null && location.web.requestScripts.requestGroup.isPrior))" :href="url('/requestScripts')">请求脚本</http-location-labels-label>
|
<http-location-labels-label v-if="location.web != null && location.web.requestScripts != null && ((location.web.requestScripts.initGroup != null && location.web.requestScripts.initGroup.isPrior) || (location.web.requestScripts.requestGroup != null && location.web.requestScripts.requestGroup.isPrior))" :href="url('/requestScripts')">请求脚本</http-location-labels-label>
|
||||||
|
|
||||||
|
<!-- 自定义访客IP地址 -->
|
||||||
|
<http-location-labels-label v-if="location.web != null && location.web.remoteAddr != null && location.web.remoteAddr.isPrior" :href="url('/remoteAddr')" :class="{disabled: !location.web.remoteAddr.isOn}">访客IP地址</http-location-labels-label>
|
||||||
|
|
||||||
|
<!-- 请求限制 -->
|
||||||
|
<http-location-labels-label v-if="location.web != null && location.web.requestLimit != null && location.web.requestLimit.isPrior" :href="url('/requestLimit')" :class="{disabled: !location.web.requestLimit.isOn}">请求限制</http-location-labels-label>
|
||||||
|
|
||||||
<!-- 自定义页面 -->
|
<!-- 自定义页面 -->
|
||||||
<div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0">
|
<div v-if="location.web != null && location.web.pages != null && location.web.pages.length > 0">
|
||||||
<div v-for="page in location.web.pages" :key="page.id"><http-location-labels-label :href="url('/pages')">PAGE [状态码{{page.status[0]}}] -> {{page.url}}</http-location-labels-label></div>
|
<div v-for="page in location.web.pages" :key="page.id"><http-location-labels-label :href="url('/pages')">PAGE [状态码{{page.status[0]}}] -> {{page.url}}</http-location-labels-label></div>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ Vue.component("http-request-limit-config-box", {
|
|||||||
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||||
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">是否启用</td>
|
<td class="title">启用</td>
|
||||||
<td>
|
<td>
|
||||||
<checkbox v-model="config.isOn"></checkbox>
|
<checkbox v-model="config.isOn"></checkbox>
|
||||||
</td>
|
</td>
|
||||||
@@ -73,14 +73,14 @@ Vue.component("http-request-limit-config-box", {
|
|||||||
<td>最大并发连接数</td>
|
<td>最大并发连接数</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" maxlength="6" v-model="maxConns"/>
|
<input type="text" maxlength="6" v-model="maxConns"/>
|
||||||
<p class="comment">当前服务最大并发连接数。为0表示不限制。</p>
|
<p class="comment">当前服务最大并发连接数,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>单IP最大并发连接数</td>
|
<td>单IP最大并发连接数</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
<input type="text" maxlength="6" v-model="maxConnsPerIP"/>
|
||||||
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务。为0表示不限制。</p>
|
<p class="comment">单IP最大连接数,统计单个IP总连接数时不区分服务,超出此限制则响应用户<code-label>429</code-label>代码。为0表示不限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ Vue.component("origin-list-table", {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr v-for="origin in vOrigins">
|
<tr v-for="origin in vOrigins">
|
||||||
<td :class="{disabled:!origin.isOn}"><a href="" @click.prevent="updateOrigin(origin.id)">{{origin.addr}} <i class="icon expand small"></i></a>
|
<td :class="{disabled:!origin.isOn}">
|
||||||
|
<a href="" @click.prevent="updateOrigin(origin.id)" :class="{disabled:!origin.isOn}">{{origin.addr}} <i class="icon expand small"></i></a>
|
||||||
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || origin.followPort || (origin.domains != null && origin.domains.length > 0)">
|
<div style="margin-top: 0.3em" v-if="origin.name.length > 0 || origin.hasCert || (origin.host != null && origin.host.length > 0) || origin.followPort || (origin.domains != null && origin.domains.length > 0)">
|
||||||
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
|
<tiny-basic-label v-if="origin.name.length > 0">{{origin.name}}</tiny-basic-label>
|
||||||
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
|
<tiny-basic-label v-if="origin.hasCert">证书</tiny-basic-label>
|
||||||
|
|||||||
@@ -1,21 +1,32 @@
|
|||||||
Vue.component("user-selector", {
|
Vue.component("user-selector", {
|
||||||
props: ["v-user-id"],
|
props: ["v-user-id", "data-url"],
|
||||||
data: function () {
|
data: function () {
|
||||||
let userId = this.vUserId
|
let userId = this.vUserId
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
userId = 0
|
userId = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dataURL = this.dataUrl
|
||||||
|
if (dataURL == null || dataURL.length == 0) {
|
||||||
|
dataURL = "/servers/users/options"
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users: [],
|
users: [],
|
||||||
userId: userId
|
userId: userId,
|
||||||
|
dataURL: dataURL
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
methods: {
|
||||||
userId: function (v) {
|
change: function(item) {
|
||||||
this.$emit("change", v)
|
if (item != null) {
|
||||||
|
this.$emit("change", item.id)
|
||||||
|
} else {
|
||||||
|
this.$emit("change", 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `<div>
|
template: `<div>
|
||||||
<combo-box placeholder="选择用户" :data-url="'/servers/users/options'" :data-key="'users'" name="userId" :v-value="userId"></combo-box>
|
<combo-box placeholder="选择用户" :data-url="dataURL" :data-key="'users'" data-search="on" name="userId" :v-value="userId" @change="change"></combo-box>
|
||||||
</div>`
|
</div>`
|
||||||
})
|
})
|
||||||
@@ -755,6 +755,10 @@ var.dash {
|
|||||||
.page a:hover {
|
.page a:hover {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
.page select {
|
||||||
|
padding-top: 0.3em !important;
|
||||||
|
padding-bottom: 0.3em !important;
|
||||||
|
}
|
||||||
/** popup **/
|
/** popup **/
|
||||||
.swal2-html-container {
|
.swal2-html-container {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -782,6 +782,11 @@ var.dash {
|
|||||||
a:hover {
|
a:hover {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
padding-top: 0.3em !important;
|
||||||
|
padding-bottom: 0.3em !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** popup **/
|
/** popup **/
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
<h3>安装步骤</h3>
|
<h3>安装步骤</h3>
|
||||||
<ol class="ui list">
|
<ol class="ui list">
|
||||||
<li>按照下面的配置信息替换<code-label>configs/api.yaml</code-label>内容</li>
|
<li>按照下面的配置信息替换<code-label>configs/api.yaml</code-label>内容;如果文件不存在,请先创建</li>
|
||||||
<li>按照下面的配置信息替换<code-label>configs/db.yaml</code-label>内容</li>
|
<li>按照下面的配置信息替换<code-label>configs/db.yaml</code-label>内容;如果文件不存在,请先创建</li>
|
||||||
<li>使用<code-label>bin/edge-api start</code-label>启动节点</li>
|
<li>使用<code-label>bin/edge-api start</code-label>启动节点</li>
|
||||||
<li>可以在<code-label>logs/run.log</code-label>中查看启动是否有异常</li>
|
<li>可以在<code-label>logs/run.log</code-label>中查看启动是否有异常</li>
|
||||||
|
<li>配置修改后,使用<code-label>bin/edge-api restart</code-label>重启节点</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|||||||
@@ -212,7 +212,9 @@ Tea.context(function () {
|
|||||||
})
|
})
|
||||||
.timeout(300)
|
.timeout(300)
|
||||||
.success(function () {
|
.success(function () {
|
||||||
teaweb.reload()
|
this.$delay(function () {
|
||||||
|
teaweb.reload()
|
||||||
|
}, 5000)
|
||||||
})
|
})
|
||||||
.done(function () {
|
.done(function () {
|
||||||
this.isRestartingLocalAPINode = false
|
this.isRestartingLocalAPINode = false
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<option value="">[请选择]</option>
|
<option value="">[请选择]</option>
|
||||||
<option v-for="type in types" :value="type.code">{{type.name}}</option>
|
<option v-for="type in types" :value="type.code">{{type.name}}</option>
|
||||||
</select>
|
</select>
|
||||||
<p class="comment">{{typeDescription}}</p>
|
<p class="comment">{{typeDescription}} <span v-if="!teaIsPlus">购买商业版可获得更多厂商支持。</span></p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -173,6 +173,24 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
||||||
|
<!-- DNS.LA -->
|
||||||
|
<tbody v-if="type == 'dnsla'">
|
||||||
|
<tr>
|
||||||
|
<td>API ID *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="paramDNSLaAPIId" maxlength="100"/>
|
||||||
|
<p class="comment">在DNS.LA控制台我的账户菜单--API设置中创建和查看。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>API密钥 *</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="paramDNSLaSecret" maxlength="100"/>
|
||||||
|
<p class="comment">在DNS.LA控制台我的账户菜单--API设置中创建和查看。</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
<!-- Edge DNS -->
|
<!-- Edge DNS -->
|
||||||
<tbody v-if="type == 'localEdgeDNS'">
|
<tbody v-if="type == 'localEdgeDNS'">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user