diff --git a/src/apis/system/type.ts b/src/apis/system/type.ts index 674809a..f0a1471 100644 --- a/src/apis/system/type.ts +++ b/src/apis/system/type.ts @@ -287,8 +287,8 @@ export interface BasicConfig { export interface SecurityConfig { PASSWORD_ERROR_LOCK_COUNT: OptionResp PASSWORD_ERROR_LOCK_MINUTES: OptionResp - PASSWORD_EXPIRATION_WARNING_DAYS: OptionResp PASSWORD_EXPIRATION_DAYS: OptionResp + PASSWORD_EXPIRATION_WARNING_DAYS: OptionResp PASSWORD_REUSE_POLICY: OptionResp PASSWORD_MIN_LENGTH: OptionResp PASSWORD_ALLOW_CONTAIN_USERNAME: OptionResp diff --git a/src/layout/components/Asider/index.vue b/src/layout/components/Asider/index.vue index d881cca..cef3d5b 100644 --- a/src/layout/components/Asider/index.vue +++ b/src/layout/components/Asider/index.vue @@ -11,7 +11,7 @@ collapsible breakpoint="xl" hide-trigger - :width="220" + :width="225" :collapsed="appStore.menuCollapse" @collapse="handleCollapse" > diff --git a/src/layout/components/Logo.vue b/src/layout/components/Logo.vue index 52d61b8..98ad20d 100644 --- a/src/layout/components/Logo.vue +++ b/src/layout/components/Logo.vue @@ -57,7 +57,7 @@ const toHome = () => { flex-shrink: 0; } .system-name { - padding-left: 8px; + padding-left: 6px; white-space: nowrap; transition: color 0.3s; &:hover { diff --git a/src/views/system/config/components/BasicSetting.vue b/src/views/system/config/components/BasicSetting.vue index 35ddd28..fd3e17f 100644 --- a/src/views/system/config/components/BasicSetting.vue +++ b/src/views/system/config/components/BasicSetting.vue @@ -172,22 +172,21 @@ const onUpdate = () => { // 取消 const handleCancel = () => { + reset() isUpdate.value = false } -const dataList = ref([]) const queryForm = reactive({ code: ['SITE_TITLE', 'SITE_COPYRIGHT', 'SITE_LOGO', 'SITE_FAVICON'] }) // 查询列表数据 const getDataList = async () => { - const res = await listOption(queryForm) - dataList.value = res.data - siteFavicon.value = dataList.value.find((option) => option.code === 'SITE_FAVICON') - siteLogo.value = dataList.value.find((option) => option.code === 'SITE_LOGO') - siteTitle.value = dataList.value.find((option) => option.code === 'SITE_TITLE') - siteCopyright.value = dataList.value.find((option) => option.code === 'SITE_COPYRIGHT') - reset() + const { data } = await listOption(queryForm) + siteFavicon.value = data.find((option) => option.code === 'SITE_FAVICON') + siteLogo.value = data.find((option) => option.code === 'SITE_LOGO') + siteTitle.value = data.find((option) => option.code === 'SITE_TITLE') + siteCopyright.value = data.find((option) => option.code === 'SITE_COPYRIGHT') + handleCancel() } const appStore = useAppStore() @@ -204,7 +203,7 @@ const handleSave = async () => { }) ) appStore.setSiteConfig(form) - handleCancel() + await getDataList() Message.success('保存成功') } diff --git a/src/views/system/config/components/SecuritySetting.vue b/src/views/system/config/components/SecuritySetting.vue index c47372f..4ab927d 100644 --- a/src/views/system/config/components/SecuritySetting.vue +++ b/src/views/system/config/components/SecuritySetting.vue @@ -2,84 +2,92 @@ - + - + - - - - - - - - + - + + + + + + + + - + - + @@ -87,10 +95,10 @@ - + @@ -138,31 +146,61 @@ import { useWindowSize } from '@vueuse/core' import { type FormInstance, Message, Modal } from '@arco-design/web-vue' import { type OptionResp, type SecurityConfig, listOption, resetOptionValue, updateOption } from '@/apis' +import { useForm } from '@/hooks' const { width } = useWindowSize() const formRef = ref() -const form = ref({ +const { form } = useForm({ + PASSWORD_ERROR_LOCK_COUNT: 0, + PASSWORD_ERROR_LOCK_MINUTES: 0, + PASSWORD_EXPIRATION_DAYS: 0, + PASSWORD_EXPIRATION_WARNING_DAYS: 0, + PASSWORD_REUSE_POLICY: 0, + PASSWORD_MIN_LENGTH: 0, + PASSWORD_ALLOW_CONTAIN_USERNAME: 0, + PASSWORD_CONTAIN_SPECIAL_CHARACTERS: 0 +}) +const rules: FormInstance['rules'] = { + PASSWORD_ERROR_LOCK_COUNT: [{ required: true, message: '请输入值' }], + PASSWORD_ERROR_LOCK_MINUTES: [{ required: true, message: '请输入值' }], + PASSWORD_EXPIRATION_DAYS: [{ required: true, message: '请输入值' }], + PASSWORD_EXPIRATION_WARNING_DAYS: [ + { required: true, message: '请输入值' }, + { + validator: (value, callback) => { + if (form.PASSWORD_EXPIRATION_DAYS > 0 && value >= form.PASSWORD_EXPIRATION_DAYS) { + callback('密码到期前的提示时间应小于密码有效期') + } else { + callback() + } + } + } + ], + PASSWORD_REUSE_POLICY: [{ required: true, message: '请输入值' }], + PASSWORD_MIN_LENGTH: [{ required: true, message: '请输入值' }] +} + +const securityConfig = ref({ PASSWORD_ERROR_LOCK_COUNT: {}, PASSWORD_ERROR_LOCK_MINUTES: {}, - PASSWORD_EXPIRATION_WARNING_DAYS: {}, PASSWORD_EXPIRATION_DAYS: {}, + PASSWORD_EXPIRATION_WARNING_DAYS: {}, PASSWORD_REUSE_POLICY: {}, PASSWORD_MIN_LENGTH: {}, PASSWORD_ALLOW_CONTAIN_USERNAME: {}, PASSWORD_CONTAIN_SPECIAL_CHARACTERS: {} }) - -const queryForm = { - code: Object.keys(form.value) -} -// 查询列表数据 -const getDataList = async () => { - const { data } = await listOption(queryForm) - form.value = data.reduce((obj: SecurityConfig, option: OptionResp) => { - obj[option.code] = { ...option, value: Number.parseInt(option.value) } - return obj - }, {}) +// 重置 +const reset = () => { + form.PASSWORD_ERROR_LOCK_COUNT = securityConfig.value.PASSWORD_ERROR_LOCK_COUNT.value || 0 + form.PASSWORD_ERROR_LOCK_MINUTES = securityConfig.value.PASSWORD_ERROR_LOCK_MINUTES.value || 0 + form.PASSWORD_EXPIRATION_DAYS = securityConfig.value.PASSWORD_EXPIRATION_DAYS.value || 0 + form.PASSWORD_EXPIRATION_WARNING_DAYS = securityConfig.value.PASSWORD_EXPIRATION_WARNING_DAYS.value || 0 + form.PASSWORD_REUSE_POLICY = securityConfig.value.PASSWORD_REUSE_POLICY.value || 0 + form.PASSWORD_MIN_LENGTH = securityConfig.value.PASSWORD_MIN_LENGTH.value || 0 + form.PASSWORD_ALLOW_CONTAIN_USERNAME = securityConfig.value.PASSWORD_ALLOW_CONTAIN_USERNAME.value || 0 + form.PASSWORD_CONTAIN_SPECIAL_CHARACTERS = securityConfig.value.PASSWORD_CONTAIN_SPECIAL_CHARACTERS.value || 0 } const isUpdate = ref(false) @@ -171,25 +209,35 @@ const onUpdate = () => { isUpdate.value = true } -// 重置 -const reset = () => { - getDataList() -} - // 取消 const handleCancel = () => { reset() isUpdate.value = false } +const queryForm = { + code: Object.keys(securityConfig.value) +} +// 查询列表数据 +const getDataList = async () => { + const { data } = await listOption(queryForm) + securityConfig.value = data.reduce((obj: SecurityConfig, option: OptionResp) => { + obj[option.code] = { ...option, value: Number.parseInt(option.value) } + return obj + }, {}) + handleCancel() +} + // 保存 const handleSave = async () => { + const isInvalid = await formRef.value?.validate() + if (isInvalid) return false await updateOption( - Object.entries(form.value).map(([key, value]) => { - return { code: key, value: value.value } + Object.entries(form).map(([key, value]) => { + return { code: key, value } }) ) - handleCancel() + await getDataList() Message.success('保存成功') }