mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 10:57:10 +08:00 
			
		
		
		
	feat: 新增系统配置
This commit is contained in:
		| @@ -2,10 +2,10 @@ | ||||
| <html lang="en"> | ||||
|   <head> | ||||
|     <meta charset="UTF-8" /> | ||||
|     <link rel="icon" href="/favicon.ico" /> | ||||
|     <link rel="shortcut icon" href="/favicon.ico" /> | ||||
|     <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" /> | ||||
|     <link rel="stylesheet" href="/static/css/loading.css" type="text/css" /> | ||||
|     <title>ContiNew Admin</title> | ||||
|     <title></title> | ||||
|   </head> | ||||
|  | ||||
|   <body> | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import http from '@/utils/http' | ||||
| import type { LabelValueState } from '@/types/global' | ||||
| import type { TreeNodeData } from '@arco-design/web-vue' | ||||
| import type {OptionQuery} from '@/apis' | ||||
|  | ||||
| const BASE_URL = '/common' | ||||
|  | ||||
| @@ -24,6 +25,11 @@ export function listCommonDict(code: string) { | ||||
|   return http.get<LabelValueState[]>(`${BASE_URL}/dict/${code}`) | ||||
| } | ||||
|  | ||||
| /** @desc 获取系统参数 */ | ||||
| export function listOption(params: OptionQuery) { | ||||
|   return http.get<LabelValueState[]>(`${BASE_URL}/option`, params) | ||||
| } | ||||
|  | ||||
| /** @desc 上传文件 */ | ||||
| export function uploadFile(data: FormData) { | ||||
|   return http.post(`${BASE_URL}/file`, data) | ||||
|   | ||||
							
								
								
									
										19
									
								
								src/apis/system/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/apis/system/config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| import http from '@/utils/http' | ||||
| import type * as System from './type' | ||||
|  | ||||
| const BASE_URL = '/system/option' | ||||
|  | ||||
| /** @desc 获取系统配置参数 */ | ||||
| export function list(params: System.OptionQuery) { | ||||
|   return http.get<System.OptionResp[]>(`${BASE_URL}`, params) | ||||
| } | ||||
|  | ||||
| /** @desc 保存系统参数 */ | ||||
| export function save(req: System.OptionReq[]) { | ||||
|   return http.patch(`${BASE_URL}`, req) | ||||
| } | ||||
|  | ||||
| /** @desc 重置系统参数 */ | ||||
| export function resetValue(params: System.OptionQuery) { | ||||
|   return http.patch(`${BASE_URL}/value`, params) | ||||
| } | ||||
| @@ -6,3 +6,4 @@ export * from './log' | ||||
| export * from './dict' | ||||
| export * from './file' | ||||
| export * from './storage' | ||||
| export * from './config' | ||||
|   | ||||
| @@ -233,4 +233,29 @@ export type StorageResp = { | ||||
| export interface StorageQuery extends PageQuery { | ||||
|   description?: string | ||||
|   status?: number | ||||
| } | ||||
|  | ||||
| /** 系统参数*/ | ||||
| export interface OptionQuery { | ||||
|   code?: Array<string> | ||||
| } | ||||
|  | ||||
| export interface OptionReq { | ||||
|   code: string | ||||
|   value: string | ||||
| } | ||||
|  | ||||
| export interface OptionResp { | ||||
|   name?: string | ||||
|   code: string | ||||
|   value: string | ||||
|   description?: string | ||||
| } | ||||
|  | ||||
| /** 系统配置*/ | ||||
| export interface BasicConfigRecordResp { | ||||
|   site_title?: string | ||||
|   site_copyright?: string | ||||
|   site_logo?: string | ||||
|   site_favicon?: string | ||||
| } | ||||
| @@ -1,9 +1,12 @@ | ||||
| <template> | ||||
|   <div class="gi-footer">Copyright © 2022-{{ year }} ContiNew Admin</div> | ||||
|   <div class="gi-footer">{{appStore.getCopyright()}}</div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import Dayjs from 'dayjs' | ||||
| import {useAppStore} from "@/stores"; | ||||
|  | ||||
| const appStore = useAppStore(); | ||||
|  | ||||
| defineOptions({ name: 'GiFooter' }) | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
| <template> | ||||
|   <section class="system-logo" :class="{ collapsed: props.collapsed }" @click="toHome"> | ||||
|     <img class="logo" src="@/assets/images/logo.svg" /> | ||||
|     <span class="system-name">ContiNew Admin</span> | ||||
|     <img class="logo" :src="appStore.getLogo() ?? '@/assets/images/logo.svg'"  alt="logo"/> | ||||
|     <span class="system-name">{{ appStore.getTitle() }}</span> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import {useAppStore} from "@/stores"; | ||||
|  | ||||
| const appStore= useAppStore(); | ||||
|  | ||||
| interface Props { | ||||
|   collapsed?: boolean | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import router from '@/router' | ||||
| import { useUserStore, useRouteStore } from '@/stores' | ||||
| import {useUserStore, useRouteStore, useAppStore} from '@/stores' | ||||
| import { getToken } from '@/utils/auth' | ||||
| import { isHttp } from '@/utils/validate' | ||||
|  | ||||
| @@ -15,6 +15,8 @@ export const resetHasRouteFlag = () => { | ||||
| router.beforeEach(async (to, from, next) => { | ||||
|   const userStore = useUserStore() | ||||
|   const routeStore = useRouteStore() | ||||
|   const appStore = useAppStore(); | ||||
|   appStore.initWebConfig(); | ||||
|  | ||||
|   // 判断该用户是否登录 | ||||
|   if (getToken()) { | ||||
|   | ||||
| @@ -2,10 +2,58 @@ import { defineStore } from 'pinia' | ||||
| import { computed, reactive, toRefs } from 'vue' | ||||
| import { generate, getRgbStr } from '@arco-design/color' | ||||
| import defaultSettings from '@/config/setting.json' | ||||
| import type { BasicConfigRecordResp } from '@/apis' | ||||
| import { listOption } from '@/apis' | ||||
|  | ||||
| const storeSetup = () => { | ||||
|   // App配置 | ||||
|   const settingConfig = reactive({ ...defaultSettings }) as App.SettingConfig | ||||
|   // 系统配置 | ||||
|   let webConfig = {} as BasicConfigRecordResp | ||||
|  | ||||
|   const getLogo = () => { | ||||
|     return webConfig.site_logo; | ||||
|   } | ||||
|   const getFavicon = () => { | ||||
|     return webConfig?.site_favicon | ||||
|   } | ||||
|   const getTitle = () => { | ||||
|     return webConfig?.site_title | ||||
|   } | ||||
|   const getCopyright = () => { | ||||
|     return webConfig?.site_copyright | ||||
|   } | ||||
|  | ||||
|   // 初始化系统配置 | ||||
|   const initWebConfig = () => { | ||||
|      listOption({ | ||||
|       code: ['site_title', 'site_copyright', 'site_favicon', 'site_logo'] | ||||
|     }).then((res) => { | ||||
|       const resMap = new Map() | ||||
|       res.data.forEach((item) => { | ||||
|         resMap.set(item.label, item.value) | ||||
|       }) | ||||
|       webConfig = { | ||||
|         site_title: resMap.get('site_title'), | ||||
|         site_copyright: resMap.get('site_copyright'), | ||||
|         site_logo: resMap.get('site_logo'), | ||||
|         site_favicon: resMap.get('site_logo') | ||||
|       } | ||||
|       document.title = resMap.get('site_title') | ||||
|       document | ||||
|         .querySelector('link[rel="shortcut icon"]') | ||||
|         ?.setAttribute('href', resMap.get('site_favicon') || 'https://cnadmin.charles7c.top/favicon.ico') | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   // 保存系统配置 | ||||
|   const saveWebConfig = (config: BasicConfigRecordResp) => { | ||||
|     webConfig = config | ||||
|     document.title = config.site_title || '' | ||||
|     document | ||||
|       .querySelector('link[rel="shortcut icon"]') | ||||
|       ?.setAttribute('href', config.site_favicon || 'https://cnadmin.charles7c.top/favicon.ico') | ||||
|   } | ||||
|  | ||||
|   // 页面切换动画类名 | ||||
|   const transitionName = computed(() => (settingConfig.animate ? settingConfig.animateMode : '')) | ||||
| @@ -61,8 +109,14 @@ const storeSetup = () => { | ||||
|     toggleTheme, | ||||
|     setThemeColor, | ||||
|     initTheme, | ||||
|     setMenuCollapse | ||||
|     setMenuCollapse, | ||||
|     getLogo, | ||||
|     getFavicon, | ||||
|     getTitle, | ||||
|     getCopyright, | ||||
|     initWebConfig, | ||||
|     saveWebConfig | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const useAppStore = defineStore('app', storeSetup, { persist: true }) | ||||
| export const useAppStore = defineStore('app', storeSetup, {}) | ||||
|   | ||||
| @@ -19,7 +19,8 @@ | ||||
|             @submit="handleLogin" | ||||
|           > | ||||
|             <h3 class="login-right__title"> | ||||
|               <img class="logo" src="@/assets/images/logo.svg" alt="logo" /><span>ContiNew Admin</span> | ||||
|               <img :src="appStore.getLogo()" alt="Logo" height="33" /> | ||||
|               <span>{{appStore.getTitle()}}</span> | ||||
|             </h3> | ||||
|             <a-form-item field="username"> | ||||
|               <a-input v-model="form.username" placeholder="请输入用户名" allow-clear> | ||||
| @@ -55,18 +56,27 @@ | ||||
|  | ||||
|     <GiThemeBtn class="theme-btn"></GiThemeBtn> | ||||
|     <LoginBg></LoginBg> | ||||
|  | ||||
| <!--    <div class="footer"> | ||||
|       <div class="beian"> | ||||
|         <div class="below text" v-html="appStore.getCopyright()"></div> | ||||
|       </div> | ||||
|     </div>--> | ||||
|   </div> | ||||
|  | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { getImageCaptcha } from '@/apis' | ||||
| import { Message, type FormInstance } from '@arco-design/web-vue' | ||||
| import LoginBg from './components/LoginBg/index.vue' | ||||
| import { useUserStore } from '@/stores' | ||||
| import {useAppStore, useUserStore} from '@/stores' | ||||
| import { useStorage } from '@vueuse/core' | ||||
| import { useLoading } from '@/hooks' | ||||
| import { encryptByRsa } from '@/utils/encrypt' | ||||
|  | ||||
| const appStore = useAppStore(); | ||||
|  | ||||
| defineOptions({ name: 'Login' }) | ||||
|  | ||||
| const loginConfig = useStorage('login-config', { | ||||
| @@ -231,4 +241,25 @@ onMounted(() => { | ||||
|   margin: 0 0 0 5px; | ||||
|   cursor: pointer; | ||||
| } | ||||
|  | ||||
| .footer { | ||||
|   align-items: center; | ||||
|   box-sizing: border-box; | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   .beian { | ||||
|     .text { | ||||
|       color: #41464f; | ||||
|       font-size: 12px; | ||||
|       font-weight: 400; | ||||
|       letter-spacing: 0.2px; | ||||
|       line-height: 20px; | ||||
|       text-align: center; | ||||
|     } | ||||
|     .below { | ||||
|       align-items: center; | ||||
|       display: flex; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
							
								
								
									
										364
									
								
								src/views/system/config/components/BasicSetting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										364
									
								
								src/views/system/config/components/BasicSetting.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,364 @@ | ||||
| <template> | ||||
|   <a-form ref="formRef" layout="vertical" :model="form" :rules="rules" size="large" :disabled="!isEdit"> | ||||
|     <a-list class="list-layout" :bordered="false"> | ||||
|       <a-list-item> | ||||
|         <a-form-item class="image-item" hide-label field="favicon"> | ||||
|           {{ siteFavicon?.name }} | ||||
|           <template #extra> | ||||
|             {{ siteFavicon?.description }} | ||||
|             <br/> | ||||
|             <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" | ||||
|                   > | ||||
|                     <img :src="faviconFile.url" alt="favicon"/> | ||||
|                     <div v-if="isEdit" class="arco-upload-list-picture-mask favicon"> | ||||
|                       <IconEdit/> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                   <div v-else class="arco-upload-picture-card favicon"> | ||||
|                     <div class="arco-upload-picture-card-text"> | ||||
|                       <icon-upload/> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </template> | ||||
|             </a-upload> | ||||
|           </template> | ||||
|         </a-form-item> | ||||
|       </a-list-item> | ||||
|       <a-list-item> | ||||
|         <a-form-item class="image-item" hide-label field="site_logo"> | ||||
|           {{ siteLogo?.name }} | ||||
|           <template #extra> | ||||
|             {{ siteLogo?.description }} | ||||
|             <br/> | ||||
|             <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 v-if="logoFile && logoFile.url" class="arco-upload-list-picture custom-upload-avatar logo"> | ||||
|                     <img :src="logoFile.url" alt="Logo"/> | ||||
|                     <div v-if="isEdit" class="arco-upload-list-picture-mask logo"> | ||||
|                       <IconEdit/> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                   <div v-else class="arco-upload-picture-card logo"> | ||||
|                     <div class="arco-upload-picture-card-text"> | ||||
|                       <icon-upload/> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </template> | ||||
|             </a-upload> | ||||
|           </template> | ||||
|         </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="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="form.site_copyright" | ||||
|               placeholder="请输入版权信息" | ||||
|               :auto-size="{ | ||||
|               minRows: 3 | ||||
|             }" | ||||
|               show-word-limit | ||||
|           /> | ||||
|         </a-form-item> | ||||
|         <div style="margin-top: 20px"> | ||||
|           <a-space> | ||||
|             <a-button v-if="!isEdit" @click="toResetValue"> | ||||
|               <template #icon> | ||||
|                 <icon-undo/> | ||||
|               </template> | ||||
|               恢复默认 | ||||
|             </a-button> | ||||
|             <a-button v-if="!isEdit" type="primary" @click="toEdit"> | ||||
|               <template #icon> | ||||
|                 <icon-edit/> | ||||
|               </template> | ||||
|               修改 | ||||
|             </a-button> | ||||
|             <a-button v-if="isEdit" type="primary" @click="handleSave"> | ||||
|               <template #icon> | ||||
|                 <icon-save/> | ||||
|               </template> | ||||
|               保存 | ||||
|             </a-button> | ||||
|             <a-button v-if="isEdit" @click="reset"> | ||||
|               <template #icon> | ||||
|                 <icon-refresh/> | ||||
|               </template> | ||||
|               重置 | ||||
|             </a-button> | ||||
|             <a-button v-if="isEdit" @click="handleCancel"> | ||||
|               <template #icon> | ||||
|                 <icon-undo/> | ||||
|               </template> | ||||
|               取消 | ||||
|             </a-button> | ||||
|           </a-space> | ||||
|         </div> | ||||
|       </a-list-item> | ||||
|     </a-list> | ||||
|   </a-form> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import type {OptionResp} from '@/apis' | ||||
| import {list, resetValue, save, uploadFile} from '@/apis' | ||||
| import {useAppStore} from '@/stores' | ||||
| import {type FileItem, type FormInstance, type RequestOption, Message, Modal} from '@arco-design/web-vue' | ||||
| import {useForm} from '@/hooks' | ||||
|  | ||||
| const formRef = ref<FormInstance>() | ||||
| const dataList = ref<OptionResp[]>([]) | ||||
| const isEdit = ref(false) | ||||
| const logoFile = ref<FileItem>({uid: '-1'}) | ||||
| const faviconFile = ref<FileItem>({uid: '-2'}) | ||||
| const siteTitle = ref<OptionResp>() | ||||
| const siteCopyright = ref<OptionResp>() | ||||
| const siteLogo = ref<OptionResp>() | ||||
| const siteFavicon = ref<OptionResp>() | ||||
| const appStore = useAppStore() | ||||
|  | ||||
| const rules: FormInstance['rules'] = { | ||||
|   site_title: [{required: true, message: '请输入系统标题'}], | ||||
|   site_copyright: [{required: true, message: '请输入版权信息'}] | ||||
| } | ||||
|  | ||||
| const {form} = useForm({ | ||||
|   site_title: '', | ||||
|   site_copyright: '', | ||||
|   site_logo: '', | ||||
|   site_favicon: '' | ||||
| }) | ||||
|  | ||||
| const query = reactive({ | ||||
|   queryParams: { | ||||
|     code: ['site_title', 'site_copyright', 'site_logo', 'site_favicon'] | ||||
|   } | ||||
| }) | ||||
|  | ||||
| /** | ||||
|  * 重置表单 | ||||
|  */ | ||||
| const reset = () => { | ||||
|   form.site_title=siteTitle.value?.value || ''; | ||||
|   form.site_copyright= siteCopyright.value?.value || ''; | ||||
|   form.site_logo= siteLogo.value?.value || ''; | ||||
|   form. site_favicon=siteFavicon.value?.value || '' | ||||
|   logoFile.value.url = siteLogo.value?.value | ||||
|   faviconFile.value.url = siteFavicon.value?.value | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 查询配置 | ||||
|  */ | ||||
| const getConfig = async () => { | ||||
|   const res = await list(query.queryParams) | ||||
|   dataList.value = res.data | ||||
|   siteTitle.value = dataList.value.find((option) => option.code === 'site_title') | ||||
|   siteCopyright.value = dataList.value.find((option) => option.code === 'site_copyright') | ||||
|   siteLogo.value = dataList.value.find((option) => option.code === 'site_logo') | ||||
|   siteFavicon.value = dataList.value.find((option) => option.code === 'site_favicon') | ||||
|   reset() | ||||
| } | ||||
|  | ||||
| getConfig() | ||||
|  | ||||
| /** | ||||
|  * 取消 | ||||
|  */ | ||||
| const handleCancel = () => { | ||||
|   isEdit.value = false | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 保存 | ||||
|  */ | ||||
| const handleSave = () => { | ||||
|   formRef.value?.validate((valid: any) => { | ||||
|     if (!valid) { | ||||
|       const optionList: OptionResp[] = Object.entries(form).map((item) => { | ||||
|         return { | ||||
|           code: item[0], | ||||
|           value: item[1] | ||||
|         } | ||||
|       }) | ||||
|       save(optionList).then((res) => { | ||||
|         appStore.saveWebConfig(form) | ||||
|         handleCancel() | ||||
|         Message.success(res.msg) | ||||
|       }) | ||||
|     } | ||||
|   }) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 上传 Logo | ||||
|  * | ||||
|  * @param options / | ||||
|  */ | ||||
| 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(res.msg) | ||||
|         }) | ||||
|         .catch((error) => { | ||||
|           onError(error) | ||||
|         }) | ||||
|   })() | ||||
|   return { | ||||
|     abort() { | ||||
|       controller.abort() | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 上传 Favicon | ||||
|  * | ||||
|  * @param options / | ||||
|  */ | ||||
| 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(res.msg) | ||||
|         }) | ||||
|         .catch((error) => { | ||||
|           onError(error) | ||||
|         }) | ||||
|   })() | ||||
|   return { | ||||
|     abort() { | ||||
|       controller.abort() | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 选择 Logo | ||||
|  * | ||||
|  * @param _ / | ||||
|  * @param currentFile | ||||
|  */ | ||||
| const handleChangeLogo = (_: any, currentFile: any) => { | ||||
|   logoFile.value = { | ||||
|     ...currentFile | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 选择 Favicon | ||||
|  * | ||||
|  * @param _ / | ||||
|  * @param currentFile | ||||
|  */ | ||||
| const handleChangeFavicon = (_: any, currentFile: any) => { | ||||
|   faviconFile.value = { | ||||
|     ...currentFile | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 恢复默认 | ||||
|  */ | ||||
| const handleResetValue = async () => { | ||||
|   await resetValue(query.queryParams) | ||||
|   Message.success('恢复成功') | ||||
|   await getConfig() | ||||
|   appStore.saveWebConfig(form) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 点击恢复默认 | ||||
|  */ | ||||
| const toResetValue = () => { | ||||
|   Modal.warning({ | ||||
|     title: '警告', | ||||
|     content: '确认恢复基础配置为默认值吗?', | ||||
|     hideCancel: false, | ||||
|     maskClosable: false, | ||||
|     onBeforeOk: handleResetValue | ||||
|   }) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 开始编辑 | ||||
|  */ | ||||
| const toEdit = () => { | ||||
|   isEdit.value = true | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
| .logo { | ||||
|   width: 33px; | ||||
|   height: 33px; | ||||
|   min-width: 33px; | ||||
|   line-height: 33px; | ||||
| } | ||||
|  | ||||
| .favicon { | ||||
|   width: 16px; | ||||
|   height: 16px; | ||||
|   min-width: 16px; | ||||
|   line-height: 16px; | ||||
| } | ||||
|  | ||||
| .arco-form .image-item, | ||||
| .input-item { | ||||
|   margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| :deep(.arco-list-medium .arco-list-content-wrapper .arco-list-content > .arco-list-item) { | ||||
|   padding: 13px; | ||||
|   border-bottom: 1px solid var(--color-fill-3); | ||||
| } | ||||
|  | ||||
| :deep(.arco-form-item-wrapper-col) { | ||||
|   width: 50%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										28
									
								
								src/views/system/config/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/views/system/config/index.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| <script lang="ts" setup> | ||||
| import BasicSetting from './components/BasicSetting.vue' | ||||
| </script> | ||||
|  | ||||
| <script lang="ts"> | ||||
| export default { | ||||
|   name: 'Config' | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <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="高级配置" disabled></a-tab-pane> | ||||
|       </a-tabs> | ||||
|     </a-card> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="less"> | ||||
| :deep(.arco-tabs-content) { | ||||
|   padding-top: 5px; | ||||
| } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user
	 Yoofff
					Yoofff