mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 00:57:11 +08:00 
			
		
		
		
	chore:优化系统配置加载与切换问题
This commit is contained in:
		| @@ -7,7 +7,7 @@ | ||||
|         </slot> | ||||
|       </a-space> | ||||
|     </a-row> | ||||
|     <a-tabs type="card-gutter" size="large" :active-key="activeKey" @change="change"> | ||||
|     <a-tabs v-model:active-key="activeKey" type="card-gutter" size="large" @change="change"> | ||||
|       <a-tab-pane key="1" title="登录日志" /> | ||||
|       <a-tab-pane key="2" title="操作日志" /> | ||||
|     </a-tabs> | ||||
|   | ||||
| @@ -7,23 +7,13 @@ | ||||
|           <template #extra> | ||||
|             {{ siteFavicon?.description }} | ||||
|             <br /> | ||||
|             <a-upload | ||||
|               :file-list="faviconFile ? [faviconFile] : []" | ||||
|               accept="image/*" | ||||
|               :show-file-list="false" | ||||
|               :custom-request="handleUploadFavicon" | ||||
|               @change="handleChangeFavicon" | ||||
|             > | ||||
|             <a-upload :file-list="faviconFile ? [faviconFile] : []" accept="image/*" :show-file-list="false" | ||||
|               :custom-request="handleUploadFavicon" @change="handleChangeFavicon"> | ||||
|               <template #upload-button> | ||||
|                 <div | ||||
|                   :class="`arco-upload-list-item${ | ||||
|                     faviconFile && faviconFile.status === 'error' ? ' arco-upload-list-item-error' : '' | ||||
|                   }`" | ||||
|                 > | ||||
|                   <div | ||||
|                     v-if="faviconFile && faviconFile.url" | ||||
|                     class="arco-upload-list-picture custom-upload-avatar favicon" | ||||
|                   > | ||||
|                 <div :class="`arco-upload-list-item${faviconFile && faviconFile.status === 'error' ? ' arco-upload-list-item-error' : '' | ||||
|                   }`"> | ||||
|                   <div v-if="faviconFile && faviconFile.url" | ||||
|                     class="arco-upload-list-picture custom-upload-avatar favicon"> | ||||
|                     <img :src="faviconFile.url" alt="favicon" /> | ||||
|                     <div v-if="isUpdate" class="arco-upload-list-picture-mask favicon"> | ||||
|                       <IconEdit /> | ||||
| @@ -46,19 +36,11 @@ | ||||
|           <template #extra> | ||||
|             {{ siteLogo?.description }} | ||||
|             <br /> | ||||
|             <a-upload | ||||
|               :file-list="logoFile ? [logoFile] : []" | ||||
|               accept="image/*" | ||||
|               :show-file-list="false" | ||||
|               :custom-request="handleUploadLogo" | ||||
|               @change="handleChangeLogo" | ||||
|             > | ||||
|             <a-upload :file-list="logoFile ? [logoFile] : []" accept="image/*" :show-file-list="false" | ||||
|               :custom-request="handleUploadLogo" @change="handleChangeLogo"> | ||||
|               <template #upload-button> | ||||
|                 <div | ||||
|                   :class="`arco-upload-list-item${ | ||||
|                     logoFile && logoFile.status === 'error' ? ' arco-upload-list-item-error' : '' | ||||
|                   }`" | ||||
|                 > | ||||
|                 <div :class="`arco-upload-list-item${logoFile && logoFile.status === 'error' ? ' arco-upload-list-item-error' : '' | ||||
|                   }`"> | ||||
|                   <div v-if="logoFile && logoFile.url" class="arco-upload-list-picture custom-upload-avatar logo"> | ||||
|                     <img :src="logoFile.url" alt="Logo" /> | ||||
|                     <div v-if="isUpdate" class="arco-upload-list-picture-mask logo"> | ||||
| @@ -81,14 +63,9 @@ | ||||
|           <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-textarea | ||||
|             v-model.trim="form.SITE_COPYRIGHT" | ||||
|             placeholder="请输入版权信息" | ||||
|             :auto-size="{ | ||||
|               minRows: 3, | ||||
|             }" | ||||
|             show-word-limit | ||||
|           /> | ||||
|           <a-textarea v-model.trim="form.SITE_COPYRIGHT" placeholder="请输入版权信息" :auto-size="{ | ||||
|             minRows: 3, | ||||
|           }" show-word-limit /> | ||||
|         </a-form-item> | ||||
|         <div style="margin-top: 20px"> | ||||
|           <a-space> | ||||
| @@ -135,6 +112,7 @@ import { type OptionResp, listOption, resetOptionValue, updateOption, uploadFile | ||||
| import { useAppStore } from '@/stores' | ||||
| import { useForm } from '@/hooks' | ||||
|  | ||||
| defineOptions({ name: 'BasicSetting' }) | ||||
| const formRef = ref<FormInstance>() | ||||
| const rules: FormInstance['rules'] = { | ||||
|   SITE_TITLE: [{ required: true, message: '请输入系统标题' }], | ||||
| @@ -227,21 +205,21 @@ const onResetValue = () => { | ||||
| // 上传 favicon | ||||
| const handleUploadFavicon = (options: RequestOption) => { | ||||
|   const controller = new AbortController() | ||||
|   ;(async function requestWrap() { | ||||
|     const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options | ||||
|     onProgress(20) | ||||
|     const formData = new FormData() | ||||
|     formData.append(name as string, fileItem.file as Blob) | ||||
|     uploadFile(formData) | ||||
|       .then((res) => { | ||||
|         onSuccess(res) | ||||
|         form.SITE_FAVICON = res.data.url | ||||
|         Message.success('上传成功') | ||||
|       }) | ||||
|       .catch((error) => { | ||||
|         onError(error) | ||||
|       }) | ||||
|   })() | ||||
|     ; (async function requestWrap() { | ||||
|       const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options | ||||
|       onProgress(20) | ||||
|       const formData = new FormData() | ||||
|       formData.append(name as string, fileItem.file as Blob) | ||||
|       uploadFile(formData) | ||||
|         .then((res) => { | ||||
|           onSuccess(res) | ||||
|           form.SITE_FAVICON = res.data.url | ||||
|           Message.success('上传成功') | ||||
|         }) | ||||
|         .catch((error) => { | ||||
|           onError(error) | ||||
|         }) | ||||
|     })() | ||||
|   return { | ||||
|     abort() { | ||||
|       controller.abort() | ||||
| @@ -257,21 +235,21 @@ const handleChangeFavicon = (_: any, currentFile: any) => { | ||||
| // 上传 Logo | ||||
| const handleUploadLogo = (options: RequestOption) => { | ||||
|   const controller = new AbortController() | ||||
|   ;(async function requestWrap() { | ||||
|     const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options | ||||
|     onProgress(20) | ||||
|     const formData = new FormData() | ||||
|     formData.append(name as string, fileItem.file as Blob) | ||||
|     uploadFile(formData) | ||||
|       .then((res) => { | ||||
|         onSuccess(res) | ||||
|         form.SITE_LOGO = res.data.url | ||||
|         Message.success('上传成功') | ||||
|       }) | ||||
|       .catch((error) => { | ||||
|         onError(error) | ||||
|       }) | ||||
|   })() | ||||
|     ; (async function requestWrap() { | ||||
|       const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options | ||||
|       onProgress(20) | ||||
|       const formData = new FormData() | ||||
|       formData.append(name as string, fileItem.file as Blob) | ||||
|       uploadFile(formData) | ||||
|         .then((res) => { | ||||
|           onSuccess(res) | ||||
|           form.SITE_LOGO = res.data.url | ||||
|           Message.success('上传成功') | ||||
|         }) | ||||
|         .catch((error) => { | ||||
|           onError(error) | ||||
|         }) | ||||
|     })() | ||||
|   return { | ||||
|     abort() { | ||||
|       controller.abort() | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| defineOptions({ name: 'MailSetting' }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| </style> | ||||
| <style lang="scss" scoped></style> | ||||
|   | ||||
| @@ -1,92 +1,62 @@ | ||||
| <template> | ||||
|   <a-form | ||||
|     ref="formRef" | ||||
|     :model="form" | ||||
|     :rules="rules" | ||||
|     size="small" | ||||
|     :auto-label-width="true" | ||||
|     label-align="left" | ||||
|     :layout="width >= 500 ? 'horizontal' : 'vertical'" | ||||
|     :disabled="!isUpdate" | ||||
|     scroll-to-first-error | ||||
|     style="margin-top: 10px" | ||||
|   > | ||||
|   <a-form ref="formRef" :model="form" :rules="rules" size="small" :auto-label-width="true" label-align="left" | ||||
|     :layout="width >= 500 ? 'horizontal' : 'vertical'" :disabled="!isUpdate" scroll-to-first-error | ||||
|     style="margin-top: 10px"> | ||||
|     <a-list size="small" :bordered="false"> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_ERROR_LOCK_COUNT.name" | ||||
|           field="PASSWORD_ERROR_LOCK_COUNT" | ||||
|           :help="securityConfig.PASSWORD_ERROR_LOCK_COUNT.description" | ||||
|           hide-asterisk | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_ERROR_LOCK_COUNT" class="input-width" :default-value="0" :precision="0" :min="0" :max="10"> | ||||
|         <a-form-item :label="securityConfig.PASSWORD_ERROR_LOCK_COUNT.name" field="PASSWORD_ERROR_LOCK_COUNT" | ||||
|           :help="securityConfig.PASSWORD_ERROR_LOCK_COUNT.description" hide-asterisk> | ||||
|           <a-input-number v-model="form.PASSWORD_ERROR_LOCK_COUNT" class="input-width" :default-value="0" :precision="0" | ||||
|             :min="0" :max="10"> | ||||
|             <template #append>次</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|      <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.name" | ||||
|           field="PASSWORD_ERROR_LOCK_MINUTES" | ||||
|           :help="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.description" | ||||
|           hide-asterisk | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_ERROR_LOCK_MINUTES" class="input-width" :precision="0" :min="1" :max="1440"> | ||||
|       <a-list-item> | ||||
|         <a-form-item :label="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.name" field="PASSWORD_ERROR_LOCK_MINUTES" | ||||
|           :help="securityConfig.PASSWORD_ERROR_LOCK_MINUTES.description" hide-asterisk> | ||||
|           <a-input-number v-model="form.PASSWORD_ERROR_LOCK_MINUTES" class="input-width" :precision="0" :min="1" | ||||
|             :max="1440"> | ||||
|             <template #append>分钟</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_EXPIRATION_DAYS.name" | ||||
|           field="PASSWORD_EXPIRATION_DAYS" | ||||
|           :help="securityConfig.PASSWORD_EXPIRATION_DAYS.description" | ||||
|           hide-asterisk | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_EXPIRATION_DAYS" class="input-width" :precision="0" :min="0" :max="999"> | ||||
|         <a-form-item :label="securityConfig.PASSWORD_EXPIRATION_DAYS.name" field="PASSWORD_EXPIRATION_DAYS" | ||||
|           :help="securityConfig.PASSWORD_EXPIRATION_DAYS.description" hide-asterisk> | ||||
|           <a-input-number v-model="form.PASSWORD_EXPIRATION_DAYS" class="input-width" :precision="0" :min="0" | ||||
|             :max="999"> | ||||
|             <template #append>天</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.name" | ||||
|           field="PASSWORD_EXPIRATION_WARNING_DAYS" | ||||
|           :help="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.description" | ||||
|           hide-asterisk | ||||
|         > | ||||
|           <a-input-number v-model="form.PASSWORD_EXPIRATION_WARNING_DAYS" class="input-width" :precision="0" :min="0" :max="998"> | ||||
|         <a-form-item :label="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.name" | ||||
|           field="PASSWORD_EXPIRATION_WARNING_DAYS" :help="securityConfig.PASSWORD_EXPIRATION_WARNING_DAYS.description" | ||||
|           hide-asterisk> | ||||
|           <a-input-number v-model="form.PASSWORD_EXPIRATION_WARNING_DAYS" class="input-width" :precision="0" :min="0" | ||||
|             :max="998"> | ||||
|             <template #append>天</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_REUSE_POLICY.name" | ||||
|           field="PASSWORD_REUSE_POLICY" | ||||
|           :help="securityConfig.PASSWORD_REUSE_POLICY.description" | ||||
|           hide-asterisk | ||||
|         > | ||||
|         <a-form-item :label="securityConfig.PASSWORD_REUSE_POLICY.name" field="PASSWORD_REUSE_POLICY" | ||||
|           :help="securityConfig.PASSWORD_REUSE_POLICY.description" hide-asterisk> | ||||
|           <a-input-number v-model="form.PASSWORD_REUSE_POLICY" class="input-width" :precision="0" :min="3" :max="32"> | ||||
|             <template #append>次</template> | ||||
|           </a-input-number> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_MIN_LENGTH.name" | ||||
|           field="PASSWORD_MIN_LENGTH" | ||||
|           :help="securityConfig.PASSWORD_MIN_LENGTH.description" | ||||
|           hide-asterisk | ||||
|         > | ||||
|         <a-form-item :label="securityConfig.PASSWORD_MIN_LENGTH.name" field="PASSWORD_MIN_LENGTH" | ||||
|           :help="securityConfig.PASSWORD_MIN_LENGTH.description" hide-asterisk> | ||||
|           <a-input-number v-model="form.PASSWORD_MIN_LENGTH" class="input-width" :precision="0" :min="8" :max="32" /> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_ALLOW_CONTAIN_USERNAME.name" | ||||
|           field="PASSWORD_ALLOW_CONTAIN_USERNAME" | ||||
|         > | ||||
|         <a-form-item :label="securityConfig.PASSWORD_ALLOW_CONTAIN_USERNAME.name" | ||||
|           field="PASSWORD_ALLOW_CONTAIN_USERNAME"> | ||||
|           <a-switch v-model="form.PASSWORD_ALLOW_CONTAIN_USERNAME" type="round" :checked-value="1" :unchecked-value="0"> | ||||
|             <template #checked>是</template> | ||||
|             <template #unchecked>否</template> | ||||
| @@ -94,11 +64,10 @@ | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item | ||||
|           :label="securityConfig.PASSWORD_CONTAIN_SPECIAL_CHARACTERS.name" | ||||
|           field="PASSWORD_CONTAIN_SPECIAL_CHARACTERS" | ||||
|         > | ||||
|           <a-switch v-model="form.PASSWORD_CONTAIN_SPECIAL_CHARACTERS" type="round" :checked-value="1" :unchecked-value="0"> | ||||
|         <a-form-item :label="securityConfig.PASSWORD_CONTAIN_SPECIAL_CHARACTERS.name" | ||||
|           field="PASSWORD_CONTAIN_SPECIAL_CHARACTERS"> | ||||
|           <a-switch v-model="form.PASSWORD_CONTAIN_SPECIAL_CHARACTERS" type="round" :checked-value="1" | ||||
|             :unchecked-value="0"> | ||||
|             <template #checked>是</template> | ||||
|             <template #unchecked>否</template> | ||||
|           </a-switch> | ||||
| @@ -148,6 +117,7 @@ import { type FormInstance, Message, Modal } from '@arco-design/web-vue' | ||||
| import { type OptionResp, type SecurityConfig, listOption, resetOptionValue, updateOption } from '@/apis' | ||||
| import { useForm } from '@/hooks' | ||||
|  | ||||
| defineOptions({ name: 'SecuritySetting' }) | ||||
| const { width } = useWindowSize() | ||||
|  | ||||
| const formRef = ref<FormInstance>() | ||||
|   | ||||
| @@ -1,27 +1,46 @@ | ||||
| <template> | ||||
|   <div class="gi_page"> | ||||
|     <a-card class="general-card" title="系统配置"> | ||||
|       <a-tabs default-active-key="1" type="rounded"> | ||||
|         <a-tab-pane key="1" title="基础配置"> | ||||
|           <BasicSetting /> | ||||
|         </a-tab-pane> | ||||
|         <a-tab-pane key="2" title="邮件配置"> | ||||
|           <MailSetting /> | ||||
|         </a-tab-pane> | ||||
|         <a-tab-pane key="3" title="安全配置"> | ||||
|           <SecuritySetting /> | ||||
|         </a-tab-pane> | ||||
|       <a-tabs v-model:active-key="activeKey" hide-content type="rounded" @change="change"> | ||||
|         <a-tab-pane key="1" title="基础配置" /> | ||||
|         <a-tab-pane key="2" title="邮件配置" /> | ||||
|         <a-tab-pane key="3" title="安全配置" /> | ||||
|       </a-tabs> | ||||
|       <keep-alive> | ||||
|         <component :is="PanMap[activeKey]" /> | ||||
|       </keep-alive> | ||||
|     </a-card> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { useRoute, useRouter } from 'vue-router' | ||||
| import BasicSetting from './components/BasicSetting.vue' | ||||
| import MailSetting from './components/MailSetting.vue' | ||||
| import SecuritySetting from './components/SecuritySetting.vue' | ||||
|  | ||||
| defineOptions({ name: 'SystemConfig' }) | ||||
| const PanMap: Record<string, Component> = { | ||||
|   1: BasicSetting, | ||||
|   2: MailSetting, | ||||
|   3: SecuritySetting | ||||
| } | ||||
| const route = useRoute() | ||||
| const router = useRouter() | ||||
| const activeKey = ref('1') | ||||
| watch( | ||||
|   () => route.query, | ||||
|   () => { | ||||
|     if (route.query.tabKey) { | ||||
|       activeKey.value = String(route.query.tabKey) | ||||
|     } | ||||
|   }, | ||||
|   { immediate: true } | ||||
| ) | ||||
| const change = (key: string | number) => { | ||||
|   activeKey.value = key as string | ||||
|   router.replace({ path: route.path, query: { tabKey: key } }) | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 秋帆
					秋帆