feat: 完成面板设置前端界面效果

This commit is contained in:
ssongliu 2022-09-09 17:17:02 +08:00 committed by ssongliu
parent 6ceb040061
commit 2a1403904f
21 changed files with 654 additions and 121 deletions

View File

@ -17,7 +17,7 @@ func (b *BaseApi) GetSettingInfo(c *gin.Context) {
helper.SuccessWithData(c, setting)
}
func (b *BaseApi) UpdateInfo(c *gin.Context) {
func (b *BaseApi) UpdateSetting(c *gin.Context) {
var req dto.SettingUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)

View File

@ -2,10 +2,10 @@ package dto
type SettingInfo struct {
UserName string `json:"userName"`
Password string `json:"password"`
Email string `json:"email"`
SessionTimeout string `json:"sessionTimeout"`
LocalTime string `json:"localTime"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
@ -13,6 +13,7 @@ type SettingInfo struct {
ServerPort string `json:"serverPort"`
SecurityEntrance string `json:"securityEntrance"`
PasswordTimeOut string `json:"passwordTimeOut"`
ComplexityVerification string `json:"complexityVerification"`
MFAStatus string `json:"mfaStatus"`

View File

@ -2,6 +2,7 @@ package service
import (
"encoding/json"
"time"
"github.com/1Panel-dev/1Panel/app/dto"
"github.com/1Panel-dev/1Panel/constant"
@ -35,6 +36,7 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
if err := json.Unmarshal(arr, &info); err != nil {
return nil, err
}
info.LocalTime = time.Now().Format("2006.01.02 15:04:05")
return &info, err
}

View File

@ -1,6 +1,8 @@
package migrations
import (
"time"
"github.com/1Panel-dev/1Panel/app/model"
"github.com/go-gormigrate/gormigrate/v2"
@ -90,6 +92,9 @@ var AddTableSetting = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "SessionTimeout", Value: "86400"}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "LocalTime", Value: ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "ServerPort", Value: "4004"}).Error; err != nil {
return err
@ -97,6 +102,9 @@ var AddTableSetting = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "SecurityEntrance", Value: "/89dc6ae8"}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "PasswordTimeOut", Value: time.Now().AddDate(0, 0, 10).Format("2016.01.02 15:04:05")}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "ComplexityVerification", Value: "enable"}).Error; err != nil {
return err
}

View File

@ -9,9 +9,10 @@ import (
type SettingRouter struct{}
func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
monitorRouter := Router.Group("settings").Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
settingRouter := Router.Group("settings").Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
baseApi := v1.ApiGroupApp.BaseApi
{
monitorRouter.POST("/search", baseApi.GetSettingInfo)
settingRouter.POST("/search", baseApi.GetSettingInfo)
settingRouter.PUT("", baseApi.UpdateSetting)
}
}

View File

@ -5,6 +5,7 @@ export namespace Setting {
email: string;
sessionTimeout: string;
localTime: string;
panelName: string;
theme: string;
@ -12,6 +13,7 @@ export namespace Setting {
serverPort: string;
securityEntrance: string;
passwordTimeOut: string;
complexityVerification: string;
mfaStatus: string;
@ -23,4 +25,13 @@ export namespace Setting {
weChatVars: string;
dingVars: string;
}
export interface SettingUpdate {
key: string;
value: string;
}
export interface PasswordUpdate {
oldPassword: string;
newPassword: string;
retryPassword: string;
}
}

View File

@ -4,3 +4,7 @@ import { Setting } from '../interface/setting';
export const getSettingInfo = () => {
return http.post<Setting.SettingInfo>(`/settings/search`);
};
export const updateSetting = (param: Setting.SettingUpdate) => {
return http.put(`/settings`, param);
};

View File

@ -18,6 +18,16 @@ export default {
dateStart: '开始日期',
dateEnd: '结束日期',
},
personal: {
about: '关于',
project_url: '项目地址',
issue: '问题反馈',
talk: '参与讨论',
star: '点亮 Star',
version: '版本',
ko_introduction:
'是一个开源的轻量级 Kubernetes 发行版专注于帮助企业规划部署和运营生产级别的 Kubernetes 集群',
},
table: {
name: '名称',
group: '组',
@ -47,6 +57,7 @@ export default {
rule: {
username: '请输入用户名',
password: '请输入密码',
rePassword: '密码不一致请检查后重新输入',
requiredInput: '请填写必填项',
requiredSelect: '请选择必选项',
commonName: '支持英文中文数字.-_,长度1-30',
@ -84,7 +95,10 @@ export default {
menu: {
home: '概览',
demo: '样例',
monitor: '监控',
terminal: '终端',
operations: '操作日志',
files: '文件管理',
apps: '应用商店',
website: '网站',
project: '项目',
@ -95,12 +109,8 @@ export default {
plan: '计划任务',
host: '主机',
security: '安全',
systemConfig: '面板设置',
settings: '面板设置',
toolbox: '工具箱',
monitor: '监控',
operations: '操作记录',
files: '文件管理',
settings: '系统设置',
},
home: {
welcome: '欢迎使用',

View File

@ -1,22 +0,0 @@
import { Layout } from '@/routers/constant';
const systemConfigRouter = {
sort: 8,
path: '/configs',
component: Layout,
redirect: '/configs',
meta: {
icon: 'p-config',
title: 'menu.systemConfig',
},
children: [
{
path: '/configs',
name: 'SystemConfig',
component: () => import('@/views/system-config/index.vue'),
meta: {},
},
],
};
export default systemConfigRouter;

View File

@ -1,13 +1,13 @@
import { Layout } from '@/routers/constant';
const settingRouter = {
sort: 3,
sort: 7,
path: '/settings',
component: Layout,
redirect: '/setting',
meta: {
title: 'menu.settings',
icon: 'Setting',
icon: 'p-config',
},
children: [
{

View File

@ -114,3 +114,13 @@
.form-button {
float: right;
}
.input-help {
font-size: 12px;
word-break: break-all;
color: #4A4B4D;
transform: scale(0.9);
transform-origin: left;
width: 110%;
display: inline-block;
}

View File

@ -34,7 +34,7 @@
</span>
</template>
<Terminal
style="height: calc(100vh - 210px); background-color: #000"
style="height: calc(100vh - 150px); background-color: #000"
:ref="'Ref' + item.key"
:wsID="item.wsID"
:terminalID="item.key"
@ -106,7 +106,7 @@
</el-tab-pane>
<div v-if="terminalTabs.length === 0">
<el-empty
style="background-color: #000; height: calc(100vh - 210px)"
style="background-color: #000; height: calc(100vh - 150px)"
:description="$t('terminal.emptyTerminal')"
></el-empty>
</div>
@ -182,9 +182,9 @@ import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { Host } from '@/api/interface/host';
import { ElMessage } from 'element-plus';
import Terminal from '@/views/terminal/terminal/index.vue';
import HostTab from '@/views/terminal/host/index.vue';
import CommandTab from '@/views/terminal/command/index.vue';
import Terminal from '@/views/host/terminal/terminal/index.vue';
import HostTab from '@/views/host/terminal/host/index.vue';
import CommandTab from '@/views/host/terminal/command/index.vue';
import type Node from 'element-plus/es/components/tree/src/model/node';
import { ElTree } from 'element-plus';
import screenfull from 'screenfull';

View File

@ -3,100 +3,45 @@
<el-card class="topCard">
<el-radio-group v-model="activeNames">
<el-radio-button class="topButton" size="large" label="all">全部</el-radio-button>
<el-radio-button class="topButton" size="large" label="user">用户设置</el-radio-button>
<el-radio-button class="topButton" size="large" label="panel">面板设置</el-radio-button>
<el-radio-button class="topButton" size="large" label="safe">安全设置</el-radio-button>
<el-radio-button class="topButton" size="large" label="backup">备份设置</el-radio-button>
<el-radio-button class="topButton" size="large" label="monitor">监控设置</el-radio-button>
<el-radio-button class="topButton" size="large" label="message">通知设置</el-radio-button>
<el-radio-button class="topButton" size="large" label="panel">面板</el-radio-button>
<el-radio-button class="topButton" size="large" label="safe">安全</el-radio-button>
<el-radio-button class="topButton" size="large" label="backup">备份</el-radio-button>
<el-radio-button class="topButton" size="large" label="monitor">监控</el-radio-button>
<el-radio-button class="topButton" size="large" label="message">通知</el-radio-button>
<el-radio-button class="topButton" size="large" label="about">关于</el-radio-button>
</el-radio-group>
</el-card>
<el-form :model="form" label-position="left" label-width="120px">
<el-card v-if="activeNames === 'all' || activeNames === 'user'" style="margin-top: 20px">
<template #header>
<div class="card-header">
<span>用户设置</span>
</div>
</template>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="8">
<el-form-item label="用户名">
<el-input size="small" clearable v-model="form.userName" />
</el-form-item>
<el-form-item label="密码">
<el-input type="password" clearable show-password size="small" v-model="form.password" />
</el-form-item>
<el-form-item label="主题色">
<el-radio-group size="small" v-model="form.theme">
<el-radio-button label="black">
<el-icon><Moon /></el-icon>
</el-radio-button>
<el-tooltip
effect="dark"
placement="top"
content="选择自动设置,将会在晚 6 点到次日早 6 点间自动切换到黑金主题。"
>
<el-radio-button label="auto" icon="Sunny">
<el-icon><MagicStick /></el-icon>
</el-radio-button>
</el-tooltip>
<el-radio-button label="write">
<el-icon><Sunny /></el-icon>
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="系统语言">
<el-radio-group size="small" v-model="form.language">
<el-radio-button label="ch">中文 </el-radio-button>
<el-radio-button label="en">English </el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button size="small" icon="Pointer">更新用户设置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-card>
<el-card v-if="activeNames === 'all' || activeNames === 'panel'" style="margin-top: 10px">
<template #header>
<div class="card-header">
<span>面板设置</span>
</div>
</template>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="8">
<el-form-item label="超时时间">
<el-input size="small" v-model="form.sessionTimeout" />
</el-form-item>
<el-form-item label="同步时间">
<el-input size="small" v-model="form.password" />
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<Panel v-if="activeNames === 'all' || activeNames === 'panel'" :settingInfo="form" />
<Safe v-if="activeNames === 'all' || activeNames === 'safe'" :settingInfo="form" />
<Backup v-if="activeNames === 'all' || activeNames === 'backup'" :settingInfo="form" />
<Monitor v-if="activeNames === 'all' || activeNames === 'monitor'" :settingInfo="form" />
<Message v-if="activeNames === 'all' || activeNames === 'message'" :settingInfo="form" />
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive } from 'vue';
import { ref, onMounted } from 'vue';
import { getSettingInfo } from '@/api/modules/setting';
import { Setting } from '@/api/interface/setting';
import Panel from '@/views/setting/tabs/panel.vue';
import Safe from '@/views/setting/tabs/safe.vue';
import Backup from '@/views/setting/tabs/backup.vue';
import Monitor from '@/views/setting/tabs/monitor.vue';
import Message from '@/views/setting/tabs/message.vue';
const activeNames = ref('all');
let form = reactive<Setting.SettingInfo>({
let form = ref<Setting.SettingInfo>({
userName: '',
password: '',
email: '',
sessionTimeout: '',
localTime: '',
panelName: '',
theme: '',
language: '',
serverPort: '',
securityEntrance: '',
passwordTimeOut: '',
complexityVerification: '',
mfaStatus: '',
monitorStatus: '',
@ -109,9 +54,10 @@ let form = reactive<Setting.SettingInfo>({
const search = async () => {
const res = await getSettingInfo();
console.log(res);
form = res.data;
form.value = res.data;
form.value.password = '******';
};
onMounted(() => {
search();
});

View File

@ -0,0 +1,17 @@
<template>
<el-card style="margin-top: 10px">
<template #header>
<div class="card-header">
<span>备份</span>
</div>
</template>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="8"> </el-col>
</el-row>
</el-card>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue';
onMounted(() => {});
</script>

View File

@ -0,0 +1,152 @@
<template>
<el-form size="small" :model="form" label-position="left" label-width="120px">
<el-card style="margin-top: 10px">
<template #header>
<div class="card-header">
<span>通知</span>
</div>
</template>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="8">
<el-form-item label="通知方式">
<el-radio-group v-model="form.settingInfo.messageType">
<el-radio-button label="none">关闭</el-radio-button>
<el-radio-button label="email">email</el-radio-button>
<el-radio-button label="wechat">企业微信</el-radio-button>
<el-radio-button label="dingding">钉钉</el-radio-button>
</el-radio-group>
</el-form-item>
<div v-if="form.settingInfo.messageType === 'none'">
<el-form-item>
<el-button @click="SaveSetting()">关闭消息通知</el-button>
</el-form-item>
</div>
<div v-if="form.settingInfo.messageType === 'email'">
<el-form-item label="邮箱服务名称">
<el-input clearable v-model="emailVars.serverName" />
</el-form-item>
<el-form-item label="邮箱地址">
<el-input clearable v-model="emailVars.serverAddr" />
</el-form-item>
<el-form-item label="邮箱SMTP授权码">
<el-input clearable v-model="emailVars.serverSMTP" />
</el-form-item>
<el-form-item>
<el-button @click="SaveSetting()">保存并启用</el-button>
</el-form-item>
</div>
<div v-if="form.settingInfo.messageType === 'wechat'">
<el-form-item label="orpid">
<el-input clearable v-model="weChatVars.orpid" />
</el-form-item>
<el-form-item label="corpsecret">
<el-input clearable v-model="weChatVars.corpsecret" />
</el-form-item>
<el-form-item label="touser">
<el-input clearable v-model="weChatVars.touser" />
</el-form-item>
<el-form-item label="agentid">
<el-input clearable v-model="weChatVars.agentid" />
</el-form-item>
<el-form-item>
<el-button @click="SaveSetting()">保存并启用</el-button>
</el-form-item>
</div>
<div v-if="form.settingInfo.messageType === 'dingding'">
<el-form-item label="webhook token">
<el-input clearable v-model="dingVars.webhookToken" />
</el-form-item>
<el-form-item label="密钥">
<el-input clearable v-model="dingVars.secret" />
</el-form-item>
<el-form-item label="邮箱 SMTP 授权码">
<el-input clearable v-model="emailVars.serverSMTP" />
</el-form-item>
<el-form-item>
<el-button @click="SaveSetting()">保存并启用</el-button>
</el-form-item>
</div>
</el-col>
</el-row>
</el-card>
</el-form>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { updateSetting } from '@/api/modules/setting';
import i18n from '@/lang';
interface Props {
settingInfo: any;
}
const form = withDefaults(defineProps<Props>(), {
settingInfo: {
messageType: '',
emailVars: '',
weChatVars: '',
dingVars: '',
},
});
const emailVars = ref({
serverName: '',
serverAddr: '',
serverSMTP: '',
});
const weChatVars = ref({
orpid: '',
corpsecret: '',
touser: '',
agentid: '',
});
const dingVars = ref({
webhookToken: '',
secret: '',
});
const SaveSetting = async () => {
let settingKey = '';
let settingVal = '';
switch (form.settingInfo.messageType) {
case 'none':
settingVal = '';
break;
case 'email':
settingVal = JSON.stringify(emailVars.value);
settingKey = 'EmailVars';
break;
case 'wechat':
settingVal = JSON.stringify(emailVars.value);
settingKey = 'WeChatVars';
break;
case 'dingding':
settingVal = JSON.stringify(emailVars.value);
settingKey = 'DingVars';
break;
}
let param = {
key: settingKey,
value: settingVal,
};
await updateSetting({ key: 'MessageType', value: form.settingInfo.messageType });
await updateSetting(param);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
};
onMounted(() => {
switch (form.settingInfo.messageType) {
case 'email':
emailVars.value = JSON.parse(form.settingInfo.emailVars);
console.log(emailVars.value);
break;
case 'wechat':
weChatVars.value = JSON.parse(form.settingInfo.weChatVars);
break;
case 'dingding':
dingVars.value = JSON.parse(form.settingInfo.dingVars);
break;
}
});
</script>

View File

@ -0,0 +1,64 @@
<template>
<el-form size="small" :model="form" label-position="left" label-width="120px">
<el-card style="margin-top: 10px">
<template #header>
<div class="card-header">
<span>监控</span>
</div>
</template>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="8">
<el-form-item label="开启监控">
<el-switch
v-model="form.settingInfo.monitorStatus"
active-value="enable"
inactive-value="disable"
@change="SaveSetting('MonitorStatus', form.settingInfo.monitorStatus)"
/>
</el-form-item>
<el-form-item label="过期时间">
<el-input clearable v-model="form.settingInfo.monitorStoreDays">
<template #append>
<el-button
@click="SaveSetting('MonitorStoreDays', form.settingInfo.monitorStoreDays)"
icon="Collection"
>
保存
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button icon="Delete"> 清空监控记录 </el-button>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
</template>
<script lang="ts" setup>
import { ElMessage } from 'element-plus';
import { updateSetting } from '@/api/modules/setting';
import i18n from '@/lang';
interface Props {
settingInfo: any;
}
const form = withDefaults(defineProps<Props>(), {
settingInfo: {
monitorStatus: '',
monitorStoreDays: '',
},
});
const SaveSetting = async (key: string, val: string) => {
let param = {
key: key,
value: val,
};
await updateSetting(param);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
};
</script>

View File

@ -0,0 +1,214 @@
<template>
<el-form size="small" :model="form" label-position="left" label-width="120px">
<el-card style="margin-top: 20px">
<template #header>
<div class="card-header">
<span>面板</span>
</div>
</template>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="8">
<el-form-item label="用户名">
<el-input clearable v-model="form.settingInfo.userName">
<template #append>
<el-button
@click="SaveSetting('UserName', form.settingInfo.userName)"
icon="Collection"
>
保存
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="密码">
<el-input type="password" clearable disabled v-model="form.settingInfo.password">
<template #append>
<el-button icon="Setting" @click="passwordVisiable = true">设置</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input clearable v-model="form.settingInfo.email">
<template #append>
<el-button @click="SaveSetting('Email', form.settingInfo.email)" icon="Collection">
保存
</el-button>
</template>
</el-input>
<div><span class="input-help">用于密码找回</span></div>
</el-form-item>
<el-form-item label="面板别名">
<el-input clearable v-model="form.settingInfo.panelName">
<template #append>
<el-button
@click="SaveSetting('PanelName', form.settingInfo.panelName)"
icon="Collection"
>
保存
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="主题色">
<el-radio-group
@change="SaveSetting('Theme', form.settingInfo.theme)"
v-model="form.settingInfo.theme"
>
<el-radio-button label="black">
<el-icon><Moon /></el-icon>
</el-radio-button>
<el-radio-button label="auto" icon="Sunny">
<el-icon><MagicStick /></el-icon>
</el-radio-button>
<el-radio-button label="write">
<el-icon><Sunny /></el-icon>
</el-radio-button>
</el-radio-group>
<div>
<span class="input-help">
选择自动设置将会在晚 6 点到次日早 6 点间自动切换到黑金主题
</span>
</div>
</el-form-item>
<el-form-item label="系统语言">
<el-radio-group
@change="SaveSetting('Language', form.settingInfo.language)"
v-model="form.settingInfo.language"
>
<el-radio-button label="ch">中文 </el-radio-button>
<el-radio-button label="en">English </el-radio-button>
</el-radio-group>
<div>
<span class="input-help">
默认跟随浏览器语言设置后只对当前浏览器生效更换浏览器后需要重新设置
</span>
</div>
</el-form-item>
<el-form-item label="超时时间">
<el-input v-model="form.settingInfo.sessionTimeout">
<template #append>
<el-button
@click="SaveSetting('SessionTimeout', form.settingInfo.sessionTimeout)"
icon="Collection"
>
保存
</el-button>
</template>
</el-input>
<div>
<span class="input-help">如果用户超过 86400秒未操作面板面板将自动退出登录 </span>
</div>
</el-form-item>
<el-form-item label="同步时间">
<el-input v-model="form.settingInfo.localTime">
<template #append>
<el-button icon="Refresh">同步</el-button>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
<el-dialog v-model="passwordVisiable" title="密码修改" width="30%">
<el-form
size="small"
ref="passFormRef"
label-width="80px"
label-position="left"
:model="passForm"
:rules="passRules"
>
<el-form-item label="原密码" prop="oldPassword">
<el-input type="password" show-password clearable v-model="passForm.oldPassword" />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input type="password" show-password clearable v-model="passForm.newPassword" />
</el-form-item>
<el-form-item label="确认密码" prop="retryPassword">
<el-input type="password" show-password clearable v-model="passForm.retryPassword" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="passwordVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button @click="submitChangePassword()">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue';
import { ElMessage, ElForm } from 'element-plus';
import { updateSetting } from '@/api/modules/setting';
import { Setting } from '@/api/interface/setting';
import { useI18n } from 'vue-i18n';
import { GlobalStore } from '@/store';
import { useTheme } from '@/hooks/use-theme';
import { Rules } from '@/global/form-rues';
const i18n = useI18n();
const globalStore = GlobalStore();
type FormInstance = InstanceType<typeof ElForm>;
const passFormRef = ref<FormInstance>();
const passRules = reactive({
oldPassword: [Rules.requiredInput],
newPassword: [Rules.requiredInput],
retryPassword: [Rules.requiredInput, { validator: checkPassword, trigger: 'blur' }],
});
const passwordVisiable = ref<boolean>(false);
const passForm = reactive<Setting.PasswordUpdate>({
oldPassword: '',
newPassword: '',
retryPassword: '',
});
interface Props {
settingInfo: any;
}
const form = withDefaults(defineProps<Props>(), {
settingInfo: {
userName: '',
password: '',
email: '',
sessionTimeout: '',
localTime: '',
panelName: '',
theme: '',
language: '',
},
});
const { switchDark } = useTheme();
const SaveSetting = async (key: string, val: string) => {
switch (key) {
case 'Language':
i18n.locale.value = val;
globalStore.updateLanguage(val);
break;
case 'theme':
switchDark();
break;
}
let param = {
key: key,
value: val,
};
await updateSetting(param);
ElMessage.success(i18n.t('commons.msg.operationSuccess'));
};
function checkPassword(rule: any, value: any, callback: any) {
if (passForm.newPassword !== passForm.retryPassword) {
return callback(new Error(i18n.t('commons.rule.rePassword')));
}
callback();
}
function submitChangePassword() {}
</script>

View File

@ -0,0 +1,122 @@
<template>
<el-form size="small" :model="form" label-position="left" label-width="120px">
<el-card style="margin-top: 10px">
<template #header>
<div class="card-header">
<span>安全</span>
</div>
</template>
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="8">
<el-form-item label="面板端口">
<el-input clearable v-model="form.settingInfo.serverPort">
<template #append>
<el-button
@click="SaveSetting('ServerPort', form.settingInfo.serverPort)"
icon="Collection"
>
保存
</el-button>
</template>
<el-tooltip
class="box-item"
effect="dark"
content="Top Left prompts info"
placement="top-start"
>
<el-icon style="font-size: 14px; margin-top: 8px"><WarningFilled /></el-icon>
</el-tooltip>
</el-input>
<div>
<span class="input-help">
建议端口范围8888 - 65535注意有安全组的服务器请提前在安全组放行新端口
</span>
</div>
</el-form-item>
<el-form-item label="安全入口">
<el-input clearable v-model="form.settingInfo.securityEntrance">
<template #append>
<el-button
@click="SaveSetting('SecurityEntrance', form.settingInfo.securityEntrance)"
icon="Collection"
>
保存
</el-button>
</template>
</el-input>
<div>
<span class="input-help">
面板管理入口设置后只能通过指定安全入口登录面板,: /89dc6ae8
</span>
</div>
</el-form-item>
<el-form-item label="密码过期时间">
<el-input clearable v-model="form.settingInfo.passwordTimeOut">
<template #append>
<el-button
@click="SaveSetting('Password', form.settingInfo.passwordTimeOut)"
icon="Collection"
>
保存
</el-button>
</template>
</el-input>
<div>
<span class="input-help"> 为面板密码设置过期时间过期后需要重新设置密码 </span>
</div>
</el-form-item>
<el-form-item label="密码复杂度验证">
<el-switch
v-model="form.settingInfo.complexityVerification"
active-value="enable"
inactive-value="disable"
@change="SaveSetting('ComplexityVerification', form.settingInfo.complexityVerification)"
/>
<div>
<span class="input-help">
密码必须满足密码长度大于8位且大写字母小写字母数字特殊字符至少3项组合
</span>
</div>
</el-form-item>
<el-form-item label="两步验证">
<el-switch
v-model="form.settingInfo.mfaStatus"
active-value="enable"
inactive-value="disable"
@change="SaveSetting('MFAStatus', form.settingInfo.mfaStatus)"
/>
</el-form-item>
</el-col>
</el-row>
</el-card>
</el-form>
</template>
<script lang="ts" setup>
import { ElMessage, ElForm } from 'element-plus';
import { updateSetting } from '@/api/modules/setting';
import i18n from '@/lang';
interface Props {
settingInfo: any;
}
const form = withDefaults(defineProps<Props>(), {
settingInfo: {
serverPort: '',
securityEntrance: '',
passwordTimeOut: '',
complexityVerification: '',
mfaStatus: '',
},
});
const SaveSetting = async (key: string, val: string) => {
let param = {
key: key,
value: val,
};
await updateSetting(param);
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
};
</script>

View File

@ -1,7 +0,0 @@
<template>
<LayoutContent></LayoutContent>
</template>
<script lang="ts" setup>
import LayoutContent from '@/layout/layout-content.vue';
</script>