Browse Source

fix: 安全入口逻辑调整 (#821)

pull/822/head
ssongliu 2 years ago committed by GitHub
parent
commit
292dca6419
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      backend/app/api/v1/setting.go
  2. 1
      backend/app/dto/setting.go
  3. 10
      backend/app/service/auth.go
  4. 21
      backend/app/service/setting.go
  5. 3
      backend/configs/system.go
  6. 13
      backend/init/migration/migrations/init.go
  7. 28
      backend/init/viper/viper.go
  8. 1
      backend/router/ro_setting.go
  9. 4
      cmd/server/cmd/reset.go
  10. 429
      cmd/server/docs/docs.go
  11. 370
      cmd/server/docs/swagger.json
  12. 350
      cmd/server/docs/swagger.yaml
  13. 1
      frontend/src/api/interface/setting.ts
  14. 4
      frontend/src/api/modules/setting.ts
  15. 3
      frontend/src/lang/modules/en.ts
  16. 9
      frontend/src/lang/modules/zh.ts
  17. 2
      frontend/src/views/home/index.vue
  18. 3
      frontend/src/views/log/operation/index.vue
  19. 2
      frontend/src/views/setting/panel/index.vue
  20. 100
      frontend/src/views/setting/safe/entrance/index.vue
  21. 141
      frontend/src/views/setting/safe/index.vue
  22. 81
      frontend/src/views/setting/safe/timeout/index.vue

27
backend/app/api/v1/setting.go

@ -65,33 +65,6 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Update system entrance
// @Description 更新系统安全入口
// @Accept json
// @Param request body dto.SettingUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/entrance/enable [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统配置 [SecurityEntranceStatus] => [打开]","formatEN":"update system setting [SecurityEntranceStatus] => [Enable]"}
func (b *BaseApi) UpdateEntrance(c *gin.Context) {
var req dto.SettingUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := settingService.UpdateEntrance(req.Value); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Update system password
// @Description 更新系统登录密码

1
backend/app/dto/setting.go

@ -16,7 +16,6 @@ type SettingInfo struct {
Language string `json:"language"`
ServerPort string `json:"serverPort"`
SecurityEntranceStatus string `json:"securityEntranceStatus"`
SSL string `json:"ssl"`
SSLType string `json:"sslType"`
SecurityEntrance string `json:"securityEntrance"`

10
backend/app/service/auth.go

@ -148,18 +148,14 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
}
func (u *AuthService) CheckIsSafety(code string) bool {
status, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntranceStatus"))
status, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return false
}
if status.Value == "disable" {
if len(status.Value) == 0 {
return true
}
setting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return false
}
return setting.Value == code
return status.Value == code
}
func (u *AuthService) CheckIsFirst() bool {

21
backend/app/service/setting.go

@ -28,7 +28,6 @@ type SettingService struct{}
type ISettingService interface {
GetSettingInfo() (*dto.SettingInfo, error)
Update(key, value string) error
UpdateEntrance(value string) error
UpdatePassword(c *gin.Context, old, new string) error
UpdatePort(port uint) error
UpdateSSL(c *gin.Context, req dto.SSLUpdate) error
@ -68,16 +67,6 @@ func (u *SettingService) Update(key, value string) error {
return err
}
}
if key == "SecurityEntrance" {
if err := settingRepo.Update("SecurityEntranceStatus", "enable"); err != nil {
return err
}
}
if key == "SecurityEntranceStatus" {
if err := settingRepo.Update("SecurityEntrance", ""); err != nil {
return err
}
}
if err := settingRepo.Update(key, value); err != nil {
return err
}
@ -87,16 +76,6 @@ func (u *SettingService) Update(key, value string) error {
return nil
}
func (u *SettingService) UpdateEntrance(value string) error {
if err := settingRepo.Update("SecurityEntranceStatus", "enable"); err != nil {
return err
}
if err := settingRepo.Update("SecurityEntrance", value); err != nil {
return err
}
return nil
}
func (u *SettingService) UpdatePort(port uint) error {
if common.ScanPort(int(port)) {
return buserr.WithDetail(constant.ErrPortInUsed, port, nil)

3
backend/configs/system.go

@ -15,5 +15,8 @@ type System struct {
Mode string `mapstructure:"mode"`
RepoUrl string `mapstructure:"repo_url"`
Version string `mapstructure:"version"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Entrance string `mapstructure:"entrance"`
IsDemo bool `mapstructure:"is_demo"`
}

13
backend/init/migration/migrations/init.go

@ -61,10 +61,10 @@ var AddTableSetting = &gormigrate.Migration{
if err := tx.AutoMigrate(&model.Setting{}); err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "UserName", Value: ""}).Error; err != nil {
if err := tx.Create(&model.Setting{Key: "UserName", Value: global.CONF.System.Username}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "Password", Value: ""}).Error; err != nil {
if err := tx.Create(&model.Setting{Key: "Password", Value: global.CONF.System.Password}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "Email", Value: ""}).Error; err != nil {
@ -91,7 +91,7 @@ var AddTableSetting = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "ServerPort", Value: global.CONF.System.Port}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "SecurityEntrance", Value: "onepanel"}).Error; err != nil {
if err := tx.Create(&model.Setting{Key: "SecurityEntrance", Value: global.CONF.System.Entrance}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "JWTSigningKey", Value: common.RandStr(16)}).Error; err != nil {
@ -291,10 +291,9 @@ var UpdateTableWebsite = &gormigrate.Migration{
var AddEntranceAndSSL = &gormigrate.Migration{
ID: "20230414-add-entrance-and-ssl",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "SecurityEntranceStatus", Value: "disable"}).Error; err != nil {
return err
}
if err := tx.Model(&model.Setting{}).Where("key = ?", "SecurityEntrance").Updates(map[string]interface{}{"value": ""}).Error; err != nil {
if err := tx.Model(&model.Setting{}).
Where("key = ? AND value = ?", "SecurityEntrance", "onepanel").
Updates(map[string]interface{}{"value": ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "SSLType", Value: "self"}).Error; err != nil {

28
backend/init/viper/viper.go

@ -21,6 +21,7 @@ func Init() {
port := "9999"
mode := ""
version := "v1.0.0"
username, password, entrance := "", "", ""
fileOp := files.NewFileOp()
v := viper.NewWithOptions()
v.SetConfigType("yaml")
@ -40,8 +41,11 @@ func Init() {
}
} else {
baseDir = loadParams("BASE_DIR")
port = loadParams("PANEL_PORT")
version = loadParams("ORIGINAL_INSTALLED_VERSION")
port = loadParams("ORIGINAL_PORT")
version = loadParams("ORIGINAL_VERSION")
username = loadParams("ORIGINAL_USERNAME")
password = loadParams("ORIGINAL_PASSWORD")
entrance = loadParams("ORIGINAL_ENTRANCE")
if strings.HasSuffix(baseDir, "/") {
baseDir = baseDir[:strings.LastIndex(baseDir, "/")]
@ -60,15 +64,26 @@ func Init() {
if err := v.Unmarshal(&serverConfig); err != nil {
panic(err)
}
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.BaseDir != "" {
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") {
if serverConfig.System.BaseDir != "" {
baseDir = serverConfig.System.BaseDir
}
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.Port != "" {
if serverConfig.System.Port != "" {
port = serverConfig.System.Port
}
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.Version != "" {
if serverConfig.System.Version != "" {
version = serverConfig.System.Version
}
if serverConfig.System.Username != "" {
version = serverConfig.System.Username
}
if serverConfig.System.Password != "" {
version = serverConfig.System.Password
}
if serverConfig.System.Entrance != "" {
version = serverConfig.System.Entrance
}
}
global.CONF = serverConfig
global.CONF.System.BaseDir = baseDir
@ -81,6 +96,9 @@ func Init() {
global.CONF.System.TmpDir = global.CONF.System.DataDir + "/tmp"
global.CONF.System.Port = port
global.CONF.System.Version = version
global.CONF.System.Username = username
global.CONF.System.Password = password
global.CONF.System.Entrance = entrance
global.Viper = v
}

1
backend/router/ro_setting.go

@ -22,7 +22,6 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
router.POST("/expired/handle", baseApi.HandlePasswordExpired)
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
settingRouter.POST("/update", baseApi.UpdateSetting)
settingRouter.POST("/entrance/enable", baseApi.UpdateEntrance)
settingRouter.POST("/port/update", baseApi.UpdatePort)
settingRouter.POST("/ssl/update", baseApi.UpdateSSL)
settingRouter.GET("/ssl/info", baseApi.LoadFromCert)

4
cmd/server/cmd/reset.go

@ -24,7 +24,7 @@ var resetMFACmd = &cobra.Command{
}
var resetSSLCmd = &cobra.Command{
Use: "reset-ssl",
Use: "reset-https",
Short: "取消 1Panel https 方式登录",
RunE: func(cmd *cobra.Command, args []string) error {
db, err := loadDBConn()
@ -44,6 +44,6 @@ var resetEntranceCmd = &cobra.Command{
return err
}
return setSettingByKey(db, "SecurityEntranceStatus", "disable")
return setSettingByKey(db, "SecurityEntrance", "")
},
}

429
cmd/server/docs/docs.go

File diff suppressed because it is too large Load Diff

370
cmd/server/docs/swagger.json

File diff suppressed because it is too large Load Diff

350
cmd/server/docs/swagger.yaml

File diff suppressed because it is too large Load Diff

1
frontend/src/api/interface/setting.ts

@ -15,7 +15,6 @@ export namespace Setting {
language: string;
serverPort: number;
securityEntranceStatus: string;
ssl: string;
sslType: string;
securityEntrance: string;

4
frontend/src/api/modules/setting.ts

@ -16,10 +16,6 @@ export const updateSetting = (param: Setting.SettingUpdate) => {
return http.post(`/settings/update`, param);
};
export const updateEntrance = (param: Setting.SettingUpdate) => {
return http.post(`/settings/entrance/enable`, param);
};
export const updatePassword = (param: Setting.PasswordUpdate) => {
return http.post(`/settings/password/update`, param);
};

3
frontend/src/lang/modules/en.ts

@ -869,10 +869,11 @@ const message = {
path: 'Path',
safe: 'Security',
safeEntrance: 'Security entrance',
entrance: 'Entrance',
entranceHelper: 'Enabling secure entry will only allow logging in to the panel through specified secure entry.',
entranceError:
'Please enter a secure login entry point of 6-10 characters, only numbers or letters are supported.',
entranceInputHelper: 'When the security entry is set to blank, the security entry is cancelled.',
expirationTime: 'Expiration Time',
unSetting: 'Not Set',
noneSetting:

9
frontend/src/lang/modules/zh.ts

@ -830,9 +830,6 @@ const message = {
portHelper: '建议端口范围8888 - 65535注意有安全组的服务器请提前在安全组放行新端口',
portChange: '端口修改',
portChangeHelper: '服务端口修改需要重启服务是否继续',
entrance: '安全入口',
entranceHelper: '开启安全入口后只能通过指定安全入口登录面板',
entranceError: '请输入 6-10 位安全登录入口仅支持输入数字或字母',
theme: '主题颜色',
componentSize: '组件大小',
dark: '暗色',
@ -924,8 +921,10 @@ const message = {
hasNewVersion: '有新版本',
safe: '安全',
safeEntrance: '安全入口',
safeEntranceHelper: '面板管理入口设置后只能通过指定安全入口登录面板: onepanel',
entrance: '安全入口',
entranceHelper: '开启安全入口后只能通过指定安全入口登录面板',
entranceError: '请输入 6-10 位安全登录入口仅支持输入数字或字母',
entranceInputHelper: '安全入口设置为空时则取消安全入口',
expirationTime: '密码过期时间',
unSetting: '未设置',
noneSetting: '为面板密码设置过期时间过期后需要重新设置密码',

2
frontend/src/views/home/index.vue

@ -502,7 +502,7 @@ const loadUpgradeStatus = async () => {
const loadSafeStatus = async () => {
const res = await getSettingInfo();
isSafety.value = res.data.securityEntranceStatus === 'enable';
isSafety.value = res.data.securityEntrance;
};
onMounted(() => {

3
frontend/src/views/log/operation/index.vue

@ -183,9 +183,6 @@ const loadDetail = (log: string) => {
if (log.indexOf('[SessionTimeout]') !== -1) {
return log.replace('[SessionTimeout]', '[' + i18n.global.t('setting.sessionTimeout') + ']');
}
if (log.indexOf('SecurityEntranceStatus') !== -1) {
return log.replace('[SecurityEntranceStatus]', '[' + i18n.global.t('setting.entrance') + ']');
}
if (log.indexOf('SecurityEntrance') !== -1) {
return log.replace('[SecurityEntrance]', '[' + i18n.global.t('setting.entrance') + ']');
}

2
frontend/src/views/setting/panel/index.vue

@ -21,7 +21,7 @@
</el-form-item>
<el-form-item :label="$t('setting.passwd')" :rules="Rules.requiredInput" prop="password">
<el-input type="password" clearable disabled v-model="form.password">
<el-input type="password" disabled v-model="form.password">
<template #append>
<el-button style="width: 85px" icon="Setting" @click="onChangePassword">
{{ $t('commons.button.set') }}

100
frontend/src/views/setting/safe/entrance/index.vue

@ -0,0 +1,100 @@
<template>
<div>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('setting.entrance')" :back="handleClose" />
</template>
<el-form label-position="top" v-loading="loading">
<el-form-item :label="$t('setting.entrance')" prop="days">
<el-input clearable v-model="securityEntrance">
<template #append>
<el-button @click="random" icon="RefreshRight"></el-button>
</template>
</el-input>
<span class="input-help">
{{ $t('setting.entranceInputHelper') }}
</span>
<span class="input-error" v-if="codeError">
{{ $t('setting.entranceError') }}
</span>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="submitEntrance">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { updateSetting } from '@/api/modules/setting';
import { GlobalStore } from '@/store';
import { getRandomStr } from '@/utils/util';
const globalStore = GlobalStore();
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
securityEntrance: string;
}
const securityEntrance = ref();
const drawerVisiable = ref();
const loading = ref();
const codeError = ref();
const acceptParams = (params: DialogProps): void => {
securityEntrance.value = params.securityEntrance;
drawerVisiable.value = true;
};
const random = async () => {
securityEntrance.value = getRandomStr(8);
};
const submitEntrance = async () => {
if (securityEntrance.value !== '') {
const reg = /^[A-Za-z0-9]{6,10}$/;
if (!reg.test(securityEntrance.value)) {
codeError.value = true;
return;
}
}
let param = {
key: 'SecurityEntrance',
value: securityEntrance.value,
};
loading.value = true;
await updateSetting(param)
.then(() => {
globalStore.entrance = securityEntrance.value;
loading.value = false;
drawerVisiable.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
})
.catch(() => {
loading.value = false;
});
};
const handleClose = () => {
drawerVisiable.value = false;
};
defineExpose({
acceptParams,
});
</script>
<style scoped lang="scss">
.margintop {
margin-top: 10px;
}
</style>

141
frontend/src/views/setting/safe/index.vue

@ -21,32 +21,26 @@
</el-form-item>
<el-form-item :label="$t('setting.entrance')">
<el-switch
@change="handleEntrance"
v-model="form.securityEntranceStatus"
active-value="enable"
inactive-value="disable"
/>
<span class="input-help">
{{ $t('setting.entranceHelper') }}
</span>
<el-input
@blur="codeError = false"
v-if="isEntranceShow"
type="password"
show-password
clearable
disabled
v-if="form.securityEntrance"
v-model="form.securityEntrance"
>
<template #append>
<el-button style="width: 85px" @click="onSaveEntrance" icon="Collection">
{{ $t('commons.button.save') }}
<el-button style="width: 85px" @click="onChangeEntrance" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-error" v-if="codeError">
{{ $t('setting.entranceError') }}
</span>
<el-input disabled v-if="!form.securityEntrance" v-model="unset">
<template #append>
<el-button style="width: 85px" @click="onChangeEntrance" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('setting.entranceHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.expirationTime')" prop="expirationTime">
@ -142,25 +136,9 @@
</el-form>
</template>
</LayoutContent>
<el-drawer v-model="timeoutVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('setting.expirationTime')" :back="handleClose" />
</template>
<el-form ref="timeoutFormRef" label-position="top" :model="timeoutForm">
<el-form-item :label="$t('setting.days')" prop="days" :rules="[Rules.number, checkNumberRange(0, 60)]">
<el-input clearable v-model.number="timeoutForm.days" />
<span class="input-help">{{ $t('setting.expirationHelper') }}</span>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="timeoutVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="submitTimeout(timeoutFormRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
<EntranceSetting ref="entranceRef" @search="search" />
<TimeoutSetting ref="timeoutref" @search="search" />
</div>
</template>
@ -170,7 +148,8 @@ import { ElForm, ElMessageBox } from 'element-plus';
import { Setting } from '@/api/interface/setting';
import LayoutContent from '@/layout/layout-content.vue';
import SSLSetting from '@/views/setting/safe/ssl/index.vue';
import DrawerHeader from '@/components/drawer-header/index.vue';
import TimeoutSetting from '@/views/setting/safe/timeout/index.vue';
import EntranceSetting from '@/views/setting/safe/entrance/index.vue';
import {
updateSetting,
getMFA,
@ -178,21 +157,18 @@ import {
getSettingInfo,
updatePort,
getSystemAvailable,
updateEntrance,
updateSSL,
} from '@/api/modules/setting';
import i18n from '@/lang';
import { Rules, checkNumberRange } from '@/global/form-rules';
import { dateFormatSimple } from '@/utils/util';
import { Rules } from '@/global/form-rules';
import { MsgError, MsgSuccess } from '@/utils/message';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
const loading = ref(false);
const entranceRef = ref();
const timeoutref = ref();
const form = reactive({
serverPort: 9999,
securityEntranceStatus: 'disable',
ssl: 'disable',
sslType: 'self',
securityEntrance: '',
@ -203,20 +179,15 @@ const form = reactive({
mfaSecret: 'disable',
});
type FormInstance = InstanceType<typeof ElForm>;
const timeoutFormRef = ref<FormInstance>();
const timeoutVisiable = ref<boolean>(false);
const timeoutForm = reactive({
days: 0,
});
const sslShow = ref();
const oldSSLStatus = ref();
const unset = ref(i18n.global.t('setting.unSetting'));
const search = async () => {
const res = await getSettingInfo();
form.serverPort = Number(res.data.serverPort);
form.securityEntranceStatus = res.data.securityEntranceStatus;
isEntranceShow.value = res.data.securityEntranceStatus === 'enable';
form.ssl = res.data.ssl;
oldSSLStatus.value = res.data.ssl;
form.sslType = res.data.sslType;
@ -231,9 +202,6 @@ const search = async () => {
form.mfaSecret = res.data.mfaSecret;
};
const isEntranceShow = ref(false);
const codeError = ref(false);
const isMFAShow = ref<boolean>(false);
const otp = reactive<Setting.MFAInfo>({
secret: '',
@ -322,23 +290,8 @@ const handleMFA = async () => {
}
};
const handleEntrance = async () => {
if (form.securityEntranceStatus === 'enable') {
isEntranceShow.value = true;
} else {
isEntranceShow.value = false;
loading.value = true;
await updateSetting({ key: 'SecurityEntranceStatus', value: 'disable' })
.then(() => {
globalStore.entrance = '';
loading.value = false;
search();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
}
const onChangeEntrance = async () => {
entranceRef.value.acceptParams({ securityEntrance: form.securityEntrance });
};
const handleSSL = async () => {
@ -368,29 +321,6 @@ const handleSSL = async () => {
});
};
const onSaveEntrance = async () => {
const reg = /^[A-Za-z0-9]{6,10}$/;
if ((!reg.test(form.securityEntrance) && form.securityEntrance !== '') || form.securityEntrance === '') {
codeError.value = true;
return;
}
loading.value = true;
await updateEntrance({ key: 'SecurityEntrance', value: form.securityEntrance })
.then(() => {
globalStore.entrance = form.securityEntrance;
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
search();
})
.catch(() => {
loading.value = false;
});
};
const handleClose = () => {
timeoutVisiable.value = false;
};
const onBind = async () => {
if (!mfaCode.value) {
MsgError(i18n.global.t('commons.msg.comfimNoNull', ['code']));
@ -415,28 +345,7 @@ const onCancelMfaBind = async () => {
};
const onChangeExpirationTime = async () => {
timeoutForm.days = form.expirationDays;
timeoutVisiable.value = true;
};
const submitTimeout = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
let time = new Date(new Date().getTime() + 3600 * 1000 * 24 * timeoutForm.days);
loading.value = true;
await updateSetting({ key: 'ExpirationDays', value: timeoutForm.days + '' })
.then(() => {
loading.value = false;
search();
loadTimeOut();
form.expirationTime = dateFormatSimple(time);
timeoutVisiable.value = false;
})
.catch(() => {
loading.value = false;
});
});
timeoutref.value.acceptParams({ expirationDays: form.expirationDays });
};
function loadTimeOut() {

81
frontend/src/views/setting/safe/timeout/index.vue

@ -0,0 +1,81 @@
<template>
<div>
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('setting.expirationTime')" :back="handleClose" />
</template>
<el-form ref="timeoutFormRef" label-position="top" :model="form">
<el-form-item :label="$t('setting.days')" prop="days" :rules="[Rules.number, checkNumberRange(0, 60)]">
<el-input clearable v-model.number="form.days" />
<span class="input-help">{{ $t('setting.expirationHelper') }}</span>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="submitTimeout(timeoutFormRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { MsgSuccess } from '@/utils/message';
import { updateSetting } from '@/api/modules/setting';
import { FormInstance } from 'element-plus';
import { Rules, checkNumberRange } from '@/global/form-rules';
import i18n from '@/lang';
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
expirationDays: number;
}
const drawerVisiable = ref();
const loading = ref();
const timeoutFormRef = ref();
const form = reactive({
days: 0,
});
const acceptParams = (params: DialogProps): void => {
form.days = params.expirationDays;
drawerVisiable.value = true;
};
const submitTimeout = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
loading.value = true;
await updateSetting({ key: 'ExpirationDays', value: form.days + '' })
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
drawerVisiable.value = false;
})
.catch(() => {
loading.value = false;
});
});
};
const handleClose = () => {
drawerVisiable.value = false;
};
defineExpose({
acceptParams,
});
</script>
<style scoped lang="scss">
.margintop {
margin-top: 10px;
}
</style>
Loading…
Cancel
Save