mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 10:57:10 +08:00 
			
		
		
		
	refactor: 优化密码策略处理
This commit is contained in:
		| @@ -276,21 +276,23 @@ export interface OptionQuery { | ||||
| } | ||||
|  | ||||
| /** 基础配置类型 */ | ||||
| export interface BasicConfigResp { | ||||
|   site_favicon: string | ||||
|   site_logo: string | ||||
|   site_title: string | ||||
|   site_copyright: string | ||||
| export interface BasicConfig { | ||||
|   SITE_FAVICON: string | ||||
|   SITE_LOGO: string | ||||
|   SITE_TITLE: string | ||||
|   SITE_COPYRIGHT: string | ||||
| } | ||||
|  | ||||
| /** 安全配置类型 */ | ||||
| export interface SecurityConfigResp { | ||||
|   password_contain_name: OptionResp | ||||
|   password_error_count: OptionResp | ||||
|   password_lock_minutes: OptionResp | ||||
|   password_min_length: OptionResp | ||||
|   password_special_char: OptionResp | ||||
|   password_update_interval: OptionResp | ||||
| export interface SecurityConfig { | ||||
|   PASSWORD_ERROR_LOCK_COUNT: OptionResp | ||||
|   PASSWORD_ERROR_LOCK_MINUTES: OptionResp | ||||
|   PASSWORD_EXPIRATION_WARNING_DAYS: OptionResp | ||||
|   PASSWORD_EXPIRATION_DAYS: OptionResp | ||||
|   PASSWORD_REUSE_POLICY: OptionResp | ||||
|   PASSWORD_MIN_LENGTH: OptionResp | ||||
|   PASSWORD_ALLOW_CONTAIN_USERNAME: OptionResp | ||||
|   PASSWORD_CONTAIN_SPECIAL_CHARACTERS: OptionResp | ||||
| } | ||||
|  | ||||
| /** 绑定三方账号信息 */ | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { defineStore } from 'pinia' | ||||
| import { computed, reactive, toRefs } from 'vue' | ||||
| import { generate, getRgbStr } from '@arco-design/color' | ||||
| import { type BasicConfigResp, listOptionDict } from '@/apis' | ||||
| import { type BasicConfig, listOptionDict } from '@/apis' | ||||
| import defaultSettings from '@/config/setting.json' | ||||
|  | ||||
| const storeSetup = () => { | ||||
| @@ -55,48 +55,48 @@ const storeSetup = () => { | ||||
|   } | ||||
|  | ||||
|   // 系统配置配置 | ||||
|   const siteConfig = reactive({}) as BasicConfigResp | ||||
|   const siteConfig = reactive({}) as BasicConfig | ||||
|   // 初始化系统配置 | ||||
|   const initSiteConfig = () => { | ||||
|     listOptionDict({ | ||||
|       code: ['site_favicon', 'site_logo', 'site_title', 'site_copyright'] | ||||
|       code: ['SITE_FAVICON', 'SITE_LOGO', 'SITE_TITLE', 'SITE_COPYRIGHT'] | ||||
|     }).then((res) => { | ||||
|       const resMap = new Map() | ||||
|       res.data.forEach((item) => { | ||||
|         resMap.set(item.label, item.value) | ||||
|       }) | ||||
|       siteConfig.site_logo = resMap.get('site_logo') | ||||
|       siteConfig.site_favicon = resMap.get('site_favicon') | ||||
|       siteConfig.site_title = resMap.get('site_title') | ||||
|       siteConfig.site_copyright = resMap.get('site_copyright') | ||||
|       document.title = resMap.get('site_title') | ||||
|       siteConfig.SITE_FAVICON = resMap.get('SITE_FAVICON') | ||||
|       siteConfig.SITE_LOGO = resMap.get('SITE_LOGO') | ||||
|       siteConfig.SITE_TITLE = resMap.get('SITE_TITLE') | ||||
|       siteConfig.SITE_COPYRIGHT = resMap.get('SITE_COPYRIGHT') | ||||
|       document.title = resMap.get('SITE_TITLE') | ||||
|       document | ||||
|         .querySelector('link[rel="shortcut icon"]') | ||||
|         ?.setAttribute('href', resMap.get('site_favicon') || '/favicon.ico') | ||||
|         ?.setAttribute('href', resMap.get('SITE_FAVICON') || '/favicon.ico') | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   // 设置系统配置 | ||||
|   const setSiteConfig = (config: BasicConfigResp) => { | ||||
|   const setSiteConfig = (config: BasicConfig) => { | ||||
|     Object.assign(siteConfig, config) | ||||
|     document.title = config.site_title || '' | ||||
|     document.querySelector('link[rel="shortcut icon"]')?.setAttribute('href', config.site_favicon || '/favicon.ico') | ||||
|     document.title = config.SITE_TITLE || '' | ||||
|     document.querySelector('link[rel="shortcut icon"]')?.setAttribute('href', config.SITE_FAVICON || '/favicon.ico') | ||||
|   } | ||||
|  | ||||
|   const getFavicon = () => { | ||||
|     return siteConfig.site_favicon | ||||
|     return siteConfig.SITE_FAVICON | ||||
|   } | ||||
|  | ||||
|   const getLogo = () => { | ||||
|     return siteConfig.site_logo | ||||
|     return siteConfig.SITE_LOGO | ||||
|   } | ||||
|  | ||||
|   const getTitle = () => { | ||||
|     return siteConfig.site_title | ||||
|     return siteConfig.SITE_TITLE | ||||
|   } | ||||
|  | ||||
|   const getCopyright = () => { | ||||
|     return siteConfig.site_copyright | ||||
|     return siteConfig.SITE_COPYRIGHT | ||||
|   } | ||||
|  | ||||
|   return { | ||||
|   | ||||
| @@ -56,7 +56,7 @@ | ||||
|     <div class="footer">注册于 {{ userInfo.registrationDate }}</div> | ||||
|   </a-card> | ||||
|  | ||||
|   <a-modal v-model:visible="visible" title="上传头像" :width="400" :footer="false" @close="reset"> | ||||
|   <a-modal v-model:visible="visible" title="上传头像" :width="width >= 400 ? 400 : '100%'" :footer="false" @close="reset"> | ||||
|     <a-row> | ||||
|       <a-col :span="14" style="width: 200px; height: 200px"> | ||||
|         <VueCropper | ||||
| @@ -95,6 +95,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { useWindowSize } from '@vueuse/core' | ||||
| import { type FileItem, Message } from '@arco-design/web-vue' | ||||
| import { VueCropper } from 'vue-cropper' | ||||
| import BasicInfoUpdateModal from './BasicInfoUpdateModal.vue' | ||||
| @@ -103,6 +104,7 @@ import 'vue-cropper/dist/index.css' | ||||
| import { useUserStore } from '@/stores' | ||||
| import getAvatar from '@/utils/avatar' | ||||
|  | ||||
| const { width } = useWindowSize() | ||||
| const userStore = useUserStore() | ||||
| const userInfo = computed(() => userStore.userInfo) | ||||
|  | ||||
|   | ||||
| @@ -37,7 +37,7 @@ | ||||
| <script lang="ts" setup> | ||||
| import type { ModeItem } from '../type' | ||||
| import VerifyModel from '../components/VerifyModel.vue' | ||||
| import { type OptionResp, type SecurityConfigResp, listOption } from '@/apis' | ||||
| import { type OptionResp, type SecurityConfig, listOption } from '@/apis' | ||||
| import { useUserStore } from '@/stores' | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| @@ -82,20 +82,21 @@ const onUpdate = (type: string) => { | ||||
|   verifyModelRef.value?.open(type) | ||||
| } | ||||
|  | ||||
| const securityConfig = ref<SecurityConfigResp>({ | ||||
|   password_contain_name: {}, | ||||
|   password_error_count: {}, | ||||
|   password_expiration_days: {}, | ||||
|   password_lock_minutes: {}, | ||||
|   password_min_length: {}, | ||||
|   password_special_char: {}, | ||||
|   password_update_interval: {} | ||||
| const securityConfig = ref<SecurityConfig>({ | ||||
|   PASSWORD_ERROR_LOCK_COUNT: {}, | ||||
|   PASSWORD_ERROR_LOCK_MINUTES: {}, | ||||
|   PASSWORD_EXPIRATION_WARNING_DAYS: {}, | ||||
|   PASSWORD_EXPIRATION_DAYS: {}, | ||||
|   PASSWORD_REUSE_POLICY: {}, | ||||
|   PASSWORD_MIN_LENGTH: {}, | ||||
|   PASSWORD_ALLOW_CONTAIN_USERNAME: {}, | ||||
|   PASSWORD_CONTAIN_SPECIAL_CHARACTERS: {} | ||||
| }) | ||||
|  | ||||
| // 查询列表数据 | ||||
| const getDataList = async () => { | ||||
|   const { data } = await listOption({ code: Object.keys(securityConfig.value) }) | ||||
|   securityConfig.value = data.reduce((obj: SecurityConfigResp, option: OptionResp) => { | ||||
|   securityConfig.value = data.reduce((obj: SecurityConfig, option: OptionResp) => { | ||||
|     obj[option.code] = { ...option, value: Number.parseInt(option.value) } | ||||
|     return obj | ||||
|   }, {}) | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   <a-form ref="formRef" :model="form" :rules="rules" size="large" layout="vertical" :disabled="!isUpdate"> | ||||
|     <a-list class="list-layout" :bordered="false"> | ||||
|       <a-list-item> | ||||
|         <a-form-item class="image-item" hide-label field="site_favicon"> | ||||
|         <a-form-item class="image-item" hide-label field="SITE_FAVICON"> | ||||
|           {{ siteFavicon?.name }} | ||||
|           <template #extra> | ||||
|             {{ siteFavicon?.description }} | ||||
| @@ -41,7 +41,7 @@ | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item class="image-item" hide-label field="site_logo"> | ||||
|         <a-form-item class="image-item" hide-label field="SITE_LOGO"> | ||||
|           {{ siteLogo?.name }} | ||||
|           <template #extra> | ||||
|             {{ siteLogo?.description }} | ||||
| @@ -77,12 +77,12 @@ | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="padding-top: 13px; border: none"> | ||||
|         <a-form-item class="input-item" :label="siteTitle?.name" field="site_title"> | ||||
|           <a-input v-model.trim="form.site_title" placeholder="请输入网站标题" :max-length="18" /> | ||||
|         <a-form-item class="input-item" :label="siteTitle?.name" field="SITE_TITLE"> | ||||
|           <a-input v-model.trim="form.SITE_TITLE" placeholder="请输入网站标题" :max-length="18" /> | ||||
|         </a-form-item> | ||||
|         <a-form-item class="input-item" :label="siteCopyright?.name" field="site_copyright" tooltip="支持HTML标签"> | ||||
|         <a-form-item class="input-item" :label="siteCopyright?.name" field="SITE_COPYRIGHT" tooltip="支持HTML标签"> | ||||
|           <a-textarea | ||||
|             v-model.trim="form.site_copyright" | ||||
|             v-model.trim="form.SITE_COPYRIGHT" | ||||
|             placeholder="请输入版权信息" | ||||
|             :auto-size="{ | ||||
|               minRows: 3, | ||||
| @@ -137,15 +137,15 @@ import { useForm } from '@/hooks' | ||||
|  | ||||
| const formRef = ref<FormInstance>() | ||||
| const rules: FormInstance['rules'] = { | ||||
|   site_title: [{ required: true, message: '请输入系统标题' }], | ||||
|   site_copyright: [{ required: true, message: '请输入版权信息' }] | ||||
|   SITE_TITLE: [{ required: true, message: '请输入系统标题' }], | ||||
|   SITE_COPYRIGHT: [{ required: true, message: '请输入版权信息' }] | ||||
| } | ||||
|  | ||||
| const { form } = useForm({ | ||||
|   site_favicon: '', | ||||
|   site_logo: '', | ||||
|   site_title: '', | ||||
|   site_copyright: '' | ||||
|   SITE_FAVICON: '', | ||||
|   SITE_LOGO: '', | ||||
|   SITE_TITLE: '', | ||||
|   SITE_COPYRIGHT: '' | ||||
| }) | ||||
|  | ||||
| const siteFavicon = ref<OptionResp>() | ||||
| @@ -156,10 +156,10 @@ const faviconFile = ref<FileItem>({ uid: '-1' }) | ||||
| const logoFile = ref<FileItem>({ uid: '-2' }) | ||||
| // 重置 | ||||
| const reset = () => { | ||||
|   form.site_favicon = siteFavicon.value?.value || '' | ||||
|   form.site_logo = siteLogo.value?.value || '' | ||||
|   form.site_title = siteTitle.value?.value || '' | ||||
|   form.site_copyright = siteCopyright.value?.value || '' | ||||
|   form.SITE_FAVICON = siteFavicon.value?.value || '' | ||||
|   form.SITE_LOGO = siteLogo.value?.value || '' | ||||
|   form.SITE_TITLE = siteTitle.value?.value || '' | ||||
|   form.SITE_COPYRIGHT = siteCopyright.value?.value || '' | ||||
|   faviconFile.value.url = siteFavicon.value?.value | ||||
|   logoFile.value.url = siteLogo.value?.value | ||||
| } | ||||
| @@ -177,16 +177,16 @@ const handleCancel = () => { | ||||
|  | ||||
| const dataList = ref<OptionResp[]>([]) | ||||
| const queryForm = reactive({ | ||||
|   code: ['site_title', 'site_copyright', 'site_logo', 'site_favicon'] | ||||
|   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') | ||||
|   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() | ||||
| } | ||||
|  | ||||
| @@ -236,7 +236,7 @@ const handleUploadFavicon = (options: RequestOption) => { | ||||
|     uploadFile(formData) | ||||
|       .then((res) => { | ||||
|         onSuccess(res) | ||||
|         form.site_favicon = res.data.url | ||||
|         form.SITE_FAVICON = res.data.url | ||||
|         Message.success('上传成功') | ||||
|       }) | ||||
|       .catch((error) => { | ||||
| @@ -266,7 +266,7 @@ const handleUploadLogo = (options: RequestOption) => { | ||||
|     uploadFile(formData) | ||||
|       .then((res) => { | ||||
|         onSuccess(res) | ||||
|         form.site_logo = res.data.url | ||||
|         form.SITE_LOGO = res.data.url | ||||
|         Message.success('上传成功') | ||||
|       }) | ||||
|       .catch((error) => { | ||||
|   | ||||
							
								
								
									
										9
									
								
								src/views/system/config/components/MailSetting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/views/system/config/components/MailSetting.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <template> | ||||
|   <div>暂未开放</div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| </style> | ||||
| @@ -1,52 +1,102 @@ | ||||
| <template> | ||||
|   <a-form ref="formRef" style="margin-top: 20px" :model="form" size="small" label-align="left" :disabled="!isUpdate"> | ||||
|     <a-list size="small" :bordered="false"> | ||||
|       <a-list-item style="border: none"> | ||||
|         <a-form-item | ||||
|           :help="form.password_expiration_days.description" | ||||
|           :label="form.password_expiration_days.name" | ||||
|           field="password_expiration_days" | ||||
|   <a-form | ||||
|     ref="formRef" | ||||
|     :model="form" | ||||
|     size="small" | ||||
|     :auto-label-width="true" | ||||
|     label-align="left" | ||||
|     :layout="width >= 500 ? 'horizontal' : 'vertical'" | ||||
|     :disabled="!isUpdate" | ||||
|     style="margin-top: 10px" | ||||
|   > | ||||
|           <a-input-number v-model="form.password_expiration_days.value" class="input-width" :min="0" :max="999"> | ||||
|     <a-list size="small" :bordered="false"> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_ERROR_LOCK_COUNT.name" | ||||
|           field="PASSWORD_ERROR_LOCK_COUNT" | ||||
|           :help="form.PASSWORD_ERROR_LOCK_COUNT.description" | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_ERROR_LOCK_COUNT.value" class="input-width" :min="0" :max="10"> | ||||
|             <template #append>次</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|      <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_ERROR_LOCK_MINUTES.name" | ||||
|           field="PASSWORD_ERROR_LOCK_MINUTES" | ||||
|           :help="form.PASSWORD_ERROR_LOCK_MINUTES.description" | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_ERROR_LOCK_MINUTES.value" class="input-width" :min="1" :max="1440"> | ||||
|             <template #append>分钟</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_EXPIRATION_WARNING_DAYS.name" | ||||
|           field="PASSWORD_EXPIRATION_WARNING_DAYS" | ||||
|           :help="form.PASSWORD_EXPIRATION_WARNING_DAYS.description" | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_EXPIRATION_WARNING_DAYS.value" class="input-width" :min="0"> | ||||
|             <template #append>天</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="border: none"> | ||||
|         <a-form-item :help="form.password_min_length.description" :label="form.password_min_length.name"> | ||||
|           <a-input-number v-model="form.password_min_length.value" class="input-width" :min="8" :max="32" /> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="border: none"> | ||||
|         <a-form-item :help="form.password_update_interval.description" :label="form.password_update_interval.name"> | ||||
|           <a-input-number v-model="form.password_update_interval.value" class="input-width" :min="0" :max="9999"> | ||||
|             <template #append>分钟</template> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_EXPIRATION_DAYS.name" | ||||
|           field="PASSWORD_EXPIRATION_DAYS" | ||||
|           :help="form.PASSWORD_EXPIRATION_DAYS.description" | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_EXPIRATION_DAYS.value" class="input-width" :min="0" :max="999"> | ||||
|             <template #append>天</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="border: none"> | ||||
|         <a-form-item :help="form.password_error_count.description" :label="form.password_error_count.name"> | ||||
|           <a-input-number v-model="form.password_error_count.value" class="input-width" :min="0" :max="9999" /> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="border: none"> | ||||
|         <a-form-item :help="form.password_lock_minutes.description" :label="form.password_lock_minutes.name"> | ||||
|           <a-input-number v-model="form.password_lock_minutes.value" class="input-width" :min="0" :max="9999"> | ||||
|             <template #append>分钟</template> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_REUSE_POLICY.name" | ||||
|           field="PASSWORD_REUSE_POLICY" | ||||
|           :help="form.PASSWORD_REUSE_POLICY.description" | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_REUSE_POLICY.value" class="input-width" :min="3" :max="32"> | ||||
|             <template #append>次</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="border: none"> | ||||
|         <a-form-item :help="form.password_special_char.description" :label="form.password_special_char.name"> | ||||
|           <a-switch v-model="form.password_special_char.value" type="round" :checked-value="1" :unchecked-value="0" /> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_MIN_LENGTH.name" | ||||
|           field="PASSWORD_MIN_LENGTH" | ||||
|           :help="form.PASSWORD_MIN_LENGTH.description" | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_MIN_LENGTH.value" class="input-width" :min="8" :max="32" /> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="border: none"> | ||||
|         <a-form-item :help="form.password_contain_name.description" :label="form.password_contain_name.name"> | ||||
|           <a-switch v-model="form.password_contain_name.value" type="round" :checked-value="1" :unchecked-value="0" /> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_ALLOW_CONTAIN_USERNAME.name" | ||||
|           field="PASSWORD_ALLOW_CONTAIN_USERNAME" | ||||
|         > | ||||
|           <a-switch v-model="form.PASSWORD_ALLOW_CONTAIN_USERNAME.value" type="round" :checked-value="1" :unchecked-value="0"> | ||||
|             <template #checked>是</template> | ||||
|             <template #unchecked>否</template> | ||||
|           </a-switch> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item style="padding-top: 13px; border: none"> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="form.PASSWORD_CONTAIN_SPECIAL_CHARACTERS.name" | ||||
|           field="PASSWORD_CONTAIN_SPECIAL_CHARACTERS" | ||||
|         > | ||||
|           <a-switch v-model="form.PASSWORD_CONTAIN_SPECIAL_CHARACTERS.value" type="round" :checked-value="1" :unchecked-value="0"> | ||||
|             <template #checked>是</template> | ||||
|             <template #unchecked>否</template> | ||||
|           </a-switch> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-space> | ||||
|           <a-button v-if="!isUpdate" v-permission="['system:config:reset']" @click="onResetValue"> | ||||
|             <template #icon> | ||||
| @@ -85,39 +135,42 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { useWindowSize } from '@vueuse/core' | ||||
| import { type FormInstance, Message, Modal } from '@arco-design/web-vue' | ||||
| import { type OptionResp, type SecurityConfigResp, listOption, resetOptionValue, updateOption } from '@/apis' | ||||
| import { type OptionResp, type SecurityConfig, listOption, resetOptionValue, updateOption } from '@/apis' | ||||
|  | ||||
| const { width } = useWindowSize() | ||||
|  | ||||
| const formRef = ref<FormInstance>() | ||||
|  | ||||
| const form = ref<SecurityConfigResp>({ | ||||
|   password_contain_name: {}, | ||||
|   password_error_count: {}, | ||||
|   password_expiration_days: {}, | ||||
|   password_lock_minutes: {}, | ||||
|   password_min_length: {}, | ||||
|   password_special_char: {}, | ||||
|   password_update_interval: {} | ||||
| const form = ref<SecurityConfig>({ | ||||
|   PASSWORD_ERROR_LOCK_COUNT: {}, | ||||
|   PASSWORD_ERROR_LOCK_MINUTES: {}, | ||||
|   PASSWORD_EXPIRATION_WARNING_DAYS: {}, | ||||
|   PASSWORD_EXPIRATION_DAYS: {}, | ||||
|   PASSWORD_REUSE_POLICY: {}, | ||||
|   PASSWORD_MIN_LENGTH: {}, | ||||
|   PASSWORD_ALLOW_CONTAIN_USERNAME: {}, | ||||
|   PASSWORD_CONTAIN_SPECIAL_CHARACTERS: {} | ||||
| }) | ||||
|  | ||||
| const isUpdate = ref(false) | ||||
| // 修改 | ||||
| const onUpdate = () => { | ||||
|   isUpdate.value = true | ||||
| } | ||||
|  | ||||
| const queryForm = { | ||||
|   code: Object.keys(form.value) | ||||
| } | ||||
| // 查询列表数据 | ||||
| const getDataList = async () => { | ||||
|   const { data } = await listOption(queryForm) | ||||
|   form.value = data.reduce((obj: SecurityConfigResp, option: OptionResp) => { | ||||
|   form.value = data.reduce((obj: SecurityConfig, option: OptionResp) => { | ||||
|     obj[option.code] = { ...option, value: Number.parseInt(option.value) } | ||||
|     return obj | ||||
|   }, {}) | ||||
| } | ||||
|  | ||||
| const isUpdate = ref(false) | ||||
| // 修改 | ||||
| const onUpdate = () => { | ||||
|   isUpdate.value = true | ||||
| } | ||||
|  | ||||
| // 重置 | ||||
| const reset = () => { | ||||
|   getDataList() | ||||
| @@ -155,12 +208,17 @@ const onResetValue = () => { | ||||
|     onOk: handleResetValue | ||||
|   }) | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
|   getDataList() | ||||
| }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| :deep(.arco-list-item:not(:last-child)) { | ||||
|   border-bottom: none; | ||||
| } | ||||
|  | ||||
| .input-width { | ||||
|   width: 130px; | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,9 @@ | ||||
|         <a-tab-pane key="1" title="基础配置"> | ||||
|           <BasicSetting /> | ||||
|         </a-tab-pane> | ||||
|         <a-tab-pane key="2" title="邮件配置(暂未开放)" disabled></a-tab-pane> | ||||
|         <a-tab-pane key="2" title="邮件配置"> | ||||
|           <MailSetting /> | ||||
|         </a-tab-pane> | ||||
|         <a-tab-pane key="3" title="安全配置"> | ||||
|           <SecuritySetting /> | ||||
|         </a-tab-pane> | ||||
| @@ -16,6 +18,7 @@ | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import BasicSetting from './components/BasicSetting.vue' | ||||
| import MailSetting from './components/MailSetting.vue' | ||||
| import SecuritySetting from './components/SecuritySetting.vue' | ||||
|  | ||||
| defineOptions({ name: 'SystemConfig' }) | ||||
| @@ -25,4 +28,8 @@ defineOptions({ name: 'SystemConfig' }) | ||||
| :deep(.arco-tabs-content) { | ||||
|   padding-top: 5px; | ||||
| } | ||||
|  | ||||
| :deep(.arco-tabs-tab) { | ||||
|   background-color: var(--color-fill-2); | ||||
| } | ||||
| </style> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user