mirror of
				https://github.com/1Panel-dev/1Panel.git
				synced 2025-10-31 03:07:34 +08:00 
			
		
		
		
	feat: 面板设置增加表单校验
This commit is contained in:
		
							parent
							
								
									9f5e9d26f5
								
							
						
					
					
						commit
						fc3318c8e9
					
				
					 20 changed files with 266 additions and 133 deletions
				
			
		|  | @ -4,14 +4,14 @@ type SettingInfo struct { | |||
| 	UserName string `json:"userName"` | ||||
| 	Email    string `json:"email"` | ||||
| 
 | ||||
| 	SessionTimeout string `json:"sessionTimeout"` | ||||
| 	SessionTimeout int    `json:"sessionTimeout"` | ||||
| 	LocalTime      string `json:"localTime"` | ||||
| 
 | ||||
| 	PanelName string `json:"panelName"` | ||||
| 	Theme     string `json:"theme"` | ||||
| 	Language  string `json:"language"` | ||||
| 
 | ||||
| 	ServerPort             string `json:"serverPort"` | ||||
| 	ServerPort             int    `json:"serverPort"` | ||||
| 	SecurityEntrance       string `json:"securityEntrance"` | ||||
| 	PasswordTimeOut        string `json:"passwordTimeOut"` | ||||
| 	ComplexityVerification string `json:"complexityVerification"` | ||||
|  | @ -19,7 +19,7 @@ type SettingInfo struct { | |||
| 	MFASecret              string `json:"mfaSecret"` | ||||
| 
 | ||||
| 	MonitorStatus    string `json:"monitorStatus"` | ||||
| 	MonitorStoreDays string `json:"monitorStoreDays"` | ||||
| 	MonitorStoreDays int    `json:"monitorStoreDays"` | ||||
| 
 | ||||
| 	MessageType string `json:"messageType"` | ||||
| 	EmailVars   string `json:"emailVars"` | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ package service | |||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/1Panel-dev/1Panel/app/dto" | ||||
|  | @ -37,9 +38,10 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) { | |||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := json.Unmarshal(arr, &info); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	_ = json.Unmarshal(arr, &info) | ||||
| 	info.MonitorStoreDays, _ = strconv.Atoi(settingMap["MonitorStoreDays"]) | ||||
| 	info.ServerPort, _ = strconv.Atoi(settingMap["ServerPort"]) | ||||
| 	info.SessionTimeout, _ = strconv.Atoi(settingMap["SessionTimeout"]) | ||||
| 	info.LocalTime = time.Now().Format("2006-01-02 15:04:05") | ||||
| 	return &info, err | ||||
| } | ||||
|  |  | |||
|  | @ -4,14 +4,14 @@ export namespace Setting { | |||
|         password: string; | ||||
|         email: string; | ||||
| 
 | ||||
|         sessionTimeout: string; | ||||
|         sessionTimeout: number; | ||||
|         localTime: string; | ||||
| 
 | ||||
|         panelName: string; | ||||
|         theme: string; | ||||
|         language: string; | ||||
| 
 | ||||
|         serverPort: string; | ||||
|         serverPort: number; | ||||
|         securityEntrance: string; | ||||
|         passwordTimeOut: string; | ||||
|         complexityVerification: string; | ||||
|  | @ -19,7 +19,7 @@ export namespace Setting { | |||
|         mfaSecret: string; | ||||
| 
 | ||||
|         monitorStatus: string; | ||||
|         monitorStoreDays: string; | ||||
|         monitorStoreDays: number; | ||||
| 
 | ||||
|         messageType: string; | ||||
|         emailVars: string; | ||||
|  | @ -33,7 +33,6 @@ export namespace Setting { | |||
|     export interface PasswordUpdate { | ||||
|         oldPassword: string; | ||||
|         newPassword: string; | ||||
|         retryPassword: string; | ||||
|     } | ||||
|     export interface MFAInfo { | ||||
|         secret: string; | ||||
|  |  | |||
|  | @ -15,10 +15,37 @@ const checkIp = (rule: any, value: any, callback: any) => { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| const complexityPassword = (rule: any, value: any, callback: any) => { | ||||
|     if (value === '' || typeof value === 'undefined' || value == null) { | ||||
|         callback(new Error(i18n.global.t('commons.rule.complexityPassword'))); | ||||
|     } else { | ||||
|         const reg = /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[~!@#$%^&*.])[\da-zA-Z~!@#$%^&*.]{8,}$/; | ||||
|         if (!reg.test(value) && value !== '') { | ||||
|             callback(new Error(i18n.global.t('commons.rule.complexityPassword'))); | ||||
|         } else { | ||||
|             callback(); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| const checkName = (rule: any, value: any, callback: any) => { | ||||
|     if (value === '' || typeof value === 'undefined' || value == null) { | ||||
|         callback(new Error(i18n.global.t('commons.rule.commonName'))); | ||||
|     } else { | ||||
|         const reg = /^[a-zA-Z0-9\u4e00-\u9fa5]{1}[a-zA-Z0-9_.\u4e00-\u9fa5-]{0,30}$/; | ||||
|         if (!reg.test(value) && value !== '') { | ||||
|             callback(new Error(i18n.global.t('commons.rule.commonName'))); | ||||
|         } else { | ||||
|             callback(); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| interface CommonRule { | ||||
|     requiredInput: FormItemRule; | ||||
|     requiredSelect: FormItemRule; | ||||
|     name: FormItemRule; | ||||
|     password: FormItemRule; | ||||
|     email: FormItemRule; | ||||
|     number: FormItemRule; | ||||
|     ip: FormItemRule; | ||||
|  | @ -37,14 +64,15 @@ export const Rules: CommonRule = { | |||
|         trigger: 'change', | ||||
|     }, | ||||
|     name: { | ||||
|         type: 'regexp', | ||||
|         min: 1, | ||||
|         max: 30, | ||||
|         message: i18n.global.t('commons.rule.commonName'), | ||||
|         validator: checkName, | ||||
|         trigger: 'blur', | ||||
|     }, | ||||
|     password: { | ||||
|         validator: complexityPassword, | ||||
|         trigger: 'blur', | ||||
|         pattern: '/^[a-zA-Z0-9\u4e00-\u9fa5]{1}[a-zA-Z0-9_.\u4e00-\u9fa5-]{0,30}$/', | ||||
|     }, | ||||
|     email: { | ||||
|         required: true, | ||||
|         type: 'email', | ||||
|         message: i18n.global.t('commons.rule.email'), | ||||
|         trigger: 'blur', | ||||
|  | @ -68,6 +68,9 @@ export default { | |||
|             requiredInput: 'Please enter the required fields', | ||||
|             requiredSelect: 'Please select the required fields', | ||||
|             commonName: 'Support English, Chinese, numbers, .-_, length 1-30', | ||||
|             complexityPassword: | ||||
|                 'Please enter a password with more than 8 characters and must contain letters, digits, and special symbols', | ||||
|             commonPassword: 'Please enter a password with more than 6 characters', | ||||
|             email: 'Email format error', | ||||
|             ip: 'Please enter the correct IP address', | ||||
|             port: 'Please enter the correct port', | ||||
|  |  | |||
|  | @ -77,6 +77,8 @@ export default { | |||
|             requiredInput: '请填写必填项', | ||||
|             requiredSelect: '请选择必选项', | ||||
|             commonName: '支持英文、中文、数字、.-_,长度1-30', | ||||
|             complexityPassword: '请输入 8 位以上、必须含有字母、数字、特殊符号的密码', | ||||
|             commonPassword: '请输入 6 位以上长度密码', | ||||
|             email: '请输入正确的邮箱', | ||||
|             number: '请输入正确的数字', | ||||
|             ip: '请输入正确的 IP 地址', | ||||
|  | @ -298,7 +300,7 @@ export default { | |||
|         passwordTimeout: '密码过期时间', | ||||
|         timeoutHelper: '【 {0} 天后 】面板密码即将过期,过期后需要重新设置密码', | ||||
|         complexity: '密码复杂度验证', | ||||
|         complexityHelper: '密码必须满足密码长度大于8位且大写字母、小写字母、数字、特殊字符至少3项组合', | ||||
|         complexityHelper: '密码必须满足密码长度大于 8 位且包含字母、数字及特殊字符', | ||||
|         mfa: '两步验证', | ||||
|         mfaHelper1: '下载两步验证手机应用 如:', | ||||
|         mfaHelper2: '使用手机应用扫描以下二维码,获取 6 位验证码', | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ import i18n from '@/lang'; | |||
| import { computed, reactive, ref, toRefs } from 'vue'; | ||||
| import { File } from '@/api/interface/file'; | ||||
| import { ElMessage, FormInstance, FormRules } from 'element-plus'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import { CompressExtention, CompressType } from '@/enums/files'; | ||||
| import { CompressFile } from '@/api/modules/files'; | ||||
| import FileList from '@/components/file-list/index.vue'; | ||||
|  |  | |||
|  | @ -56,7 +56,7 @@ import { ElMessage, FormInstance, FormRules } from 'element-plus'; | |||
| import { CreateFile } from '@/api/modules/files'; | ||||
| import i18n from '@/lang'; | ||||
| import FileRole from '@/components/file-role/index.vue'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import FileList from '@/components/file-list/index.vue'; | ||||
| 
 | ||||
| const fileForm = ref<FormInstance>(); | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ import i18n from '@/lang'; | |||
| import { reactive, ref, toRefs } from 'vue'; | ||||
| import { File } from '@/api/interface/file'; | ||||
| import { ElMessage, FormInstance, FormRules } from 'element-plus'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import { DeCompressFile } from '@/api/modules/files'; | ||||
| import { Mimetypes } from '@/global/mimetype'; | ||||
| import FileList from '@/components/file-list/index.vue'; | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ import { CompressExtention, CompressType } from '@/enums/files'; | |||
| import { computed, PropType, reactive, ref, toRefs } from 'vue'; | ||||
| import { DownloadFile } from '@/api/modules/files'; | ||||
| import { File } from '@/api/interface/file'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|     open: { | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ | |||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { MoveFile } from '@/api/modules/files'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import i18n from '@/lang'; | ||||
| import { ElMessage, FormInstance, FormRules } from 'element-plus'; | ||||
| import { toRefs, ref, reactive, PropType, computed } from 'vue'; | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { RenameRile } from '@/api/modules/files'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import { ElMessage, FormInstance, FormRules } from 'element-plus'; | ||||
| import { reactive, ref, toRefs } from 'vue'; | ||||
| import { File } from '@/api/interface/file'; | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ | |||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { WgetFile } from '@/api/modules/files'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import i18n from '@/lang'; | ||||
| import { ElMessage, FormInstance, FormRules } from 'element-plus'; | ||||
| import { reactive, ref, toRefs } from 'vue'; | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ import { addCommand, editCommand, deleteCommand, getCommandPage } from '@/api/mo | |||
| import { reactive, ref } from '@vue/runtime-core'; | ||||
| import { useDeleteData } from '@/hooks/use-delete-data'; | ||||
| import type { ElForm } from 'element-plus'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import i18n from '@/lang'; | ||||
| import { ElMessage } from 'element-plus'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -119,7 +119,7 @@ | |||
| <script lang="ts" setup> | ||||
| import { ref, reactive } from 'vue'; | ||||
| import type { ElForm } from 'element-plus'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import { Host } from '@/api/interface/host'; | ||||
| import { Group } from '@/api/interface/group'; | ||||
| import { testConn, getHostTree, getHostInfo, addHost, editHost, deleteHost } from '@/api/modules/host'; | ||||
|  |  | |||
|  | @ -173,7 +173,7 @@ | |||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { onMounted, onBeforeMount, ref, watch, reactive, getCurrentInstance } from 'vue'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import { testConn, getHostTree, addHost } from '@/api/modules/host'; | ||||
| import { getCommandList } from '@/api/modules/command'; | ||||
| import i18n from '@/lang'; | ||||
|  |  | |||
|  | @ -7,45 +7,51 @@ | |||
|                 <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> | ||||
|         <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" /> | ||||
|         <Panel v-if="activeNames === 'all' || activeNames === 'panel'" :settingInfo="form" @on-save="SaveSetting" /> | ||||
|         <Safe v-if="activeNames === 'all' || activeNames === 'safe'" :settingInfo="form" @on-save="SaveSetting" /> | ||||
|         <Backup v-if="activeNames === 'all' || activeNames === 'backup'" :settingInfo="form" @on-save="SaveSetting" /> | ||||
|         <Monitor v-if="activeNames === 'all' || activeNames === 'monitor'" :settingInfo="form" @on-save="SaveSetting" /> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { ref, onMounted } from 'vue'; | ||||
| import { getSettingInfo } from '@/api/modules/setting'; | ||||
| import { ref, onMounted, computed } from 'vue'; | ||||
| import { getSettingInfo, updateSetting } 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'; | ||||
| import { GlobalStore } from '@/store'; | ||||
| import { useTheme } from '@/hooks/use-theme'; | ||||
| import { useI18n } from 'vue-i18n'; | ||||
| import { ElMessage, FormInstance } from 'element-plus'; | ||||
| 
 | ||||
| const i18n = useI18n(); | ||||
| const globalStore = GlobalStore(); | ||||
| const themeConfig = computed(() => globalStore.themeConfig); | ||||
| 
 | ||||
| const activeNames = ref('all'); | ||||
| let form = ref<Setting.SettingInfo>({ | ||||
|     userName: '', | ||||
|     password: '', | ||||
|     email: '', | ||||
|     sessionTimeout: '', | ||||
|     sessionTimeout: 86400, | ||||
|     localTime: '', | ||||
|     panelName: '', | ||||
|     theme: '', | ||||
|     language: '', | ||||
|     serverPort: '', | ||||
|     serverPort: 8888, | ||||
|     securityEntrance: '', | ||||
|     passwordTimeOut: '', | ||||
|     complexityVerification: '', | ||||
|     mfaStatus: '', | ||||
|     mfaSecret: '', | ||||
|     monitorStatus: '', | ||||
|     monitorStoreDays: '', | ||||
|     monitorStoreDays: 30, | ||||
|     messageType: '', | ||||
|     emailVars: '', | ||||
|     weChatVars: '', | ||||
|  | @ -58,6 +64,52 @@ const search = async () => { | |||
|     form.value.password = '******'; | ||||
| }; | ||||
| 
 | ||||
| const { switchDark } = useTheme(); | ||||
| 
 | ||||
| const SaveSetting = async (formEl: FormInstance | undefined, key: string, val: any) => { | ||||
|     if (!formEl) return; | ||||
|     const result = await formEl.validateField('settingInfo.' + key.replace(key[0], key[0].toLowerCase()), callback); | ||||
|     if (!result) { | ||||
|         return; | ||||
|     } | ||||
|     if (val === '') { | ||||
|         return; | ||||
|     } | ||||
|     switch (key) { | ||||
|         case 'Language': | ||||
|             i18n.locale.value = val; | ||||
|             globalStore.updateLanguage(val); | ||||
|             break; | ||||
|         case 'Theme': | ||||
|             globalStore.setThemeConfig({ ...themeConfig.value, theme: val }); | ||||
|             switchDark(); | ||||
|             break; | ||||
|         case 'PanelName': | ||||
|             globalStore.setThemeConfig({ ...themeConfig.value, panelName: val }); | ||||
|             break; | ||||
|         case 'SessionTimeout': | ||||
|         case 'MonitorStoreDays': | ||||
|         case 'ServerPort': | ||||
|             val = val + ''; | ||||
|             break; | ||||
|     } | ||||
|     let param = { | ||||
|         key: key, | ||||
|         value: val, | ||||
|     }; | ||||
|     await updateSetting(param); | ||||
|     ElMessage.success(i18n.t('commons.msg.operationSuccess')); | ||||
|     search(); | ||||
| }; | ||||
| 
 | ||||
| function callback(error: any) { | ||||
|     if (error) { | ||||
|         return error.message; | ||||
|     } else { | ||||
|         return; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| onMounted(() => { | ||||
|     search(); | ||||
| }); | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
|     <el-form :model="form" label-position="left" label-width="160px"> | ||||
|     <el-form :model="form" ref="panelFormRef" label-position="left" label-width="160px"> | ||||
|         <el-card style="margin-top: 10px"> | ||||
|             <template #header> | ||||
|                 <div class="card-header"> | ||||
|  | @ -9,20 +9,28 @@ | |||
|             <el-row> | ||||
|                 <el-col :span="1"><br /></el-col> | ||||
|                 <el-col :span="10"> | ||||
|                     <el-form-item :label="$t('setting.enableMonitor')"> | ||||
|                     <el-form-item | ||||
|                         :label="$t('setting.enableMonitor')" | ||||
|                         :rules="Rules.requiredInput" | ||||
|                         prop="settingInfo.monitorStatus" | ||||
|                     > | ||||
|                         <el-radio-group | ||||
|                             @change="SaveSetting('MonitorStatus', form.settingInfo.monitorStatus)" | ||||
|                             @change="onSave(panelFormRef, 'MonitorStatus', form.settingInfo.monitorStatus)" | ||||
|                             v-model="form.settingInfo.monitorStatus" | ||||
|                         > | ||||
|                             <el-radio-button label="enable">{{ $t('commons.button.enable') }}</el-radio-button> | ||||
|                             <el-radio-button label="disable">{{ $t('commons.button.disable') }}</el-radio-button> | ||||
|                         </el-radio-group> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item :label="$t('setting.storeDays')"> | ||||
|                         <el-input clearable v-model="form.settingInfo.monitorStoreDays"> | ||||
|                     <el-form-item | ||||
|                         :label="$t('setting.storeDays')" | ||||
|                         :rules="Rules.number" | ||||
|                         prop="settingInfo.monitorStoreDays" | ||||
|                     > | ||||
|                         <el-input clearable v-model.number="form.settingInfo.monitorStoreDays"> | ||||
|                             <template #append> | ||||
|                                 <el-button | ||||
|                                     @click="SaveSetting('MonitorStoreDays', form.settingInfo.monitorStoreDays)" | ||||
|                                     @click="onSave(panelFormRef, 'MonitorStoreDays', form.settingInfo.monitorStoreDays)" | ||||
|                                     icon="Collection" | ||||
|                                 > | ||||
|                                     {{ $t('commons.button.save') }} | ||||
|  | @ -40,10 +48,13 @@ | |||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { ElMessage } from 'element-plus'; | ||||
| import { updateSetting, cleanMonitors } from '@/api/modules/setting'; | ||||
| import i18n from '@/lang'; | ||||
| import { ref } from 'vue'; | ||||
| import { FormInstance } from 'element-plus'; | ||||
| import { cleanMonitors } from '@/api/modules/setting'; | ||||
| import { useDeleteData } from '@/hooks/use-delete-data'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| 
 | ||||
| const emit = defineEmits<{ (e: 'on-save', formEl: FormInstance | undefined, key: string, val: any): void }>(); | ||||
| 
 | ||||
| interface Props { | ||||
|     settingInfo: any; | ||||
|  | @ -51,18 +62,14 @@ interface Props { | |||
| const form = withDefaults(defineProps<Props>(), { | ||||
|     settingInfo: { | ||||
|         monitorStatus: '', | ||||
|         monitorStoreDays: '', | ||||
|         monitorStoreDays: 30, | ||||
|     }, | ||||
| }); | ||||
| const panelFormRef = ref<FormInstance>(); | ||||
| 
 | ||||
| const SaveSetting = async (key: string, val: string) => { | ||||
|     let param = { | ||||
|         key: key, | ||||
|         value: val, | ||||
|     }; | ||||
|     await updateSetting(param); | ||||
|     ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); | ||||
| }; | ||||
| function onSave(formEl: FormInstance | undefined, key: string, val: any) { | ||||
|     emit('on-save', formEl, key, val); | ||||
| } | ||||
| 
 | ||||
| const onClean = async () => { | ||||
|     await useDeleteData(cleanMonitors, {}, 'commons.msg.delete', true); | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
|     <el-form :model="form" label-position="left" label-width="160px"> | ||||
|     <el-form :model="form" ref="panelFormRef" label-position="left" label-width="160px"> | ||||
|         <el-card style="margin-top: 20px"> | ||||
|             <template #header> | ||||
|                 <div class="card-header"> | ||||
|  | @ -9,11 +9,11 @@ | |||
|             <el-row> | ||||
|                 <el-col :span="1"><br /></el-col> | ||||
|                 <el-col :span="10"> | ||||
|                     <el-form-item :label="$t('auth.username')" prop="settingInfo.userName"> | ||||
|                     <el-form-item :label="$t('auth.username')" :rules="Rules.requiredInput" prop="settingInfo.userName"> | ||||
|                         <el-input clearable v-model="form.settingInfo.userName"> | ||||
|                             <template #append> | ||||
|                                 <el-button | ||||
|                                     @click="SaveSetting('UserName', form.settingInfo.userName)" | ||||
|                                     @click="onSave(panelFormRef, 'UserName', form.settingInfo.userName)" | ||||
|                                     icon="Collection" | ||||
|                                 > | ||||
|                                     {{ $t('commons.button.save') }} | ||||
|  | @ -21,7 +21,7 @@ | |||
|                             </template> | ||||
|                         </el-input> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item :label="$t('auth.password')" prop="settingInfo.password"> | ||||
|                     <el-form-item :label="$t('auth.password')" :rules="Rules.requiredInput" prop="settingInfo.password"> | ||||
|                         <el-input type="password" clearable disabled v-model="form.settingInfo.password"> | ||||
|                             <template #append> | ||||
|                                 <el-button icon="Setting" @click="passwordVisiable = true"> | ||||
|  | @ -30,10 +30,13 @@ | |||
|                             </template> | ||||
|                         </el-input> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item :label="$t('auth.email')" prop="settingInfo.email"> | ||||
|                     <el-form-item :label="$t('auth.email')" :rules="Rules.email" prop="settingInfo.email"> | ||||
|                         <el-input clearable v-model="form.settingInfo.email"> | ||||
|                             <template #append> | ||||
|                                 <el-button @click="SaveSetting('Email', form.settingInfo.email)" icon="Collection"> | ||||
|                                 <el-button | ||||
|                                     @click="onSave(panelFormRef, 'Email', form.settingInfo.email)" | ||||
|                                     icon="Collection" | ||||
|                                 > | ||||
|                                     {{ $t('commons.button.save') }} | ||||
|                                 </el-button> | ||||
|                             </template> | ||||
|  | @ -42,11 +45,15 @@ | |||
|                             <span class="input-help">{{ $t('setting.emailHelper') }}</span> | ||||
|                         </div> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item :label="$t('setting.title')" prop="settingInfo.panelName"> | ||||
|                     <el-form-item | ||||
|                         :label="$t('setting.title')" | ||||
|                         :rules="Rules.requiredInput" | ||||
|                         prop="settingInfo.panelName" | ||||
|                     > | ||||
|                         <el-input clearable v-model="form.settingInfo.panelName"> | ||||
|                             <template #append> | ||||
|                                 <el-button | ||||
|                                     @click="SaveSetting('PanelName', form.settingInfo.panelName)" | ||||
|                                     @click="onSave(panelFormRef, 'PanelName', form.settingInfo.panelName)" | ||||
|                                     icon="Collection" | ||||
|                                 > | ||||
|                                     {{ $t('commons.button.save') }} | ||||
|  | @ -54,9 +61,9 @@ | |||
|                             </template> | ||||
|                         </el-input> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item :label="$t('setting.theme')" prop="settingInfo.theme"> | ||||
|                     <el-form-item :label="$t('setting.theme')" :rules="Rules.requiredSelect" prop="settingInfo.theme"> | ||||
|                         <el-radio-group | ||||
|                             @change="SaveSetting('Theme', form.settingInfo.theme)" | ||||
|                             @change="onSave(panelFormRef, 'Theme', form.settingInfo.theme)" | ||||
|                             v-model="form.settingInfo.theme" | ||||
|                         > | ||||
|                             <el-radio-button label="dark"> | ||||
|  | @ -69,9 +76,13 @@ | |||
|                             </el-radio-button> | ||||
|                         </el-radio-group> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item :label="$t('setting.language')" prop="settingInfo.language"> | ||||
|                     <el-form-item | ||||
|                         :label="$t('setting.language')" | ||||
|                         :rules="Rules.requiredSelect" | ||||
|                         prop="settingInfo.language" | ||||
|                     > | ||||
|                         <el-radio-group | ||||
|                             @change="SaveSetting('Language', form.settingInfo.language)" | ||||
|                             @change="onSave(panelFormRef, 'Language', form.settingInfo.language)" | ||||
|                             v-model="form.settingInfo.language" | ||||
|                         > | ||||
|                             <el-radio-button label="zh">中文</el-radio-button> | ||||
|  | @ -83,11 +94,15 @@ | |||
|                             </span> | ||||
|                         </div> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item :label="$t('setting.sessionTimeout')" prop="settingInfo.sessionTimeout"> | ||||
|                     <el-form-item | ||||
|                         :label="$t('setting.sessionTimeout')" | ||||
|                         :rules="Rules.number" | ||||
|                         prop="settingInfo.sessionTimeout" | ||||
|                     > | ||||
|                         <el-input v-model.number="form.settingInfo.sessionTimeout"> | ||||
|                             <template #append> | ||||
|                                 <el-button | ||||
|                                     @click="SaveSetting('SessionTimeout', form.settingInfo.sessionTimeout)" | ||||
|                                     @click="onSave(panelFormRef, 'SessionTimeout', form.settingInfo.sessionTimeout)" | ||||
|                                     icon="Collection" | ||||
|                                 > | ||||
|                                     {{ $t('commons.button.save') }} | ||||
|  | @ -118,9 +133,20 @@ | |||
|             <el-form-item :label="$t('setting.oldPassword')" prop="oldPassword"> | ||||
|                 <el-input type="password" show-password clearable v-model="passForm.oldPassword" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item :label="$t('setting.newPassword')" prop="newPassword"> | ||||
|             <el-form-item | ||||
|                 v-if="form.settingInfo.complexityVerification === 'disable'" | ||||
|                 :label="$t('setting.newPassword')" | ||||
|                 prop="newPassword" | ||||
|             > | ||||
|                 <el-input type="password" show-password clearable v-model="passForm.newPassword" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item | ||||
|                 v-if="form.settingInfo.complexityVerification === 'enable'" | ||||
|                 :label="$t('setting.newPassword')" | ||||
|                 prop="newPasswordComplexity" | ||||
|             > | ||||
|                 <el-input type="password" show-password clearable v-model="passForm.newPasswordComplexity" /> | ||||
|             </el-form-item> | ||||
|             <el-form-item :label="$t('setting.retryPassword')" prop="retryPassword"> | ||||
|                 <el-input type="password" show-password clearable v-model="passForm.retryPassword" /> | ||||
|             </el-form-item> | ||||
|  | @ -137,31 +163,30 @@ | |||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { ref, reactive, computed } from 'vue'; | ||||
| import { ref, reactive } from 'vue'; | ||||
| import { ElMessage, ElForm } from 'element-plus'; | ||||
| import { updateSetting, updatePassword, syncTime } 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 { updatePassword, syncTime } from '@/api/modules/setting'; | ||||
| import router from '@/routers/router'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import i18n from '@/lang'; | ||||
| import { GlobalStore } from '@/store'; | ||||
| 
 | ||||
| const i18n = useI18n(); | ||||
| const globalStore = GlobalStore(); | ||||
| const themeConfig = computed(() => globalStore.themeConfig); | ||||
| const emit = defineEmits<{ (e: 'on-save', formEl: FormInstance | undefined, key: string, val: any): void }>(); | ||||
| 
 | ||||
| type FormInstance = InstanceType<typeof ElForm>; | ||||
| const passFormRef = ref<FormInstance>(); | ||||
| const passRules = reactive({ | ||||
|     oldPassword: [Rules.requiredInput], | ||||
|     newPassword: [Rules.requiredInput], | ||||
|     newPassword: [Rules.requiredInput, { min: 6, message: i18n.global.t('commons.rule.passwordLen'), trigger: 'blur' }], | ||||
|     newPasswordComplexity: [Rules.password], | ||||
|     retryPassword: [Rules.requiredInput, { validator: checkPassword, trigger: 'blur' }], | ||||
| }); | ||||
| const passwordVisiable = ref<boolean>(false); | ||||
| const passForm = reactive<Setting.PasswordUpdate>({ | ||||
| const passForm = reactive({ | ||||
|     oldPassword: '', | ||||
|     newPassword: '', | ||||
|     newPasswordComplexity: '', | ||||
|     retryPassword: '', | ||||
| }); | ||||
| 
 | ||||
|  | @ -173,61 +198,49 @@ const form = withDefaults(defineProps<Props>(), { | |||
|         userName: '', | ||||
|         password: '', | ||||
|         email: '', | ||||
|         sessionTimeout: '', | ||||
|         sessionTimeout: 0, | ||||
|         localTime: '', | ||||
|         panelName: '', | ||||
|         theme: '', | ||||
|         language: '', | ||||
|         complexityVerification: '', | ||||
|     }, | ||||
| }); | ||||
| 
 | ||||
| const { switchDark } = useTheme(); | ||||
| const panelFormRef = ref<FormInstance>(); | ||||
| 
 | ||||
| const SaveSetting = async (key: string, val: string) => { | ||||
|     if (val === '') { | ||||
|         return; | ||||
|     } | ||||
|     switch (key) { | ||||
|         case 'Language': | ||||
|             i18n.locale.value = val; | ||||
|             globalStore.updateLanguage(val); | ||||
|             break; | ||||
|         case 'Theme': | ||||
|             globalStore.setThemeConfig({ ...themeConfig.value, theme: val }); | ||||
|             switchDark(); | ||||
|             break; | ||||
|         case 'PanelName': | ||||
|             globalStore.setThemeConfig({ ...themeConfig.value, panelName: val }); | ||||
|             break; | ||||
|     } | ||||
|     let param = { | ||||
|         key: key, | ||||
|         value: val, | ||||
|     }; | ||||
|     await updateSetting(param); | ||||
|     ElMessage.success(i18n.t('commons.msg.operationSuccess')); | ||||
| }; | ||||
| function onSave(formEl: FormInstance | undefined, key: string, val: any) { | ||||
|     emit('on-save', formEl, key, val); | ||||
| } | ||||
| 
 | ||||
| function checkPassword(rule: any, value: any, callback: any) { | ||||
|     if (passForm.newPassword !== passForm.retryPassword) { | ||||
|         return callback(new Error(i18n.t('commons.rule.rePassword'))); | ||||
|     let password = | ||||
|         form.settingInfo.complexityVerification === 'disable' ? passForm.newPassword : passForm.newPasswordComplexity; | ||||
|     if (password !== passForm.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; | ||||
|         await updatePassword(passForm); | ||||
|         let password = | ||||
|             form.settingInfo.complexityVerification === 'disable' | ||||
|                 ? passForm.newPassword | ||||
|                 : passForm.newPasswordComplexity; | ||||
|         await updatePassword({ oldPassword: passForm.oldPassword, newPassword: password }); | ||||
|         passwordVisiable.value = false; | ||||
|         ElMessage.success(i18n.t('commons.msg.operationSuccess')); | ||||
|         ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); | ||||
|         router.push({ name: 'login', params: { code: '' } }); | ||||
|         globalStore.setLogStatus(false); | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| const onSyncTime = async () => { | ||||
|     const res = await syncTime(); | ||||
|     form.settingInfo.localTime = res.data; | ||||
|     ElMessage.success(i18n.t('commons.msg.operationSuccess')); | ||||
|     ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); | ||||
| }; | ||||
| </script> | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <template> | ||||
|     <div> | ||||
|         <el-form :model="form" label-position="left" label-width="160px"> | ||||
|         <el-form :model="form" ref="panelFormRef" label-position="left" label-width="160px"> | ||||
|             <el-card style="margin-top: 10px"> | ||||
|                 <template #header> | ||||
|                     <div class="card-header"> | ||||
|  | @ -10,11 +10,15 @@ | |||
|                 <el-row> | ||||
|                     <el-col :span="1"><br /></el-col> | ||||
|                     <el-col :span="10"> | ||||
|                         <el-form-item :label="$t('setting.panelPort')"> | ||||
|                         <el-form-item | ||||
|                             :label="$t('setting.panelPort')" | ||||
|                             prop="settingInfo.serverPort" | ||||
|                             :rules="Rules.number" | ||||
|                         > | ||||
|                             <el-input clearable v-model="form.settingInfo.serverPort"> | ||||
|                                 <template #append> | ||||
|                                     <el-button | ||||
|                                         @click="SaveSetting('ServerPort', form.settingInfo.serverPort)" | ||||
|                                         @click="onSave(panelFormRef, 'ServerPort', form.settingInfo.serverPort)" | ||||
|                                         icon="Collection" | ||||
|                                     > | ||||
|                                         {{ $t('commons.button.save') }} | ||||
|  | @ -35,11 +39,17 @@ | |||
|                                 </span> | ||||
|                             </div> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item :label="$t('setting.safeEntrance')"> | ||||
|                         <el-form-item | ||||
|                             :label="$t('setting.safeEntrance')" | ||||
|                             prop="settingInfo.securityEntrance" | ||||
|                             :rules="Rules.requiredInput" | ||||
|                         > | ||||
|                             <el-input clearable v-model="form.settingInfo.securityEntrance"> | ||||
|                                 <template #append> | ||||
|                                     <el-button | ||||
|                                         @click="SaveSetting('SecurityEntrance', form.settingInfo.securityEntrance)" | ||||
|                                         @click=" | ||||
|                                             onSave(panelFormRef, 'SecurityEntrance', form.settingInfo.securityEntrance) | ||||
|                                         " | ||||
|                                         icon="Collection" | ||||
|                                     > | ||||
|                                         {{ $t('commons.button.save') }} | ||||
|  | @ -52,8 +62,12 @@ | |||
|                                 </span> | ||||
|                             </div> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item :label="$t('setting.passwordTimeout')"> | ||||
|                             <el-input clearable v-model="form.settingInfo.passwordTimeOut"> | ||||
|                         <el-form-item | ||||
|                             :label="$t('setting.passwordTimeout')" | ||||
|                             prop="settingInfo.passwordTimeOut" | ||||
|                             :rules="Rules.requiredInput" | ||||
|                         > | ||||
|                             <el-input disabled v-model="form.settingInfo.passwordTimeOut"> | ||||
|                                 <template #append> | ||||
|                                     <el-button @click="timeoutVisiable = true" icon="Collection"> | ||||
|                                         {{ $t('commons.button.set') }} | ||||
|  | @ -66,9 +80,19 @@ | |||
|                                 </span> | ||||
|                             </div> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item :label="$t('setting.complexity')"> | ||||
|                         <el-form-item | ||||
|                             :label="$t('setting.complexity')" | ||||
|                             prop="settingInfo.complexityVerification" | ||||
|                             :rules="Rules.requiredSelect" | ||||
|                         > | ||||
|                             <el-radio-group | ||||
|                                 @change="SaveSetting('ComplexityVerification', form.settingInfo.complexityVerification)" | ||||
|                                 @change=" | ||||
|                                     onSave( | ||||
|                                         panelFormRef, | ||||
|                                         'ComplexityVerification', | ||||
|                                         form.settingInfo.complexityVerification, | ||||
|                                     ) | ||||
|                                 " | ||||
|                                 v-model="form.settingInfo.complexityVerification" | ||||
|                             > | ||||
|                                 <el-radio-button label="enable">{{ $t('commons.button.enable') }}</el-radio-button> | ||||
|  | @ -80,7 +104,11 @@ | |||
|                                 </span> | ||||
|                             </div> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item :label="$t('setting.mfa')"> | ||||
|                         <el-form-item | ||||
|                             :label="$t('setting.mfa')" | ||||
|                             prop="settingInfo.securityEntrance" | ||||
|                             :rules="Rules.requiredSelect" | ||||
|                         > | ||||
|                             <el-radio-group @change="handleMFA()" v-model="form.settingInfo.mfaStatus"> | ||||
|                                 <el-radio-button label="enable">{{ $t('commons.button.enable') }}</el-radio-button> | ||||
|                                 <el-radio-button label="disable">{{ $t('commons.button.disable') }}</el-radio-button> | ||||
|  | @ -143,9 +171,12 @@ import { ElMessage, ElForm } from 'element-plus'; | |||
| import { Setting } from '@/api/interface/setting'; | ||||
| import { updateSetting, getMFA, bindMFA } from '@/api/modules/setting'; | ||||
| import i18n from '@/lang'; | ||||
| import { Rules } from '@/global/form-rues'; | ||||
| import { Rules } from '@/global/form-rules'; | ||||
| import { dateFromat } from '@/utils/util'; | ||||
| 
 | ||||
| // const emit = defineEmits(['on-save']); | ||||
| const emit = defineEmits<{ (e: 'on-save', formEl: FormInstance | undefined, key: string, val: any): void }>(); | ||||
| 
 | ||||
| interface Props { | ||||
|     settingInfo: any; | ||||
| } | ||||
|  | @ -172,15 +203,11 @@ const otp = reactive<Setting.MFAInfo>({ | |||
|     qrImage: '', | ||||
| }); | ||||
| const mfaCode = ref(); | ||||
| const panelFormRef = ref<FormInstance>(); | ||||
| 
 | ||||
| const SaveSetting = async (key: string, val: string) => { | ||||
|     let param = { | ||||
|         key: key, | ||||
|         value: val, | ||||
|     }; | ||||
|     await updateSetting(param); | ||||
|     ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); | ||||
| }; | ||||
| function onSave(formEl: FormInstance | undefined, key: string, val: any) { | ||||
|     emit('on-save', formEl, key, val); | ||||
| } | ||||
| 
 | ||||
| const handleMFA = async () => { | ||||
|     if (form.settingInfo.mfaStatus === 'enable') { | ||||
|  | @ -205,7 +232,7 @@ const submitTimeout = async (formEl: FormInstance | undefined) => { | |||
|     formEl.validate(async (valid) => { | ||||
|         if (!valid) return; | ||||
|         let time = new Date(new Date().getTime() + 3600 * 1000 * 24 * timeoutForm.days); | ||||
|         SaveSetting('PasswordTimeOut', dateFromat(0, 0, time)); | ||||
|         await updateSetting({ key: 'PasswordTimeOut', value: dateFromat(0, 0, time) }); | ||||
|         form.settingInfo.passwordTimeOut = dateFromat(0, 0, time); | ||||
|         timeoutVisiable.value = false; | ||||
|     }); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue