fix: Fix the problem of terminal saving failure (#8043)

This commit is contained in:
ssongliu 2025-03-03 10:18:55 +08:00 committed by GitHub
parent 5963e28b25
commit c3bd196a23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 205 additions and 134 deletions

View file

@ -137,24 +137,3 @@ func (b *BaseApi) LoadDashboardCurrentInfo(c *gin.Context) {
data := dashboardService.LoadCurrentInfo(ioOption, netOption) data := dashboardService.LoadCurrentInfo(ioOption, netOption)
helper.SuccessWithData(c, data) helper.SuccessWithData(c, data)
} }
// @Tags Dashboard
// @Summary System restart
// @Accept json
// @Param operation path string true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /dashboard/system/restart/:operation [post]
func (b *BaseApi) SystemRestart(c *gin.Context) {
operation, ok := c.Params.Get("operation")
if !ok {
helper.BadRequest(c, errors.New("error operation in path"))
return
}
if err := dashboardService.Restart(operation); err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithOutData(c)
}

View file

@ -42,7 +42,6 @@ type IDashboardService interface {
LoadAppLauncher() ([]dto.AppLauncher, error) LoadAppLauncher() ([]dto.AppLauncher, error)
ListLauncherOption(filter string) ([]dto.LauncherOption, error) ListLauncherOption(filter string) ([]dto.LauncherOption, error)
Restart(operation string) error
} }
func NewIDashboardService() IDashboardService { func NewIDashboardService() IDashboardService {
@ -78,23 +77,6 @@ func (u *DashboardService) Sync(req dto.SyncFromMaster) error {
} }
} }
func (u *DashboardService) Restart(operation string) error {
if operation != "1panel" && operation != "system" {
return fmt.Errorf("handle restart operation %s failed, err: nonsupport such operation", operation)
}
itemCmd := fmt.Sprintf("%s systemctl restart 1panel-agent.service", cmd.SudoHandleCmd())
if operation == "system" {
itemCmd = fmt.Sprintf("%s reboot", cmd.SudoHandleCmd())
}
go func() {
stdout, err := cmd.Exec(itemCmd)
if err != nil {
global.LOG.Errorf("handle %s failed, err: %v", itemCmd, stdout)
}
}()
return nil
}
func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) { func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
var baseInfo dto.OsInfo var baseInfo dto.OsInfo
hostInfo, err := host.Info() hostInfo, err := host.Info()

View file

@ -18,6 +18,5 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) {
cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo) cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo)
cmdRouter.GET("/current/node", baseApi.LoadCurrentInfoForNode) cmdRouter.GET("/current/node", baseApi.LoadCurrentInfoForNode)
cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo) cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo)
cmdRouter.POST("/system/restart/:operation", baseApi.SystemRestart)
} }
} }

View file

@ -9,6 +9,7 @@ import (
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper" "github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
"github.com/1Panel-dev/1Panel/core/app/dto" "github.com/1Panel-dev/1Panel/core/app/dto"
"github.com/1Panel-dev/1Panel/core/app/service"
"github.com/1Panel-dev/1Panel/core/global" "github.com/1Panel-dev/1Panel/core/global"
"github.com/1Panel-dev/1Panel/core/utils/copier" "github.com/1Panel-dev/1Panel/core/utils/copier"
"github.com/1Panel-dev/1Panel/core/utils/encrypt" "github.com/1Panel-dev/1Panel/core/utils/encrypt"
@ -159,7 +160,7 @@ func (b *BaseApi) DeleteHost(c *gin.Context) {
// @Summary Update host // @Summary Update host
// @Accept json // @Accept json
// @Param request body dto.HostOperate true "request" // @Param request body dto.HostOperate true "request"
// @Success 200 // @Success 200 {object} dto.HostInfo
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /core/hosts/update [post] // @Router /core/hosts/update [post]
@ -214,11 +215,12 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
upMap["pass_phrase"] = req.PassPhrase upMap["pass_phrase"] = req.PassPhrase
} }
upMap["description"] = req.Description upMap["description"] = req.Description
if err := hostService.Update(req.ID, upMap); err != nil { hostItem, err := hostService.Update(req.ID, upMap)
if err != nil {
helper.InternalServer(c, err) helper.InternalServer(c, err)
return return
} }
helper.SuccessWithOutData(c) helper.SuccessWithData(c, hostItem)
} }
// @Tags Host // @Tags Host
@ -238,13 +240,34 @@ func (b *BaseApi) UpdateHostGroup(c *gin.Context) {
upMap := make(map[string]interface{}) upMap := make(map[string]interface{})
upMap["group_id"] = req.GroupID upMap["group_id"] = req.GroupID
if err := hostService.Update(req.ID, upMap); err != nil { if _, err := hostService.Update(req.ID, upMap); err != nil {
helper.InternalServer(c, err) helper.InternalServer(c, err)
return return
} }
helper.SuccessWithOutData(c) helper.SuccessWithOutData(c)
} }
// @Tags Host
// @Summary Get host info
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200 {object} dto.HostInfo
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/hosts/info [post]
func (b *BaseApi) GetHostByID(c *gin.Context) {
var req dto.OperateByID
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
info, err := hostService.GetHostByID(req.ID)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, info)
}
func (b *BaseApi) WsSsh(c *gin.Context) { func (b *BaseApi) WsSsh(c *gin.Context) {
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil) wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil { if err != nil {
@ -265,7 +288,7 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) { if wshandleError(wsConn, errors.WithMessage(err, "invalid param rows in request")) {
return return
} }
host, err := hostService.GetHostInfo(uint(id)) host, err := service.GetHostInfo(uint(id))
if wshandleError(wsConn, errors.WithMessage(err, "load host info by id failed")) { if wshandleError(wsConn, errors.WithMessage(err, "load host info by id failed")) {
return return
} }

View file

@ -20,11 +20,11 @@ type HostService struct{}
type IHostService interface { type IHostService interface {
TestLocalConn(id uint) bool TestLocalConn(id uint) bool
TestByInfo(req dto.HostConnTest) bool TestByInfo(req dto.HostConnTest) bool
GetHostInfo(id uint) (*model.Host, error) GetHostByID(id uint) (*dto.HostInfo, error)
SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error) SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error)
SearchWithPage(search dto.SearchHostWithPage) (int64, interface{}, error) SearchWithPage(search dto.SearchHostWithPage) (int64, interface{}, error)
Create(hostDto dto.HostOperate) (*dto.HostInfo, error) Create(hostDto dto.HostOperate) (*dto.HostInfo, error)
Update(id uint, upMap map[string]interface{}) error Update(id uint, upMap map[string]interface{}) (*dto.HostInfo, error)
Delete(id []uint) error Delete(id []uint) error
EncryptHost(itemVal string) (string, error) EncryptHost(itemVal string) (string, error)
@ -124,33 +124,6 @@ func (u *HostService) TestLocalConn(id uint) bool {
return true return true
} }
func (u *HostService) GetHostInfo(id uint) (*model.Host, error) {
host, err := hostRepo.Get(repo.WithByID(id))
if err != nil {
return nil, buserr.New("ErrRecordNotFound")
}
if len(host.Password) != 0 {
host.Password, err = encrypt.StringDecrypt(host.Password)
if err != nil {
return nil, err
}
}
if len(host.PrivateKey) != 0 {
host.PrivateKey, err = encrypt.StringDecrypt(host.PrivateKey)
if err != nil {
return nil, err
}
}
if len(host.PassPhrase) != 0 {
host.PassPhrase, err = encrypt.StringDecrypt(host.PassPhrase)
if err != nil {
return nil, err
}
}
return &host, err
}
func (u *HostService) SearchWithPage(req dto.SearchHostWithPage) (int64, interface{}, error) { func (u *HostService) SearchWithPage(req dto.SearchHostWithPage) (int64, interface{}, error) {
var options []global.DBOption var options []global.DBOption
if len(req.Info) != 0 { if len(req.Info) != 0 {
@ -230,6 +203,48 @@ func (u *HostService) SearchForTree(search dto.SearchForTree) ([]dto.HostTree, e
return datas, err return datas, err
} }
func (u *HostService) GetHostByID(id uint) (*dto.HostInfo, error) {
var item dto.HostInfo
var host model.Host
if id == 0 {
host, _ = hostRepo.Get(repo.WithByName("local"))
} else {
host, _ = hostRepo.Get(repo.WithByID(id))
}
if host.ID == 0 {
return nil, buserr.New("ErrRecordNotFound")
}
if err := copier.Copy(&item, &host); err != nil {
return nil, buserr.WithDetail("ErrStructTransform", err.Error(), nil)
}
if !item.RememberPassword {
item.Password = ""
item.PrivateKey = ""
item.PassPhrase = ""
return &item, nil
}
var err error
if len(host.Password) != 0 {
item.Password, err = encrypt.StringDecrypt(host.Password)
if err != nil {
return nil, err
}
}
if len(host.PrivateKey) != 0 {
item.PrivateKey, err = encrypt.StringDecrypt(host.PrivateKey)
if err != nil {
return nil, err
}
}
if len(host.PassPhrase) != 0 {
item.PassPhrase, err = encrypt.StringDecrypt(host.PassPhrase)
if err != nil {
return nil, err
}
}
return &item, err
}
func (u *HostService) Create(req dto.HostOperate) (*dto.HostInfo, error) { func (u *HostService) Create(req dto.HostOperate) (*dto.HostInfo, error) {
if req.Name == "local" { if req.Name == "local" {
return nil, buserr.New("ErrRecordExist") return nil, buserr.New("ErrRecordExist")
@ -297,8 +312,16 @@ func (u *HostService) Delete(ids []uint) error {
return hostRepo.Delete(repo.WithByIDs(ids)) return hostRepo.Delete(repo.WithByIDs(ids))
} }
func (u *HostService) Update(id uint, upMap map[string]interface{}) error { func (u *HostService) Update(id uint, upMap map[string]interface{}) (*dto.HostInfo, error) {
return hostRepo.Update(id, upMap) if err := hostRepo.Update(id, upMap); err != nil {
return nil, err
}
hostItem, _ := hostRepo.Get(repo.WithByID(id))
var hostinfo dto.HostInfo
if err := copier.Copy(&hostinfo, &hostItem); err != nil {
return nil, buserr.WithDetail("ErrStructTransform", err.Error(), nil)
}
return &hostinfo, nil
} }
func (u *HostService) EncryptHost(itemVal string) (string, error) { func (u *HostService) EncryptHost(itemVal string) (string, error) {
@ -309,3 +332,30 @@ func (u *HostService) EncryptHost(itemVal string) (string, error) {
keyItem, err := encrypt.StringEncrypt(string(privateKey)) keyItem, err := encrypt.StringEncrypt(string(privateKey))
return keyItem, err return keyItem, err
} }
func GetHostInfo(id uint) (*model.Host, error) {
host, err := hostRepo.Get(repo.WithByID(id))
if err != nil {
return nil, buserr.New("ErrRecordNotFound")
}
if len(host.Password) != 0 {
host.Password, err = encrypt.StringDecrypt(host.Password)
if err != nil {
return nil, err
}
}
if len(host.PrivateKey) != 0 {
host.PrivateKey, err = encrypt.StringDecrypt(host.PrivateKey)
if err != nil {
return nil, err
}
}
if len(host.PassPhrase) != 0 {
host.PassPhrase, err = encrypt.StringDecrypt(host.PassPhrase)
if err != nil {
return nil, err
}
}
return &host, err
}

View file

@ -53,7 +53,6 @@ var WebUrlMap = map[string]struct{}{
"/containers": {}, "/containers": {},
"/containers/container": {}, "/containers/container": {},
"containers/container/operate": {},
"/containers/image": {}, "/containers/image": {},
"/containers/network": {}, "/containers/network": {},
"/containers/volume": {}, "/containers/volume": {},
@ -147,6 +146,7 @@ var WebUrlMap = map[string]struct{}{
} }
var DynamicRoutes = []string{ var DynamicRoutes = []string{
`^/containers/container/operate/[^/]+$`,
`^/containers/composeDetail/[^/]+$`, `^/containers/composeDetail/[^/]+$`,
`^/databases/mysql/setting/[^/]+/[^/]+$`, `^/databases/mysql/setting/[^/]+/[^/]+$`,
`^/databases/postgresql/setting/[^/]+/[^/]+$`, `^/databases/postgresql/setting/[^/]+/[^/]+$`,

View file

@ -16,6 +16,7 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) {
baseApi := v2.ApiGroupApp.BaseApi baseApi := v2.ApiGroupApp.BaseApi
{ {
hostRouter.POST("", baseApi.CreateHost) hostRouter.POST("", baseApi.CreateHost)
hostRouter.POST("/info", baseApi.GetHostByID)
hostRouter.POST("/del", baseApi.DeleteHost) hostRouter.POST("/del", baseApi.DeleteHost)
hostRouter.POST("/update", baseApi.UpdateHost) hostRouter.POST("/update", baseApi.UpdateHost)
hostRouter.POST("/update/group", baseApi.UpdateHostGroup) hostRouter.POST("/update/group", baseApi.UpdateHostGroup)

View file

@ -71,6 +71,13 @@ func (c *SSHClient) Run(shell string) (string, error) {
return string(buf), err return string(buf), err
} }
func (c *SSHClient) SudoHandleCmd() string {
if _, err := c.Run("sudo -n ls"); err == nil {
return "sudo "
}
return ""
}
func (c *SSHClient) Runf(shell string, args ...interface{}) (string, error) { func (c *SSHClient) Runf(shell string, args ...interface{}) (string, error) {
session, err := c.Client.NewSession() session, err := c.Client.NewSession()
if err != nil { if err != nil {

View file

@ -7,6 +7,9 @@ import { deepCopy } from '@/utils/util';
export const searchHosts = (params: Host.SearchWithPage) => { export const searchHosts = (params: Host.SearchWithPage) => {
return http.post<ResPage<Host.Host>>(`/core/hosts/search`, params); return http.post<ResPage<Host.Host>>(`/core/hosts/search`, params);
}; };
export const getHostByID = (id: number) => {
return http.post<Host.Host>(`/core/hosts/info`, { id: id });
};
export const getHostTree = (params: Host.ReqSearch) => { export const getHostTree = (params: Host.ReqSearch) => {
return http.post<Array<Host.HostTree>>(`/core/hosts/tree`, params); return http.post<Array<Host.HostTree>>(`/core/hosts/tree`, params);
}; };

View file

@ -52,11 +52,11 @@ const seriesStyle = [
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ {
offset: 0, offset: 0,
color: 'rgba(0, 94, 235, .5)', color: 'rgba(0, 94, 235, .3)',
}, },
{ {
offset: 1, offset: 1,
color: 'rgba(0, 94, 235, 0)', color: 'rgba(0, 94, 235, .4)',
}, },
]), ]),
}, },
@ -64,11 +64,11 @@ const seriesStyle = [
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ {
offset: 0, offset: 0,
color: 'rgba(27, 143, 60, .5)', color: 'rgba(27, 143, 60, .3)',
}, },
{ {
offset: 1, offset: 1,
color: 'rgba(27, 143, 60, 0)', color: 'rgba(27, 143, 60, .4)',
}, },
]), ]),
}, },
@ -76,11 +76,11 @@ const seriesStyle = [
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ {
offset: 0, offset: 0,
color: 'rgba(249, 199, 79, .5)', color: 'rgba(249, 199, 79, .3)',
}, },
{ {
offset: 1, offset: 1,
color: 'rgba(249, 199, 79, 0)', color: 'rgba(249, 199, 79, .4)',
}, },
]), ]),
}, },
@ -88,11 +88,11 @@ const seriesStyle = [
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ {
offset: 0, offset: 0,
color: 'rgba(255, 173, 177, 0.5)', color: 'rgba(255, 173, 177, 0.3)',
}, },
{ {
offset: 1, offset: 1,
color: 'rgba(255, 173, 177, 0)', color: 'rgba(255, 173, 177, .4)',
}, },
]), ]),
}, },

View file

@ -8,11 +8,11 @@
</div> </div>
<div v-if="createdBy === '1Panel'" style="margin-left: 50px"> <div v-if="createdBy === '1Panel'" style="margin-left: 50px">
<el-button link type="primary" @click="onComposeOperate('up')"> <el-button link type="primary" @click="onComposeOperate('up')">
{{ $t('app.start') }} {{ $t('commons.operate.start') }}
</el-button> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button link type="primary" @click="onComposeOperate('stop')"> <el-button link type="primary" @click="onComposeOperate('stop')">
{{ $t('app.stop') }} {{ $t('commons.operate.stop') }}
</el-button> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button link type="primary" @click="onComposeOperate('down')"> <el-button link type="primary" @click="onComposeOperate('down')">
@ -40,10 +40,10 @@
<template #main> <template #main>
<el-button-group> <el-button-group>
<el-button :disabled="checkStatus('start')" @click="onOperate('start')"> <el-button :disabled="checkStatus('start')" @click="onOperate('start')">
{{ $t('app.start') }} {{ $t('commons.operate.start') }}
</el-button> </el-button>
<el-button :disabled="checkStatus('stop')" @click="onOperate('stop')"> <el-button :disabled="checkStatus('stop')" @click="onOperate('stop')">
{{ $t('app.stop') }} {{ $t('commons.operate.stop') }}
</el-button> </el-button>
<el-button :disabled="checkStatus('restart')" @click="onOperate('restart')"> <el-button :disabled="checkStatus('restart')" @click="onOperate('restart')">
{{ $t('commons.button.restart') }} {{ $t('commons.button.restart') }}

View file

@ -76,7 +76,7 @@
import { ElForm } from 'element-plus'; import { ElForm } from 'element-plus';
import { Host } from '@/api/interface/host'; import { Host } from '@/api/interface/host';
import { Rules } from '@/global/form-rules'; import { Rules } from '@/global/form-rules';
import { addHost, testByInfo } from '@/api/modules/terminal'; import { addHost, editHost, getHostByID, testByInfo } from '@/api/modules/terminal';
import i18n from '@/lang'; import i18n from '@/lang';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { MsgError, MsgSuccess } from '@/utils/message'; import { MsgError, MsgSuccess } from '@/utils/message';
@ -88,6 +88,7 @@ type FormInstance = InstanceType<typeof ElForm>;
const hostRef = ref<FormInstance>(); const hostRef = ref<FormInstance>();
const groupList = ref(); const groupList = ref();
const defaultGroup = ref();
let hostInfo = reactive<Host.HostOperate>({ let hostInfo = reactive<Host.HostOperate>({
id: 0, id: 0,
@ -118,21 +119,7 @@ interface DialogProps {
isLocal: boolean; isLocal: boolean;
} }
const acceptParams = (props: DialogProps) => { const acceptParams = (props: DialogProps) => {
hostInfo.addr = '';
hostInfo.name = 'local';
hostInfo.groupID = 0;
hostInfo.addr = '';
hostInfo.port = 22;
hostInfo.user = '';
hostInfo.authMode = 'password';
hostInfo.password = '';
hostInfo.privateKey = '';
hostInfo.description = '';
isLocal.value = props.isLocal; isLocal.value = props.isLocal;
if (props.isLocal) {
hostInfo.addr = '127.0.0.1';
hostInfo.user = 'root';
}
loadGroups(); loadGroups();
dialogVisible.value = true; dialogVisible.value = true;
}; };
@ -143,11 +130,57 @@ const handleClose = () => {
const emit = defineEmits(['on-conn-terminal', 'load-host-tree']); const emit = defineEmits(['on-conn-terminal', 'load-host-tree']);
const loadGroups = async () => {
const res = await getGroupList('host');
groupList.value = res.data;
for (const item of groupList.value) {
if (item.isDefault) {
defaultGroup.value = item.id;
break;
}
}
if (isLocal.value) {
loadLocal();
} else {
setDefault();
}
};
const loadLocal = async () => {
await getHostByID(0)
.then((res) => {
hostInfo.id = res.data.id || 0;
hostInfo.addr = res.data.addr || '';
hostInfo.name = 'local';
hostInfo.groupID = res.data.groupID || defaultGroup.value;
hostInfo.port = res.data.port || 22;
hostInfo.user = res.data.user || 'root';
hostInfo.authMode = res.data.authMode || 'password';
hostInfo.password = res.data.password || '';
hostInfo.privateKey = res.data.privateKey || '';
hostInfo.description = res.data.description || '';
})
.catch(() => {
setDefault();
});
};
const setDefault = () => {
console.log('123');
hostInfo.addr = '';
hostInfo.name = 'local';
hostInfo.groupID = defaultGroup.value;
hostInfo.port = 22;
hostInfo.user = '';
hostInfo.authMode = 'password';
hostInfo.password = '';
hostInfo.privateKey = '';
hostInfo.description = '';
};
const submitAddHost = (formEl: FormInstance | undefined, ops: string) => { const submitAddHost = (formEl: FormInstance | undefined, ops: string) => {
if (!formEl) return; if (!formEl) return;
formEl.validate(async (valid) => { formEl.validate(async (valid) => {
if (!valid) return; if (!valid) return;
hostInfo.groupID = 0;
switch (ops) { switch (ops) {
case 'testConn': case 'testConn':
await testByInfo(hostInfo).then((res) => { await testByInfo(hostInfo).then((res) => {
@ -161,7 +194,12 @@ const submitAddHost = (formEl: FormInstance | undefined, ops: string) => {
}); });
break; break;
case 'saveAndConn': case 'saveAndConn':
const res = await addHost(hostInfo); let res;
if (hostInfo.id == 0) {
res = await addHost(hostInfo);
} else {
res = await editHost(hostInfo);
}
dialogVisible.value = false; dialogVisible.value = false;
let title = res.data.user + '@' + res.data.addr + ':' + res.data.port; let title = res.data.user + '@' + res.data.addr + ':' + res.data.port;
if (res.data.name.length !== 0) { if (res.data.name.length !== 0) {
@ -175,17 +213,6 @@ const submitAddHost = (formEl: FormInstance | undefined, ops: string) => {
}); });
}; };
const loadGroups = async () => {
const res = await getGroupList('host');
groupList.value = res.data;
for (const item of groupList.value) {
if (item.isDefault) {
hostInfo.groupID = item.id;
break;
}
}
};
defineExpose({ defineExpose({
acceptParams, acceptParams,
}); });

View file

@ -364,7 +364,7 @@ const onConnTerminal = async (title: string, wsID: number, isLocal?: boolean) =>
const res = await testByID(wsID); const res = await testByID(wsID);
if (isLocal) { if (isLocal) {
for (const tab of terminalTabs.value) { for (const tab of terminalTabs.value) {
if (tab.title.indexOf('@127.0.0.1:') !== -1 || tab.title === i18n.global.t('terminal.localhost')) { if (tab.title === i18n.global.t('terminal.localhost')) {
onReconnect(tab); onReconnect(tab);
} }
} }

View file

@ -10,10 +10,10 @@
</div> </div>
<div class="mt-0.5"> <div class="mt-0.5">
<el-button type="primary" v-if="!data.isActive" link @click="onOperate('ClamAV', 'start')"> <el-button type="primary" v-if="!data.isActive" link @click="onOperate('ClamAV', 'start')">
{{ $t('app.start') }} {{ $t('commons.operate.start') }}
</el-button> </el-button>
<el-button type="primary" v-if="data.isActive" link @click="onOperate('ClamAV', 'stop')"> <el-button type="primary" v-if="data.isActive" link @click="onOperate('ClamAV', 'stop')">
{{ $t('app.stop') }} {{ $t('commons.operate.stop') }}
</el-button> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button type="primary" link @click="onOperate('ClamAV', 'restart')"> <el-button type="primary" link @click="onOperate('ClamAV', 'restart')">
@ -45,7 +45,7 @@
link link
@click="onOperate('FreshClam', 'start')" @click="onOperate('FreshClam', 'start')"
> >
{{ $t('app.start') }} {{ $t('commons.operate.start') }}
</el-button> </el-button>
<el-button <el-button
type="primary" type="primary"
@ -53,7 +53,7 @@
link link
@click="onOperate('FreshClam', 'stop')" @click="onOperate('FreshClam', 'stop')"
> >
{{ $t('app.stop') }} {{ $t('commons.operate.stop') }}
</el-button> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button type="primary" link @click="onOperate('FreshClam', 'restart')"> <el-button type="primary" link @click="onOperate('FreshClam', 'restart')">

View file

@ -10,10 +10,10 @@
</div> </div>
<div class="mt-0.5" v-if="!data.init"> <div class="mt-0.5" v-if="!data.init">
<el-button type="primary" v-if="data.status != 'running'" link @click="onOperate('start')"> <el-button type="primary" v-if="data.status != 'running'" link @click="onOperate('start')">
{{ $t('app.start') }} {{ $t('commons.operate.start') }}
</el-button> </el-button>
<el-button type="primary" v-if="data.status == 'running'" link @click="onOperate('stop')"> <el-button type="primary" v-if="data.status == 'running'" link @click="onOperate('stop')">
{{ $t('app.stop') }} {{ $t('commons.operate.stop') }}
</el-button> </el-button>
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-button type="primary" link @click="onOperate('restart')"> <el-button type="primary" link @click="onOperate('restart')">