mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-27 12:39:01 +08:00
feat: 增加主机工具箱管理 (#3001)
This commit is contained in:
parent
6c7e9d0a52
commit
c260b858bf
183
backend/app/api/v1/device.go
Normal file
183
backend/app/api/v1/device.go
Normal file
@ -0,0 +1,183 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Load device base info
|
||||
// @Description 获取设备基础信息
|
||||
// @Success 200 {object} dto.DeviceBaseInfo
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/base [get]
|
||||
func (b *BaseApi) LoadDeviceBaseInfo(c *gin.Context) {
|
||||
data, err := deviceService.LoadBaseInfo()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary list time zone options
|
||||
// @Description 获取系统可用时区选项
|
||||
// @Accept json
|
||||
// @Success 200 {Array} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/zone/options [get]
|
||||
func (b *BaseApi) LoadTimeOption(c *gin.Context) {
|
||||
list, err := deviceService.LoadTimeZone()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary load conf
|
||||
// @Description 获取系统配置文件
|
||||
// @Accept json
|
||||
// @Param request body dto.OperationWithName true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/conf [post]
|
||||
func (b *BaseApi) LoadDeviceConf(c *gin.Context) {
|
||||
var req dto.OperationWithName
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list, err := deviceService.LoadConf(req.Name)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device conf by file
|
||||
// @Description 通过文件修改配置
|
||||
// @Accept json
|
||||
// @Param request body dto.UpdateByNameAndFile true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/byconf [post]
|
||||
func (b *BaseApi) UpdateDevicByFile(c *gin.Context) {
|
||||
var req dto.UpdateByNameAndFile
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := deviceService.UpdateByConf(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device
|
||||
// @Description 修改系统参数
|
||||
// @Accept json
|
||||
// @Param request body dto.SettingUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/conf [post]
|
||||
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改主机参数 [key] => [value]","formatEN":"update device conf [key] => [value]"}
|
||||
func (b *BaseApi) UpdateDeviceConf(c *gin.Context) {
|
||||
var req dto.SettingUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := deviceService.Update(req.Key, req.Value); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device hosts
|
||||
// @Description 修改系统 hosts
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/host [post]
|
||||
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"修改主机 Host [key] => [value]","formatEN":"update device host [key] => [value]"}
|
||||
func (b *BaseApi) UpdateDeviceHost(c *gin.Context) {
|
||||
var req []dto.HostHelper
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := deviceService.UpdateHosts(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Update device passwd
|
||||
// @Description 修改系统密码
|
||||
// @Accept json
|
||||
// @Param request body dto.ChangePasswd true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/update/passwd [post]
|
||||
func (b *BaseApi) UpdateDevicPasswd(c *gin.Context) {
|
||||
var req dto.ChangePasswd
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if len(req.Passwd) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Passwd)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Passwd = string(password)
|
||||
}
|
||||
if err := deviceService.UpdatePasswd(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Device
|
||||
// @Summary Check device DNS conf
|
||||
// @Description 检查系统 DNS 配置可用性
|
||||
// @Accept json
|
||||
// @Param request body dto.SettingUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /toolbox/device/check/dns [post]
|
||||
func (b *BaseApi) CheckDNS(c *gin.Context) {
|
||||
var req dto.SettingUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := deviceService.CheckDNS(req.Key, req.Value)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
@ -33,6 +33,7 @@ var (
|
||||
sshService = service.NewISSHService()
|
||||
firewallService = service.NewIFirewallService()
|
||||
|
||||
deviceService = service.NewIDeviceService()
|
||||
fail2banService = service.NewIFail2BanService()
|
||||
|
||||
settingService = service.NewISettingService()
|
||||
|
@ -217,43 +217,6 @@ func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load time zone options
|
||||
// @Description 加载系统可用时区
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/time/option [get]
|
||||
func (b *BaseApi) LoadTimeZone(c *gin.Context) {
|
||||
zones, err := settingService.LoadTimeZone()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, zones)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Sync system time
|
||||
// @Description 系统时间同步
|
||||
// @Accept json
|
||||
// @Param request body dto.SyncTime true "request"
|
||||
// @Success 200 {string} ntime
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/time/sync [post]
|
||||
// @x-panel-log {"bodyKeys":["ntpSite"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"系统时间同步[ntpSite]","formatEN":"sync system time [ntpSite]"}
|
||||
func (b *BaseApi) SyncTime(c *gin.Context) {
|
||||
var req dto.SyncTime
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := settingService.SyncTime(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Load local backup dir
|
||||
// @Description 获取安装根目录
|
||||
|
@ -45,6 +45,11 @@ type UpdateByFile struct {
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type UpdateByNameAndFile struct {
|
||||
Name string `json:"name"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type OperationWithNameAndType struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
|
26
backend/app/dto/device.go
Normal file
26
backend/app/dto/device.go
Normal file
@ -0,0 +1,26 @@
|
||||
package dto
|
||||
|
||||
type DeviceBaseInfo struct {
|
||||
DNS []string `json:"dns"`
|
||||
Hosts []HostHelper `json:"hosts"`
|
||||
Hostname string `json:"hostname"`
|
||||
TimeZone string `json:"timeZone"`
|
||||
LocalTime string `json:"localTime"`
|
||||
Ntp string `json:"ntp"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
type HostHelper struct {
|
||||
IP string `json:"ip"`
|
||||
Host string `json:"host"`
|
||||
}
|
||||
|
||||
type TimeZoneOptions struct {
|
||||
From string `json:"from"`
|
||||
Zones []string `json:"zones"`
|
||||
}
|
||||
|
||||
type ChangePasswd struct {
|
||||
User string `json:"user"`
|
||||
Passwd string `json:"passwd"`
|
||||
}
|
293
backend/app/service/device.go
Normal file
293
backend/app/service/device.go
Normal file
@ -0,0 +1,293 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
|
||||
)
|
||||
|
||||
const defaultDNSPath = "/etc/resolv.conf"
|
||||
const defaultHostPath = "/etc/hosts"
|
||||
|
||||
type DeviceService struct{}
|
||||
|
||||
type IDeviceService interface {
|
||||
LoadBaseInfo() (dto.DeviceBaseInfo, error)
|
||||
Update(key, value string) error
|
||||
UpdateHosts(req []dto.HostHelper) error
|
||||
UpdatePasswd(req dto.ChangePasswd) error
|
||||
UpdateByConf(req dto.UpdateByNameAndFile) error
|
||||
LoadTimeZone() ([]string, error)
|
||||
CheckDNS(key, value string) (bool, error)
|
||||
LoadConf(name string) (string, error)
|
||||
}
|
||||
|
||||
func NewIDeviceService() IDeviceService {
|
||||
return &DeviceService{}
|
||||
}
|
||||
|
||||
func (u *DeviceService) LoadBaseInfo() (dto.DeviceBaseInfo, error) {
|
||||
var baseInfo dto.DeviceBaseInfo
|
||||
baseInfo.LocalTime = time.Now().Format("2006-01-02 15:04:05 MST -0700")
|
||||
baseInfo.TimeZone = common.LoadTimeZoneByCmd()
|
||||
baseInfo.DNS = loadDNS()
|
||||
baseInfo.Hosts = loadHosts()
|
||||
baseInfo.Hostname = loadHostname()
|
||||
baseInfo.User = loadUser()
|
||||
ntp, _ := settingRepo.Get(settingRepo.WithByKey("NtpSite"))
|
||||
baseInfo.Ntp = ntp.Value
|
||||
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) LoadTimeZone() ([]string, error) {
|
||||
std, err := cmd.Exec("timedatectl list-timezones")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return strings.Split(std, "\n"), nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) CheckDNS(key, value string) (bool, error) {
|
||||
content, err := os.ReadFile(defaultDNSPath)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer func() { _ = u.UpdateByConf(dto.UpdateByNameAndFile{Name: "DNS", File: string(content)}) }()
|
||||
if key == "form" {
|
||||
if err := u.Update("DNS", value); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
if err := u.UpdateByConf(dto.UpdateByNameAndFile{Name: "DNS", File: value}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("ip4:icmp", "www.baidu.com", time.Second*2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) Update(key, value string) error {
|
||||
switch key {
|
||||
case "TimeZone":
|
||||
if err := ntp.UpdateSystemTimeZone(value); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
||||
if err != nil {
|
||||
global.LOG.Errorf("restart system for new time zone failed, err: %v", err)
|
||||
}
|
||||
}()
|
||||
case "DNS":
|
||||
if err := updateDNS(strings.Split(value, ",")); err != nil {
|
||||
return err
|
||||
}
|
||||
case "Hostname":
|
||||
std, err := cmd.Execf("%s hostnamectl set-hostname %s", cmd.SudoHandleCmd(), value)
|
||||
if err != nil {
|
||||
return errors.New(std)
|
||||
}
|
||||
case "LocalTime":
|
||||
if err := settingRepo.Update("NtpSite", value); err != nil {
|
||||
return err
|
||||
}
|
||||
ntime, err := ntp.GetRemoteTime(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts := ntime.Format("2006-01-02 15:04:05")
|
||||
if err := ntp.UpdateSystemTime(ts); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("not support such key %s", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdateHosts(req []dto.HostHelper) error {
|
||||
conf, err := os.ReadFile(defaultHostPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read namesever conf of %s failed, err: %v", defaultHostPath, err)
|
||||
}
|
||||
lines := strings.Split(string(conf), "\n")
|
||||
newFile := ""
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
newFile += line + "\n"
|
||||
continue
|
||||
}
|
||||
for index, item := range req {
|
||||
if item.IP == parts[0] && item.Host == strings.Join(parts[1:], " ") {
|
||||
newFile += line + "\n"
|
||||
req = append(req[:index], req[index+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, item := range req {
|
||||
newFile += fmt.Sprintf("%s %s \n", item.IP, item.Host)
|
||||
}
|
||||
file, err := os.OpenFile(defaultHostPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(newFile)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdatePasswd(req dto.ChangePasswd) error {
|
||||
std, err := cmd.Execf("%s echo '%s:%s' | %s chpasswd", cmd.SudoHandleCmd(), req.User, req.Passwd, cmd.SudoHandleCmd())
|
||||
if err != nil {
|
||||
return errors.New(std)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) LoadConf(name string) (string, error) {
|
||||
pathItem := ""
|
||||
switch name {
|
||||
case "DNS":
|
||||
pathItem = defaultDNSPath
|
||||
case "Hosts":
|
||||
pathItem = defaultHostPath
|
||||
default:
|
||||
return "", fmt.Errorf("not support such name %s", name)
|
||||
}
|
||||
if _, err := os.Stat(pathItem); err != nil {
|
||||
return "", err
|
||||
}
|
||||
content, err := os.ReadFile(pathItem)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(content), nil
|
||||
}
|
||||
|
||||
func (u *DeviceService) UpdateByConf(req dto.UpdateByNameAndFile) error {
|
||||
if req.Name != "DNS" && req.Name != "Hosts" {
|
||||
return fmt.Errorf("not support such name %s", req.Name)
|
||||
}
|
||||
path := defaultDNSPath
|
||||
if req.Name == "Hosts" {
|
||||
path = defaultHostPath
|
||||
}
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(req.File)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadDNS() []string {
|
||||
var list []string
|
||||
dnsConf, err := os.ReadFile(defaultDNSPath)
|
||||
if err == nil {
|
||||
lines := strings.Split(string(dnsConf), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "nameserver ") {
|
||||
list = append(list, strings.TrimPrefix(line, "nameserver "))
|
||||
}
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func updateDNS(list []string) error {
|
||||
conf, err := os.ReadFile(defaultDNSPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read nameserver conf of %s failed, err: %v", defaultDNSPath, err)
|
||||
}
|
||||
lines := strings.Split(string(conf), "\n")
|
||||
newFile := ""
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 || parts[0] != "nameserver" {
|
||||
newFile += line + "\n"
|
||||
continue
|
||||
}
|
||||
itemNs := strings.Join(parts[1:], " ")
|
||||
for index, item := range list {
|
||||
if item == itemNs {
|
||||
newFile += line + "\n"
|
||||
list = append(list[:index], list[index+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, item := range list {
|
||||
newFile += fmt.Sprintf("nameserver %s \n", item)
|
||||
}
|
||||
file, err := os.OpenFile(defaultDNSPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
write := bufio.NewWriter(file)
|
||||
_, _ = write.WriteString(newFile)
|
||||
write.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadHosts() []dto.HostHelper {
|
||||
var list []dto.HostHelper
|
||||
hostConf, err := os.ReadFile(defaultHostPath)
|
||||
if err == nil {
|
||||
lines := strings.Split(string(hostConf), "\n")
|
||||
for _, line := range lines {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
list = append(list, dto.HostHelper{IP: parts[0], Host: strings.Join(parts[1:], " ")})
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func loadHostname() string {
|
||||
std, err := cmd.Exec("hostname")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.ReplaceAll(std, "\n", "")
|
||||
}
|
||||
|
||||
func loadUser() string {
|
||||
std, err := cmd.Exec("whoami")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.ReplaceAll(std, "\n", "")
|
||||
}
|
@ -21,7 +21,6 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/robfig/cron/v3"
|
||||
@ -32,7 +31,6 @@ type SettingService struct{}
|
||||
type ISettingService interface {
|
||||
GetSettingInfo() (*dto.SettingInfo, error)
|
||||
LoadInterfaceAddr() ([]string, error)
|
||||
LoadTimeZone() ([]string, error)
|
||||
Update(key, value string) error
|
||||
UpdatePassword(c *gin.Context, old, new string) error
|
||||
UpdatePort(port uint) error
|
||||
@ -40,7 +38,6 @@ type ISettingService interface {
|
||||
UpdateSSL(c *gin.Context, req dto.SSLUpdate) error
|
||||
LoadFromCert() (*dto.SSLInfo, error)
|
||||
HandlePasswordExpired(c *gin.Context, old, new string) error
|
||||
SyncTime(req dto.SyncTime) error
|
||||
|
||||
SystemScan() dto.CleanData
|
||||
SystemClean(req []dto.Clean)
|
||||
@ -72,14 +69,6 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
|
||||
return &info, err
|
||||
}
|
||||
|
||||
func (u *SettingService) LoadTimeZone() ([]string, error) {
|
||||
std, err := cmd.Exec("timedatectl list-timezones")
|
||||
if err != nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
return strings.Split(std, "\n"), err
|
||||
}
|
||||
|
||||
func (u *SettingService) Update(key, value string) error {
|
||||
switch key {
|
||||
case "MonitorStatus":
|
||||
@ -107,10 +96,6 @@ func (u *SettingService) Update(key, value string) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case "TimeZone":
|
||||
if err := ntp.UpdateSystemTimeZone(value); err != nil {
|
||||
return err
|
||||
}
|
||||
case "AppStoreLastModified":
|
||||
exist, _ := settingRepo.Get(settingRepo.WithByKey("AppStoreLastModified"))
|
||||
if exist.ID == 0 {
|
||||
@ -129,13 +114,6 @@ func (u *SettingService) Update(key, value string) error {
|
||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
|
||||
return err
|
||||
}
|
||||
case "TimeZone":
|
||||
go func() {
|
||||
_, err := cmd.Exec("systemctl restart 1panel.service")
|
||||
if err != nil {
|
||||
global.LOG.Errorf("restart system for new time zone failed, err: %v", err)
|
||||
}
|
||||
}()
|
||||
case "BindDomain":
|
||||
if len(value) != 0 {
|
||||
_ = global.SESSION.Clean()
|
||||
@ -148,21 +126,6 @@ func (u *SettingService) Update(key, value string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SettingService) SyncTime(req dto.SyncTime) error {
|
||||
if err := settingRepo.Update("NtpSite", req.NtpSite); err != nil {
|
||||
return err
|
||||
}
|
||||
ntime, err := ntp.GetRemoteTime(req.NtpSite)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts := ntime.Format("2006-01-02 15:04:05")
|
||||
if err := ntp.UpdateSystemTime(ts); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SettingService) LoadInterfaceAddr() ([]string, error) {
|
||||
addrMap := make(map[string]struct{})
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
|
@ -29,8 +29,6 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
|
||||
settingRouter.GET("/ssl/info", baseApi.LoadFromCert)
|
||||
settingRouter.POST("/ssl/download", baseApi.DownloadSSL)
|
||||
settingRouter.POST("/password/update", baseApi.UpdatePassword)
|
||||
settingRouter.GET("/time/option", baseApi.LoadTimeZone)
|
||||
settingRouter.POST("/time/sync", baseApi.SyncTime)
|
||||
settingRouter.POST("/monitor/clean", baseApi.CleanMonitor)
|
||||
settingRouter.POST("/mfa", baseApi.LoadMFA)
|
||||
settingRouter.POST("/mfa/bind", baseApi.MFABind)
|
||||
|
@ -16,6 +16,15 @@ func (s *ToolboxRouter) InitToolboxRouter(Router *gin.RouterGroup) {
|
||||
Use(middleware.PasswordExpired())
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
toolboxRouter.GET("/device/base", baseApi.LoadDeviceBaseInfo)
|
||||
toolboxRouter.GET("/device/zone/options", baseApi.LoadTimeOption)
|
||||
toolboxRouter.POST("/device/update/conf", baseApi.UpdateDeviceConf)
|
||||
toolboxRouter.POST("/device/update/host", baseApi.UpdateDeviceHost)
|
||||
toolboxRouter.POST("/device/update/passwd", baseApi.UpdateDevicPasswd)
|
||||
toolboxRouter.POST("/device/update/byconf", baseApi.UpdateDevicByFile)
|
||||
toolboxRouter.POST("/device/check/dns", baseApi.CheckDNS)
|
||||
toolboxRouter.POST("/device/conf", baseApi.LoadDeviceConf)
|
||||
|
||||
toolboxRouter.GET("/fail2ban/base", baseApi.LoadFail2BanBaseInfo)
|
||||
toolboxRouter.GET("/fail2ban/load/conf", baseApi.LoadFail2BanConf)
|
||||
toolboxRouter.POST("/fail2ban/search", baseApi.SearchFail2Ban)
|
||||
|
@ -1,61 +0,0 @@
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssh"
|
||||
)
|
||||
|
||||
func TestCds(t *testing.T) {
|
||||
kk := ssh.ConnInfo{
|
||||
Port: 22,
|
||||
AuthMode: "password",
|
||||
User: "root",
|
||||
}
|
||||
sd, err := kk.Run("fail2ban-client get sshd ignoreip")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
sd = strings.ReplaceAll(sd, "|", "")
|
||||
sd = strings.ReplaceAll(sd, "`", "")
|
||||
sd = strings.ReplaceAll(sd, "\n", "")
|
||||
|
||||
addrs := strings.Split(sd, "-")
|
||||
for _, addr := range addrs {
|
||||
if !strings.HasPrefix(addr, " ") {
|
||||
continue
|
||||
}
|
||||
fmt.Println(strings.TrimPrefix(addr, " "))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCdsxx(t *testing.T) {
|
||||
initFile := `#DEFAULT-START
|
||||
[DEFAULT]
|
||||
ignoreip = 127.0.0.1/8,172.16.10.114,172.16.10.116
|
||||
bantime = 600
|
||||
findtime = 300
|
||||
maxretry = 5
|
||||
banaction = firewallcmd-ipset
|
||||
action = %(action_mwl)s
|
||||
#DEFAULT-END
|
||||
|
||||
#sshd-START
|
||||
[sshd]
|
||||
enabled = true
|
||||
filter = sshd
|
||||
port = 22
|
||||
maxretry = 5
|
||||
findtime = 300
|
||||
bantime = 86400
|
||||
action = %(action_mwl)s
|
||||
logpath = /var/log/secure
|
||||
#sshd-END`
|
||||
|
||||
if err := os.WriteFile("/Users/slooop/Downloads/tex.txt", []byte(initFile), 0640); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
// Code generated by swaggo/swag. DO NOT EDIT.
|
||||
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
@ -9906,70 +9906,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/option": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "加载系统可用时区",
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load time zone options",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/sync": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "系统时间同步",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Sync system time",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SyncTime"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"ntpSite"
|
||||
],
|
||||
"formatEN": "sync system time [ntpSite]",
|
||||
"formatZH": "系统时间同步[ntpSite]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -10086,6 +10022,257 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/base": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取设备基础信息",
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Load device base info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.DeviceBaseInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/check/dns": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "检查系统 DNS 配置可用性",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Check device DNS conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/conf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取系统配置文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "load conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.OperationWithName"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/byconf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "通过文件修改配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device conf by file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpdateByNameAndFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/conf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统参数",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"key",
|
||||
"value"
|
||||
],
|
||||
"formatEN": "update device conf [key] =\u003e [value]",
|
||||
"formatZH": "修改主机参数 [key] =\u003e [value]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/host": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统 hosts",
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device hosts",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"key",
|
||||
"value"
|
||||
],
|
||||
"formatEN": "update device host [key] =\u003e [value]",
|
||||
"formatZH": "修改主机 Host [key] =\u003e [value]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/passwd": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统密码",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device passwd",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ChangePasswd"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/zone/options": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取系统可用时区选项",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "list time zone options",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "Array"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/fail2ban/base": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -13094,6 +13281,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ChangePasswd": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"passwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ChangeRedisPass": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -14202,6 +14400,38 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.DeviceBaseInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
"hosts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.HostHelper"
|
||||
}
|
||||
},
|
||||
"localTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"ntp": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.DiskInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -14546,6 +14776,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.HostHelper": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"host": {
|
||||
"type": "string"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.HostOperate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -16290,17 +16531,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SyncTime": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ntpSite"
|
||||
],
|
||||
"properties": {
|
||||
"ntpSite": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.TreeChild": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -16320,6 +16550,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UpdateByNameAndFile": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UpdateDescription": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -9899,70 +9899,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/option": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "加载系统可用时区",
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Load time zone options",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/time/sync": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "系统时间同步",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Sync system time",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SyncTime"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"ntpSite"
|
||||
],
|
||||
"formatEN": "sync system time [ntpSite]",
|
||||
"formatZH": "系统时间同步[ntpSite]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
@ -10079,6 +10015,257 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/base": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取设备基础信息",
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Load device base info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.DeviceBaseInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/check/dns": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "检查系统 DNS 配置可用性",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Check device DNS conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/conf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取系统配置文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "load conf",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.OperationWithName"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/byconf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "通过文件修改配置",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device conf by file",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpdateByNameAndFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/conf": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统参数",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SettingUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"key",
|
||||
"value"
|
||||
],
|
||||
"formatEN": "update device conf [key] =\u003e [value]",
|
||||
"formatZH": "修改主机参数 [key] =\u003e [value]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/host": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统 hosts",
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device hosts",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFunctions": [],
|
||||
"bodyKeys": [
|
||||
"key",
|
||||
"value"
|
||||
],
|
||||
"formatEN": "update device host [key] =\u003e [value]",
|
||||
"formatZH": "修改主机 Host [key] =\u003e [value]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/update/passwd": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改系统密码",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "Update device passwd",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.ChangePasswd"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/device/zone/options": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取系统可用时区选项",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "list time zone options",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "Array"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/toolbox/fail2ban/base": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -13087,6 +13274,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ChangePasswd": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"passwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.ChangeRedisPass": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -14195,6 +14393,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.DeviceBaseInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hostname": {
|
||||
"type": "string"
|
||||
},
|
||||
"hosts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.HostHelper"
|
||||
}
|
||||
},
|
||||
"localTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"ntp": {
|
||||
"type": "string"
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.DiskInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -14539,6 +14769,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.HostHelper": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"host": {
|
||||
"type": "string"
|
||||
},
|
||||
"ip": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.HostOperate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@ -16283,17 +16524,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SyncTime": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ntpSite"
|
||||
],
|
||||
"properties": {
|
||||
"ntpSite": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.TreeChild": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -16313,6 +16543,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UpdateByNameAndFile": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UpdateDescription": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -176,6 +176,13 @@ definitions:
|
||||
- groupID
|
||||
- id
|
||||
type: object
|
||||
dto.ChangePasswd:
|
||||
properties:
|
||||
passwd:
|
||||
type: string
|
||||
user:
|
||||
type: string
|
||||
type: object
|
||||
dto.ChangeRedisPass:
|
||||
properties:
|
||||
value:
|
||||
@ -923,6 +930,27 @@ definitions:
|
||||
- username
|
||||
- version
|
||||
type: object
|
||||
dto.DeviceBaseInfo:
|
||||
properties:
|
||||
dns:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
hostname:
|
||||
type: string
|
||||
hosts:
|
||||
items:
|
||||
$ref: '#/definitions/dto.HostHelper'
|
||||
type: array
|
||||
localTime:
|
||||
type: string
|
||||
ntp:
|
||||
type: string
|
||||
timeZone:
|
||||
type: string
|
||||
user:
|
||||
type: string
|
||||
type: object
|
||||
dto.DiskInfo:
|
||||
properties:
|
||||
device:
|
||||
@ -1158,6 +1186,13 @@ definitions:
|
||||
- port
|
||||
- user
|
||||
type: object
|
||||
dto.HostHelper:
|
||||
properties:
|
||||
host:
|
||||
type: string
|
||||
ip:
|
||||
type: string
|
||||
type: object
|
||||
dto.HostOperate:
|
||||
properties:
|
||||
addr:
|
||||
@ -2334,13 +2369,6 @@ definitions:
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
dto.SyncTime:
|
||||
properties:
|
||||
ntpSite:
|
||||
type: string
|
||||
required:
|
||||
- ntpSite
|
||||
type: object
|
||||
dto.TreeChild:
|
||||
properties:
|
||||
id:
|
||||
@ -2353,6 +2381,13 @@ definitions:
|
||||
file:
|
||||
type: string
|
||||
type: object
|
||||
dto.UpdateByNameAndFile:
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
type: object
|
||||
dto.UpdateDescription:
|
||||
properties:
|
||||
description:
|
||||
@ -10774,46 +10809,6 @@ paths:
|
||||
formatEN: update system ssl => [ssl]
|
||||
formatZH: 修改系统 ssl => [ssl]
|
||||
paramKeys: []
|
||||
/settings/time/option:
|
||||
get:
|
||||
description: 加载系统可用时区
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load time zone options
|
||||
tags:
|
||||
- System Setting
|
||||
/settings/time/sync:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 系统时间同步
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SyncTime'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Sync system time
|
||||
tags:
|
||||
- System Setting
|
||||
x-panel-log:
|
||||
BeforeFunctions: []
|
||||
bodyKeys:
|
||||
- ntpSite
|
||||
formatEN: sync system time [ntpSite]
|
||||
formatZH: 系统时间同步[ntpSite]
|
||||
paramKeys: []
|
||||
/settings/update:
|
||||
post:
|
||||
consumes:
|
||||
@ -10888,6 +10883,161 @@ paths:
|
||||
formatEN: upgrade service => [version]
|
||||
formatZH: 更新系统 => [version]
|
||||
paramKeys: []
|
||||
/toolbox/device/base:
|
||||
get:
|
||||
description: 获取设备基础信息
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.DeviceBaseInfo'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Load device base info
|
||||
tags:
|
||||
- Device
|
||||
/toolbox/device/check/dns:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 检查系统 DNS 配置可用性
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SettingUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Check device DNS conf
|
||||
tags:
|
||||
- Device
|
||||
/toolbox/device/conf:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取系统配置文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.OperationWithName'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: load conf
|
||||
tags:
|
||||
- Device
|
||||
/toolbox/device/update/byconf:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 通过文件修改配置
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UpdateByNameAndFile'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update device conf by file
|
||||
tags:
|
||||
- Device
|
||||
/toolbox/device/update/conf:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改系统参数
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SettingUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update device
|
||||
tags:
|
||||
- Device
|
||||
x-panel-log:
|
||||
BeforeFunctions: []
|
||||
bodyKeys:
|
||||
- key
|
||||
- value
|
||||
formatEN: update device conf [key] => [value]
|
||||
formatZH: 修改主机参数 [key] => [value]
|
||||
paramKeys: []
|
||||
/toolbox/device/update/host:
|
||||
post:
|
||||
description: 修改系统 hosts
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update device hosts
|
||||
tags:
|
||||
- Device
|
||||
x-panel-log:
|
||||
BeforeFunctions: []
|
||||
bodyKeys:
|
||||
- key
|
||||
- value
|
||||
formatEN: update device host [key] => [value]
|
||||
formatZH: 修改主机 Host [key] => [value]
|
||||
paramKeys: []
|
||||
/toolbox/device/update/passwd:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改系统密码
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.ChangePasswd'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update device passwd
|
||||
tags:
|
||||
- Device
|
||||
/toolbox/device/zone/options:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取系统可用时区选项
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: Array
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: list time zone options
|
||||
tags:
|
||||
- Device
|
||||
/toolbox/fail2ban/base:
|
||||
get:
|
||||
description: 获取 Fail2Ban 基础信息
|
||||
|
@ -1,4 +1,22 @@
|
||||
export namespace Toolbox {
|
||||
export interface DeviceBaseInfo {
|
||||
dns: Array<string>;
|
||||
hosts: Array<HostHelper>;
|
||||
hostname: string;
|
||||
ntp: string;
|
||||
user: string;
|
||||
timeZone: string;
|
||||
localTime: string;
|
||||
}
|
||||
export interface HostHelper {
|
||||
ip: string;
|
||||
host: string;
|
||||
}
|
||||
export interface TimeZoneOptions {
|
||||
from: string;
|
||||
zones: Array<string>;
|
||||
}
|
||||
|
||||
export interface Fail2banBaseInfo {
|
||||
isEnable: boolean;
|
||||
isActive: boolean;
|
||||
|
@ -1,6 +1,33 @@
|
||||
import http from '@/api';
|
||||
import { UpdateByFile } from '../interface';
|
||||
import { Toolbox } from '../interface/toolbox';
|
||||
import { Base64 } from 'js-base64';
|
||||
|
||||
// device
|
||||
export const getDeviceBase = () => {
|
||||
return http.get<Toolbox.DeviceBaseInfo>(`/toolbox/device/base`);
|
||||
};
|
||||
export const loadTimeZoneOptions = () => {
|
||||
return http.get<Array<string>>(`/toolbox/device/zone/options`);
|
||||
};
|
||||
export const updateDevice = (key: string, value: string) => {
|
||||
return http.post(`/toolbox/device/update/conf`, { key: key, value: value });
|
||||
};
|
||||
export const updateDeviceHost = (param: Array<Toolbox.TimeZoneOptions>) => {
|
||||
return http.post(`/toolbox/device/update/host`, param);
|
||||
};
|
||||
export const updateDevicePasswd = (user: string, passwd: string) => {
|
||||
return http.post(`/toolbox/device/update/passwd`, { user: user, passwd: Base64.encode(passwd) });
|
||||
};
|
||||
export const updateDeviceByConf = (name: string, file: string) => {
|
||||
return http.post(`/toolbox/device/update/byconf`, { name: name, file: file });
|
||||
};
|
||||
export const checkDNS = (key: string, value: string) => {
|
||||
return http.post(`/toolbox/device/check/dns`, { key: key, value: value });
|
||||
};
|
||||
export const loadDeviceConf = (name: string) => {
|
||||
return http.post(`/toolbox/device/conf`, { name: name });
|
||||
};
|
||||
|
||||
// fail2ban
|
||||
export const getFail2banBase = () => {
|
||||
|
@ -873,6 +873,37 @@ const message = {
|
||||
emptyTerminal: 'No terminal is currently connected',
|
||||
},
|
||||
toolbox: {
|
||||
device: {
|
||||
dnsHelper: 'Server Address Domain Resolution',
|
||||
hostsHelper: 'Hostname Resolution',
|
||||
hosts: 'Domain',
|
||||
toolbox: 'Toolbox',
|
||||
hostname: 'Hostname',
|
||||
passwd: 'Host Password',
|
||||
passwdHelper: 'Input characters cannot include $ and &',
|
||||
timeZone: 'System Time Zone',
|
||||
localTime: 'Server Time',
|
||||
timeZoneChangeHelper: 'Modifying the system time zone requires restarting the service. Continue?',
|
||||
timeZoneHelper:
|
||||
'Time zone modification depends on the timedatectl command. If not installed, the modification may fail.',
|
||||
timeZoneCN: 'Beijing',
|
||||
timeZoneAM: 'Los Angeles',
|
||||
timeZoneNY: 'New York',
|
||||
ntpALi: 'Alibaba',
|
||||
ntpGoogle: 'Google',
|
||||
syncSite: 'NTP Server',
|
||||
hostnameHelper:
|
||||
'Hostname modification depends on the hostnamectl command. If not installed, the modification may fail.',
|
||||
userHelper:
|
||||
'The username depends on the whoami command for retrieval. If not installed, retrieval may fail.',
|
||||
passwordHelper:
|
||||
'Password modification depends on the chpasswd command. If not installed, the modification may fail.',
|
||||
hostHelper:
|
||||
'There is an empty value in the provided content. Please check and try again after modification!',
|
||||
dnsCheck: 'Test Availability',
|
||||
dnsOK: 'DNS configuration information is available!',
|
||||
dnsTestFailed: 'DNS configuration information is not available. Please modify and try again!',
|
||||
},
|
||||
fail2ban: {
|
||||
noFail2ban: 'Fail2Ban service not detected, please refer to the official documentation for installation',
|
||||
unActive: 'The Fail2Ban service is not enabled at present, please enable it first!',
|
||||
|
@ -837,6 +837,32 @@ const message = {
|
||||
emptyTerminal: '暫無終端連接',
|
||||
},
|
||||
toolbox: {
|
||||
device: {
|
||||
dnsHelper: '伺服器地址域名解析',
|
||||
hostsHelper: '主機名解析',
|
||||
hosts: '域名',
|
||||
toolbox: '工具箱',
|
||||
hostname: '主機名',
|
||||
passwd: '主機密碼',
|
||||
passwdHelper: '輸入的字符不能包含 $ 和 &',
|
||||
timeZone: '系統時區',
|
||||
localTime: '伺服器時間',
|
||||
timeZoneChangeHelper: '修改系統時區需要重新啟動服務,是否繼續?',
|
||||
timeZoneHelper: '時區修改依賴於 timedatectl 命令,如未安裝可能導致修改失敗',
|
||||
timeZoneCN: '北京',
|
||||
timeZoneAM: '洛杉磯',
|
||||
timeZoneNY: '紐約',
|
||||
ntpALi: '阿里',
|
||||
ntpGoogle: '谷歌',
|
||||
syncSite: 'NTP 伺服器',
|
||||
hostnameHelper: '主機名修改依賴於 hostnamectl 命令,如未安裝可能導致修改失敗',
|
||||
userHelper: '用戶名依賴於 whoami 命令獲取,如未安裝可能導致獲取失敗。',
|
||||
passwordHelper: '密碼修改依賴於 chpasswd 命令,如未安裝可能導致修改失敗',
|
||||
hostHelper: '填寫的內容中存在空值,請檢查修改後重試!',
|
||||
dnsCheck: '測試可用性',
|
||||
dnsOK: 'DNS 配置信息可用!',
|
||||
dnsTestFailed: 'DNS 配置信息不可用,請修改後重試!',
|
||||
},
|
||||
fail2ban: {
|
||||
noFail2ban: '未檢測到 Fail2Ban 服務,請參考官方文檔進行安裝',
|
||||
unActive: '當前未開啟 Fail2Ban 服務,請先開啟!',
|
||||
@ -1055,16 +1081,6 @@ const message = {
|
||||
systemIP: '服務器地址',
|
||||
systemIPWarning: '當前未設置服務器地址,請先在面板設置中設置!',
|
||||
defaultNetwork: '默認網卡',
|
||||
syncTime: '服務器時間',
|
||||
timeZone: '系統時區',
|
||||
timeZoneChangeHelper: '系統時區修改需要重啟服務,是否繼續?',
|
||||
timeZoneHelper: '時區修改依賴於系統 timedatectl 服務,重啟 1Panel 服務後生效。',
|
||||
timeZoneCN: '北京',
|
||||
timeZoneAM: '洛杉磯',
|
||||
timeZoneNY: '紐約',
|
||||
ntpALi: '阿裏',
|
||||
ntpGoogle: '谷歌',
|
||||
syncSite: 'NTP 服務器',
|
||||
syncSiteHelper: '該操作將使用 {0} 作為源進行系統時間同步,是否繼續?',
|
||||
changePassword: '密碼修改',
|
||||
oldPassword: '原密碼',
|
||||
|
@ -838,6 +838,32 @@ const message = {
|
||||
emptyTerminal: '暂无终端连接',
|
||||
},
|
||||
toolbox: {
|
||||
device: {
|
||||
dnsHelper: '服务器地址域名解析',
|
||||
hostsHelper: '主机名解析',
|
||||
hosts: '域名',
|
||||
toolbox: '工具箱',
|
||||
hostname: '主机名',
|
||||
passwd: '主机密码',
|
||||
passwdHelper: '输入字符不能包含 $ 和 &',
|
||||
timeZone: '系统时区',
|
||||
localTime: '服务器时间',
|
||||
timeZoneChangeHelper: '系统时区修改需要重启服务,是否继续?',
|
||||
timeZoneHelper: '时区修改依赖于 timedatectl 命令,如未安装可能导致修改失败',
|
||||
timeZoneCN: '北京',
|
||||
timeZoneAM: '洛杉矶',
|
||||
timeZoneNY: '纽约',
|
||||
ntpALi: '阿里',
|
||||
ntpGoogle: '谷歌',
|
||||
syncSite: 'NTP 服务器',
|
||||
hostnameHelper: '主机名修改依赖于 hostnamectl 命令,如未安装可能导致修改失败',
|
||||
userHelper: '用户名依赖于 whoami 命令获取,如未安装可能导致获取失败。',
|
||||
passwordHelper: '密码修改依赖于 chpasswd 命令,如未安装可能导致修改失败',
|
||||
hostHelper: '填写的内容中存在空值,请检查修改后重试!',
|
||||
dnsCheck: '测试可用性',
|
||||
dnsOK: 'DNS 配置信息可用!',
|
||||
dnsTestFailed: 'DNS 配置信息不可用,请修改后重试!',
|
||||
},
|
||||
fail2ban: {
|
||||
noFail2ban: '未检测到 Fail2Ban 服务,请参考官方文档进行安装',
|
||||
unActive: '当前未开启 Fail2Ban 服务,请先开启!',
|
||||
@ -1056,16 +1082,6 @@ const message = {
|
||||
systemIP: '服务器地址',
|
||||
systemIPWarning: '当前未设置服务器地址,请先在面板设置中设置!',
|
||||
defaultNetwork: '默认网卡',
|
||||
syncTime: '服务器时间',
|
||||
timeZone: '系统时区',
|
||||
timeZoneChangeHelper: '系统时区修改需要重启服务,是否继续?',
|
||||
timeZoneHelper: '时区修改依赖于系统 timedatectl 服务,重启 1Panel 服务后生效。',
|
||||
timeZoneCN: '北京',
|
||||
timeZoneAM: '洛杉矶',
|
||||
timeZoneNY: '纽约',
|
||||
ntpALi: '阿里',
|
||||
ntpGoogle: '谷歌',
|
||||
syncSite: 'NTP 服务器',
|
||||
syncSiteHelper: '该操作将使用 {0} 作为源进行系统时间同步,是否继续?',
|
||||
changePassword: '密码修改',
|
||||
oldPassword: '原密码',
|
||||
|
@ -13,10 +13,20 @@ const toolboxRouter = {
|
||||
{
|
||||
path: '/toolbox',
|
||||
name: 'Toolbox',
|
||||
redirect: '/toolbox/supervisor',
|
||||
redirect: '/toolbox/device',
|
||||
component: () => import('@/views/toolbox/index.vue'),
|
||||
meta: {},
|
||||
children: [
|
||||
{
|
||||
path: 'device',
|
||||
name: 'Device',
|
||||
component: () => import('@/views/toolbox/device/index.vue'),
|
||||
hidden: true,
|
||||
meta: {
|
||||
activeMenu: '/toolbox',
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'supervisor',
|
||||
name: 'Supervisor',
|
||||
|
@ -93,24 +93,6 @@
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('setting.timeZone')" prop="timeZone">
|
||||
<el-input disabled v-model.number="form.timeZone">
|
||||
<template #append>
|
||||
<el-button @click="onChangeTimeZone" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.syncTime')">
|
||||
<el-input disabled v-model="form.localTime">
|
||||
<template #append>
|
||||
<el-button v-show="!show" @click="onChangeNtp" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.systemIP')" prop="systemIP">
|
||||
<el-input disabled v-if="form.systemIP" v-model="form.systemIP">
|
||||
<template #append>
|
||||
@ -138,8 +120,6 @@
|
||||
<PanelName ref="panelNameRef" @search="search()" />
|
||||
<SystemIP ref="systemIPRef" @search="search()" />
|
||||
<Timeout ref="timeoutRef" @search="search()" />
|
||||
<TimeZone ref="timezoneRef" @search="search()" />
|
||||
<Ntp ref="ntpRef" @search="search()" />
|
||||
<Network ref="networkRef" @search="search()" />
|
||||
<Clean ref="cleanRef" @search="search()" />
|
||||
</div>
|
||||
@ -158,10 +138,8 @@ import UserName from '@/views/setting/panel/username/index.vue';
|
||||
import Timeout from '@/views/setting/panel/timeout/index.vue';
|
||||
import PanelName from '@/views/setting/panel/name/index.vue';
|
||||
import SystemIP from '@/views/setting/panel/systemip/index.vue';
|
||||
import TimeZone from '@/views/setting/panel/timezone/index.vue';
|
||||
import Network from '@/views/setting/panel/default-network/index.vue';
|
||||
import Clean from '@/views/setting/panel/clean/index.vue';
|
||||
import Ntp from '@/views/setting/panel/ntp/index.vue';
|
||||
|
||||
const loading = ref(false);
|
||||
const i18n = useI18n();
|
||||
@ -197,8 +175,6 @@ const passwordRef = ref();
|
||||
const panelNameRef = ref();
|
||||
const systemIPRef = ref();
|
||||
const timeoutRef = ref();
|
||||
const ntpRef = ref();
|
||||
const timezoneRef = ref();
|
||||
const networkRef = ref();
|
||||
const cleanRef = ref();
|
||||
const unset = ref(i18n.t('setting.unSetting'));
|
||||
@ -239,12 +215,6 @@ const onChangeTimeout = () => {
|
||||
const onChangeSystemIP = () => {
|
||||
systemIPRef.value.acceptParams({ systemIP: form.systemIP });
|
||||
};
|
||||
const onChangeTimeZone = () => {
|
||||
timezoneRef.value.acceptParams({ timeZone: form.timeZone });
|
||||
};
|
||||
const onChangeNtp = () => {
|
||||
ntpRef.value.acceptParams({ localTime: form.localTime, ntpSite: form.ntpSite });
|
||||
};
|
||||
const onChangeNetwork = () => {
|
||||
networkRef.value.acceptParams({ defaultNetwork: form.defaultNetwork });
|
||||
};
|
||||
|
161
frontend/src/views/toolbox/device/dns/index.vue
Normal file
161
frontend/src/views/toolbox/device/dns/index.vue
Normal file
@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader header="DNS" :back="handleClose" />
|
||||
</template>
|
||||
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-radio-group v-model="confShowType" @change="changeMode">
|
||||
<el-radio-button label="form">{{ $t('database.baseConf') }}</el-radio-button>
|
||||
<el-radio-button label="all">{{ $t('database.allConf') }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-form
|
||||
class="mt-4"
|
||||
v-if="confShowType === 'form'"
|
||||
ref="formRef"
|
||||
label-position="top"
|
||||
@submit.prevent
|
||||
:model="form"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-form-item label="DNS" prop="dns">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:placeholder="$t('setting.allowIPEgs')"
|
||||
:autosize="{ minRows: 8, maxRows: 10 }"
|
||||
v-model="form.dns"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div v-else>
|
||||
<codemirror
|
||||
:autofocus="true"
|
||||
placeholder="# The DNS configuration file does not exist or is empty (/etc/resolv.conf)"
|
||||
:indent-with-tab="true"
|
||||
:tabSize="4"
|
||||
style="margin-top: 10px; height: calc(100vh - 200px)"
|
||||
:lineWrapping="true"
|
||||
:matchBrackets="true"
|
||||
theme="cobalt"
|
||||
:styleActiveLine="true"
|
||||
:extensions="extensions"
|
||||
v-model="dnsConf"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button :disabled="loading" @click="onTest()">
|
||||
{{ $t('toolbox.device.dnsCheck') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSave()">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { loadDeviceConf, checkDNS, updateDevice, updateDeviceByConf } from '@/api/modules/toolbox';
|
||||
import { Codemirror } from 'vue-codemirror';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
const extensions = [javascript(), oneDark];
|
||||
const confShowType = ref('form');
|
||||
const dnsConf = ref();
|
||||
|
||||
const form = reactive({
|
||||
dns: '',
|
||||
});
|
||||
|
||||
interface DialogProps {
|
||||
dns: Array<string>;
|
||||
}
|
||||
|
||||
const drawerVisible = ref();
|
||||
const loading = ref();
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
form.dns = params.dns ? params.dns.join('\n') : '';
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const loadDNSConf = async () => {
|
||||
const res = await loadDeviceConf('DNS');
|
||||
dnsConf.value = res.data || '';
|
||||
};
|
||||
|
||||
const changeMode = async () => {
|
||||
if (confShowType.value === 'all') {
|
||||
loadDNSConf();
|
||||
}
|
||||
};
|
||||
|
||||
const onTest = async () => {
|
||||
loading.value = true;
|
||||
let value = '';
|
||||
if (confShowType.value === 'form') {
|
||||
value = form.dns.replaceAll('\n', ',');
|
||||
} else {
|
||||
value = dnsConf.value;
|
||||
}
|
||||
await checkDNS(confShowType.value, value)
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
if (res.data) {
|
||||
MsgSuccess(i18n.global.t('toolbox.device.dnsOK'));
|
||||
} else {
|
||||
MsgError(i18n.global.t('toolbox.device.dnsTestFailed'));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onSave = async () => {
|
||||
loading.value = true;
|
||||
if (confShowType.value == 'form') {
|
||||
await updateDevice('DNS', form.dns.replaceAll('\n', ','))
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
handleClose();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await updateDeviceByConf('DNS', dnsConf.value)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
handleClose();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const handleClose = () => {
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
100
frontend/src/views/toolbox/device/hostname/index.vue
Normal file
100
frontend/src/views/toolbox/device/hostname/index.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('toolbox.device.hostname')" :back="handleClose" />
|
||||
</template>
|
||||
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-alert
|
||||
:title="$t('toolbox.device.hostnameHelper')"
|
||||
class="common-prompt"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
/>
|
||||
<el-form ref="formRef" label-position="top" :model="form" @submit.prevent v-loading="loading">
|
||||
<el-form-item
|
||||
:label="$t('toolbox.device.hostname')"
|
||||
prop="hostname"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input clearable v-model.trim="form.hostname" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSaveHostame(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { updateDevice } from '@/api/modules/toolbox';
|
||||
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
interface DialogProps {
|
||||
hostname: string;
|
||||
}
|
||||
const drawerVisible = ref();
|
||||
const loading = ref();
|
||||
|
||||
const form = reactive({
|
||||
hostname: '',
|
||||
});
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
form.hostname = params.hostname;
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const onSaveHostame = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('ssh.sshChangeHelper', [i18n.global.t('toolbox.device.hostname'), form.hostname]),
|
||||
i18n.global.t('database.confChange'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
).then(async () => {
|
||||
await updateDevice('Hostname', form.hostname)
|
||||
.then(async () => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
loading.value = false;
|
||||
drawerVisible.value = false;
|
||||
emit('search');
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
167
frontend/src/views/toolbox/device/hosts/index.vue
Normal file
167
frontend/src/views/toolbox/device/hosts/index.vue
Normal file
@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader header="Hosts" :back="handleClose" />
|
||||
</template>
|
||||
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-radio-group v-model="confShowType" @change="changeMode">
|
||||
<el-radio-button label="base">{{ $t('database.baseConf') }}</el-radio-button>
|
||||
<el-radio-button label="all">{{ $t('database.allConf') }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<table style="width: 100%" class="mt-4" v-if="confShowType === 'base'">
|
||||
<tr v-if="form.hosts.length !== 0">
|
||||
<th scope="col" width="25%" align="left">
|
||||
<label>IP</label>
|
||||
</th>
|
||||
<th scope="col" width="70%" align="left">
|
||||
<label>{{ $t('toolbox.device.hosts') }}</label>
|
||||
</th>
|
||||
<th align="left"></th>
|
||||
</tr>
|
||||
<tr v-for="(row, index) in form.hosts" :key="index">
|
||||
<td width="25%">
|
||||
<el-input placeholder="172.16.10.111" v-model="row.ip" />
|
||||
</td>
|
||||
<td width="70%">
|
||||
<el-input placeholder="test.hostname.com" v-model="row.host" />
|
||||
</td>
|
||||
<td>
|
||||
<el-button link type="primary" @click="handleHostsDelete(index)">
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<el-button @click="handleHostsAdd()">{{ $t('commons.button.add') }}</el-button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div v-else>
|
||||
<codemirror
|
||||
:autofocus="true"
|
||||
placeholder="# The hosts configuration file does not exist or is empty (/etc/hosts)"
|
||||
:indent-with-tab="true"
|
||||
:tabSize="4"
|
||||
style="margin-top: 10px; height: calc(100vh - 200px)"
|
||||
:lineWrapping="true"
|
||||
:matchBrackets="true"
|
||||
theme="cobalt"
|
||||
:styleActiveLine="true"
|
||||
:extensions="extensions"
|
||||
v-model="hostsConf"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSave()">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { loadDeviceConf, updateDeviceByConf, updateDeviceHost } from '@/api/modules/toolbox';
|
||||
import { Codemirror } from 'vue-codemirror';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { Toolbox } from '@/api/interface/toolbox';
|
||||
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
const extensions = [javascript(), oneDark];
|
||||
const confShowType = ref('base');
|
||||
const hostsConf = ref();
|
||||
|
||||
const form = reactive({
|
||||
hosts: [],
|
||||
});
|
||||
|
||||
interface DialogProps {
|
||||
hosts: Array<Toolbox.HostHelper>;
|
||||
}
|
||||
|
||||
const drawerVisible = ref();
|
||||
const loading = ref();
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
confShowType.value = 'base';
|
||||
form.hosts = params.hosts;
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const loadHostsConf = async () => {
|
||||
const res = await loadDeviceConf('Hosts');
|
||||
hostsConf.value = res.data || '';
|
||||
};
|
||||
|
||||
const changeMode = async () => {
|
||||
if (confShowType.value === 'all') {
|
||||
loadHostsConf();
|
||||
}
|
||||
};
|
||||
|
||||
const handleHostsAdd = () => {
|
||||
let item = {
|
||||
ip: '',
|
||||
host: '',
|
||||
};
|
||||
form.hosts.push(item);
|
||||
};
|
||||
const handleHostsDelete = (index: number) => {
|
||||
form.hosts.splice(index, 1);
|
||||
};
|
||||
|
||||
const onSave = async () => {
|
||||
for (const item of form.hosts) {
|
||||
if (item.ip === '' || item.host === '') {
|
||||
MsgError(i18n.global.t('toolbox.device.hostHelper'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
loading.value = true;
|
||||
if (confShowType.value === 'base') {
|
||||
await updateDeviceHost(form.hosts)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
handleClose();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await updateDeviceByConf('Hosts', hostsConf.value)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
handleClose();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
146
frontend/src/views/toolbox/device/index.vue
Normal file
146
frontend/src/views/toolbox/device/index.vue
Normal file
@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<LayoutContent :title="$t('toolbox.device.toolbox')" :divider="true">
|
||||
<template #main>
|
||||
<el-row style="margin-top: 20px">
|
||||
<el-col :span="1"><br /></el-col>
|
||||
<el-col :xs="24" :sm="20" :md="20" :lg="10" :xl="10">
|
||||
<el-form :model="form" label-position="left" ref="formRef" label-width="120px">
|
||||
<el-form-item label="DNS" prop="dnsItem">
|
||||
<el-input disabled v-model="form.dnsItem">
|
||||
<template #append>
|
||||
<el-button @click="onChangeDNS" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Hosts" prop="hosts">
|
||||
<el-input disabled v-model="form.hostItem">
|
||||
<template #append>
|
||||
<el-button @click="onChangeHost" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('toolbox.device.hostname')" prop="hostname">
|
||||
<el-input disabled v-model="form.hostname">
|
||||
<template #append>
|
||||
<el-button @click="onChangeHostname" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('toolbox.device.passwd')" prop="passwd">
|
||||
<el-input disabled v-model="form.passwd">
|
||||
<template #append>
|
||||
<el-button @click="onChangePasswd" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('toolbox.device.timeZone')" prop="timeZone">
|
||||
<el-input disabled v-model="form.timeZone">
|
||||
<template #append>
|
||||
<el-button @click="onChangeTimeZone" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('toolbox.device.localTime')" prop="localTime">
|
||||
<el-input disabled v-model="form.localTime">
|
||||
<template #append>
|
||||
<el-button @click="onChangeLocalTime" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
</LayoutContent>
|
||||
|
||||
<Passwd ref="passwdRef" @search="search" />
|
||||
<TimeZone ref="timeZoneRef" @search="search" />
|
||||
<LocalTime ref="localTimeRef" @search="search" />
|
||||
<DNS ref="dnsRef" @search="search" />
|
||||
<Hostname ref="hostnameRef" @search="search" />
|
||||
<Hosts ref="hostsRef" @search="search" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import Passwd from '@/views/toolbox/device/passwd/index.vue';
|
||||
import TimeZone from '@/views/toolbox/device/time-zone/index.vue';
|
||||
import LocalTime from '@/views/toolbox/device/local-time/index.vue';
|
||||
import DNS from '@/views/toolbox/device/dns/index.vue';
|
||||
import Hostname from '@/views/toolbox/device/hostname/index.vue';
|
||||
import Hosts from '@/views/toolbox/device/hosts/index.vue';
|
||||
import { getDeviceBase } from '@/api/modules/toolbox';
|
||||
import i18n from '@/lang';
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
const timeZoneRef = ref();
|
||||
const localTimeRef = ref();
|
||||
const passwdRef = ref();
|
||||
const dnsRef = ref();
|
||||
const hostnameRef = ref();
|
||||
const hostsRef = ref();
|
||||
|
||||
const form = reactive({
|
||||
dns: [],
|
||||
dnsItem: '',
|
||||
hosts: [],
|
||||
hostItem: '',
|
||||
hostname: '',
|
||||
user: '',
|
||||
passwd: '******',
|
||||
timeZone: '',
|
||||
localTime: '',
|
||||
ntp: '',
|
||||
});
|
||||
|
||||
const onChangeTimeZone = () => {
|
||||
timeZoneRef.value.acceptParams({ timeZone: form.timeZone });
|
||||
};
|
||||
const onChangeLocalTime = () => {
|
||||
localTimeRef.value.acceptParams({ localTime: form.localTime, ntpSite: form.ntp });
|
||||
};
|
||||
const onChangePasswd = () => {
|
||||
passwdRef.value.acceptParams({ user: form.user });
|
||||
};
|
||||
const onChangeDNS = () => {
|
||||
dnsRef.value.acceptParams({ dns: form.dns });
|
||||
};
|
||||
const onChangeHostname = () => {
|
||||
hostnameRef.value.acceptParams({ hostname: form.hostname });
|
||||
};
|
||||
const onChangeHost = () => {
|
||||
hostsRef.value.acceptParams({ hosts: form.hosts });
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
const res = await getDeviceBase();
|
||||
form.timeZone = res.data.timeZone;
|
||||
form.localTime = res.data.localTime;
|
||||
form.hostname = res.data.hostname;
|
||||
form.ntp = res.data.ntp;
|
||||
form.user = res.data.user;
|
||||
form.dns = res.data.dns || [];
|
||||
form.dnsItem = form.dns ? i18n.global.t('toolbox.device.dnsHelper') : i18n.global.t('setting.unSetting');
|
||||
form.hosts = res.data.hosts || [];
|
||||
form.hostItem = form.hosts ? i18n.global.t('toolbox.device.hostsHelper') : i18n.global.t('setting.unSetting');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
@ -2,25 +2,25 @@
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('setting.syncTime')" :back="handleClose" />
|
||||
<DrawerHeader :header="$t('toolbox.device.localTime')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form ref="formRef" label-position="top" :model="form" @submit.prevent v-loading="loading">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('setting.syncSite')" prop="ntpSite" :rules="Rules.domain">
|
||||
<el-form-item :label="$t('toolbox.device.syncSite')" prop="ntpSite" :rules="Rules.domain">
|
||||
<el-input v-model="form.ntpSite" />
|
||||
<el-button type="primary" link class="tagClass" @click="form.ntpSite = 'pool.ntp.org'">
|
||||
{{ $t('website.default') }}
|
||||
</el-button>
|
||||
<el-button type="primary" link class="tagClass" @click="form.ntpSite = 'ntp.aliyun.com'">
|
||||
{{ $t('setting.ntpALi') }}
|
||||
{{ $t('toolbox.device.ntpALi') }}
|
||||
</el-button>
|
||||
<el-button type="primary" link class="tagClass" @click="form.ntpSite = 'time.google.com'">
|
||||
{{ $t('setting.ntpGoogle') }}
|
||||
{{ $t('toolbox.device.ntpGoogle') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('setting.syncTime')" prop="localTime">
|
||||
<el-form-item :label="$t('toolbox.device.localTime')" prop="localTime">
|
||||
<el-input v-model="form.localTime" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -41,10 +41,10 @@
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { syncTime } from '@/api/modules/setting';
|
||||
import { ElMessageBox, FormInstance } from 'element-plus';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { updateDevice } from '@/api/modules/toolbox';
|
||||
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
@ -73,8 +73,8 @@ const onSyncTime = async (formEl: FormInstance | undefined) => {
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('setting.syncSiteHelper', [form.ntpSite]),
|
||||
i18n.global.t('setting.syncSite'),
|
||||
i18n.global.t('toolbox.device.syncSiteHelper', [form.ntpSite]),
|
||||
i18n.global.t('toolbox.device.syncSite'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
@ -82,10 +82,9 @@ const onSyncTime = async (formEl: FormInstance | undefined) => {
|
||||
},
|
||||
).then(async () => {
|
||||
loading.value = true;
|
||||
await syncTime(form.ntpSite)
|
||||
.then((res) => {
|
||||
await updateDevice('LocalTime', form.ntpSite)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
form.localTime = res.data;
|
||||
emit('search');
|
||||
handleClose();
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
115
frontend/src/views/toolbox/device/passwd/index.vue
Normal file
115
frontend/src/views/toolbox/device/passwd/index.vue
Normal file
@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-drawer v-model="passwordVisible" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('setting.changePassword')" :back="handleClose" />
|
||||
</template>
|
||||
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form ref="formRef" label-position="top" :model="form" :rules="passRules">
|
||||
<el-alert
|
||||
:title="$t('toolbox.device.passwordHelper')"
|
||||
class="common-prompt"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
/>
|
||||
<el-form-item :label="$t('setting.user')" prop="user">
|
||||
<el-input clearable v-model.trim="form.user" />
|
||||
<span class="input-help">{{ $t('toolbox.device.userHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.newPassword')" prop="newPassword">
|
||||
<el-input type="password" show-password clearable v-model.trim="form.newPassword" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.retryPassword')" prop="retryPassword">
|
||||
<el-input type="password" show-password clearable v-model.trim="form.retryPassword" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="passwordVisible = false">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="submitChangePassword(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { updateDevicePasswd } from '@/api/modules/toolbox';
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const passRules = reactive({
|
||||
user: Rules.requiredInput,
|
||||
newPassword: [Rules.requiredInput, Rules.noSpace, { validator: checkPassword, trigger: 'blur' }],
|
||||
retryPassword: [Rules.requiredInput, Rules.noSpace, { validator: checkRePassword, trigger: 'blur' }],
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const passwordVisible = ref<boolean>(false);
|
||||
const form = reactive({
|
||||
user: '',
|
||||
newPassword: '',
|
||||
retryPassword: '',
|
||||
});
|
||||
|
||||
interface DialogProps {
|
||||
user: string;
|
||||
}
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
form.user = params.user;
|
||||
form.newPassword = '';
|
||||
form.retryPassword = '';
|
||||
passwordVisible.value = true;
|
||||
};
|
||||
|
||||
function checkPassword(rule: any, value: any, callback: any) {
|
||||
if (form.newPassword.indexOf('&') !== -1 || form.newPassword.indexOf('$') !== -1) {
|
||||
return callback(new Error(i18n.global.t('toolbox.device.passwdHelper')));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
function checkRePassword(rule: any, value: any, callback: any) {
|
||||
if (form.newPassword !== form.retryPassword) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.rePassword')));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
const submitChangePassword = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
await updateDevicePasswd(form.user, form.newPassword)
|
||||
.then(async () => {
|
||||
loading.value = false;
|
||||
passwordVisible.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
const handleClose = () => {
|
||||
passwordVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -2,19 +2,22 @@
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('setting.timeZone')" :back="handleClose" />
|
||||
<DrawerHeader :header="$t('toolbox.device.timeZone')" :back="handleClose" />
|
||||
</template>
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-alert
|
||||
v-if="canChangeZone()"
|
||||
:title="$t('setting.timeZoneHelper')"
|
||||
:title="$t('toolbox.device.timeZoneHelper')"
|
||||
class="common-prompt"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
/>
|
||||
<el-form ref="formRef" label-position="top" :model="form" @submit.prevent v-loading="loading">
|
||||
<el-form-item :label="$t('setting.timeZone')" prop="timeZone" :rules="Rules.requiredInput">
|
||||
<el-form-item
|
||||
:label="$t('toolbox.device.timeZone')"
|
||||
prop="timeZone"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-select filterable :disabled="canChangeZone()" v-model="form.timeZone">
|
||||
<el-option v-for="item in zones" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
@ -25,7 +28,7 @@
|
||||
class="tagClass"
|
||||
@click="form.timeZone = 'Asia/Shanghai'"
|
||||
>
|
||||
{{ $t('setting.timeZoneCN') }}
|
||||
{{ $t('toolbox.device.timeZoneCN') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
:disabled="canChangeZone()"
|
||||
@ -34,7 +37,7 @@
|
||||
class="tagClass"
|
||||
@click="form.timeZone = 'America/Los_Angeles'"
|
||||
>
|
||||
{{ $t('setting.timeZoneAM') }}
|
||||
{{ $t('toolbox.device.timeZoneAM') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
:disabled="canChangeZone()"
|
||||
@ -43,7 +46,7 @@
|
||||
class="tagClass"
|
||||
@click="form.timeZone = 'America/New_York'"
|
||||
>
|
||||
{{ $t('setting.timeZoneNY') }}
|
||||
{{ $t('toolbox.device.timeZoneNY') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -64,11 +67,11 @@
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { loadTimeZone, updateSetting } from '@/api/modules/setting';
|
||||
import { ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { GlobalStore } from '@/store';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { loadTimeZoneOptions, updateDevice } from '@/api/modules/toolbox';
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
interface DialogProps {
|
||||
@ -91,7 +94,7 @@ const acceptParams = (params: DialogProps): void => {
|
||||
};
|
||||
|
||||
const loadTimeZones = async () => {
|
||||
const res = await loadTimeZone();
|
||||
const res = await loadTimeZoneOptions();
|
||||
zones.value = res.data;
|
||||
};
|
||||
|
||||
@ -103,12 +106,16 @@ const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
ElMessageBox.confirm(i18n.global.t('setting.timeZoneChangeHelper'), i18n.global.t('setting.timeZone'), {
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
}).then(async () => {
|
||||
await updateSetting({ key: 'TimeZone', value: form.timeZone })
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('toolbox.device.timeZoneChangeHelper'),
|
||||
i18n.global.t('toolbox.device.timeZone'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
).then(async () => {
|
||||
await updateDevice('TimeZone', form.timeZone)
|
||||
.then(async () => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
@ -11,6 +11,10 @@
|
||||
import i18n from '@/lang';
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('toolbox.device.toolbox'),
|
||||
path: '/toolbox/device',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.supervisor'),
|
||||
path: '/toolbox/supervisor',
|
||||
|
Loading…
Reference in New Issue
Block a user