From e672c2dfdffe61984fbf423dfe6007cb5525c487 Mon Sep 17 00:00:00 2001 From: baiqi Date: Mon, 7 Aug 2023 13:47:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=B3=BB=E7=BB=9F=E8=AE=BE=E7=BD=AE):=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=AE=BE=E7=BD=AE-=E7=95=8C=E9=9D=A2?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE-=E8=87=AA=E5=AE=9A=E4=B9=89=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E9=A3=8E=E6=A0=BC&=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/config/vite.config.base.ts | 2 +- frontend/index.html | 6 +- frontend/package.json | 4 + frontend/{src/assets => public}/favicon.ico | Bin .../svg => public/images}/MS-full-logo.svg | 0 .../assets => public}/images/login-banner.jpg | Bin .../svg => public/images}/login-logo.svg | 0 frontend/src/App.vue | 6 + frontend/src/api/modules/setting/config.ts | 27 + frontend/src/api/requrls/setting/config.ts | 4 + frontend/src/assets/images/login-bg.jpg | Bin 4580 -> 0 bytes .../components/pure/ms-color-select/index.vue | 21 +- .../src/components/pure/ms-drawer/index.vue | 12 +- .../components/pure/ms-drawer/locale/en-US.ts | 1 + .../components/pure/ms-drawer/locale/zh-CN.ts | 1 + .../pure/ms-pagination/pagination.tsx | 1 + frontend/src/components/pure/navbar/index.vue | 18 +- frontend/src/enums/tableEnum.ts | 1 + frontend/src/layout/default-layout.vue | 11 +- frontend/src/models/setting/config.ts | 46 +- frontend/src/store/modules/app/index.ts | 39 +- frontend/src/theme/default.less | 6 +- frontend/src/utils/dom.ts | 5 + frontend/src/utils/theme.ts | 134 +++ .../src/views/login/components/banner.vue | 2 +- .../src/views/login/components/login-form.vue | 4 +- .../system/config/components/authConfig.vue | 809 ++++++++++++++++++ .../system/config/components/pageConfig.vue | 153 +++- .../src/views/setting/system/config/index.vue | 21 +- .../setting/system/config/locale/zh-CN.ts | 103 +++ 30 files changed, 1362 insertions(+), 75 deletions(-) rename frontend/{src/assets => public}/favicon.ico (100%) rename frontend/{src/assets/svg => public/images}/MS-full-logo.svg (100%) rename frontend/{src/assets => public}/images/login-banner.jpg (100%) rename frontend/{src/assets/svg => public/images}/login-logo.svg (100%) delete mode 100644 frontend/src/assets/images/login-bg.jpg create mode 100644 frontend/src/utils/theme.ts create mode 100644 frontend/src/views/setting/system/config/components/authConfig.vue diff --git a/frontend/config/vite.config.base.ts b/frontend/config/vite.config.base.ts index ea2ff70eaf..675e83e581 100644 --- a/frontend/config/vite.config.base.ts +++ b/frontend/config/vite.config.base.ts @@ -18,7 +18,7 @@ export default defineConfig({ configArcoStyleImportPlugin(), createSvgIconsPlugin({ // 指定需要缓存的图标文件夹 - iconDirs: [resolve(process.cwd(), 'src/assets/svg')], // 与本地储存地址一致 + iconDirs: [resolve(process.cwd(), 'src/assets/svg'), resolve(process.cwd(), 'public/images')], // 与本地储存地址一致 // 指定symbolId格式 symbolId: 'icon-[name]', }), diff --git a/frontend/index.html b/frontend/index.html index 4943b26291..44e04ce58c 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,11 +2,7 @@ - + MeterSphere diff --git a/frontend/package.json b/frontend/package.json index eff09b6400..7fe255fad4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -40,6 +40,7 @@ "@arco-design/web-vue": "^2.49.2", "@arco-themes/vue-ms-theme-default": "^0.0.25", "@form-create/arco-design": "^3.1.21", + "@types/color": "^3.0.3", "@vueuse/core": "^10.2.1", "ace-builds": "^1.22.0", "axios": "^0.24.0", @@ -79,8 +80,11 @@ "@vitest/coverage-c8": "^0.31.4", "@vue/babel-plugin-jsx": "^1.1.1", "@vue/test-utils": "^2.3.2", + "@zougt/some-loader-utils": "^1.4.3", + "@zougt/vite-plugin-theme-preprocessor": "^1.4.8", "autoprefixer": "^10.4.14", "axios-mock-adapter": "^1.21.5", + "color": "^4.2.3", "consola": "^2.15.3", "cross-env": "^7.0.3", "eslint": "^8.42.0", diff --git a/frontend/src/assets/favicon.ico b/frontend/public/favicon.ico similarity index 100% rename from frontend/src/assets/favicon.ico rename to frontend/public/favicon.ico diff --git a/frontend/src/assets/svg/MS-full-logo.svg b/frontend/public/images/MS-full-logo.svg similarity index 100% rename from frontend/src/assets/svg/MS-full-logo.svg rename to frontend/public/images/MS-full-logo.svg diff --git a/frontend/src/assets/images/login-banner.jpg b/frontend/public/images/login-banner.jpg similarity index 100% rename from frontend/src/assets/images/login-banner.jpg rename to frontend/public/images/login-banner.jpg diff --git a/frontend/src/assets/svg/login-logo.svg b/frontend/public/images/login-logo.svg similarity index 100% rename from frontend/src/assets/svg/login-logo.svg rename to frontend/public/images/login-logo.svg diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 612a664afe..2d0abe71f5 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -14,6 +14,7 @@ import { saveBaseInfo, getBaseInfo } from '@/api/modules/setting/config'; import { getLocalStorage, setLocalStorage } from '@/utils/local-storage'; import useAppStore from '@/store/modules/app'; + import { watchStyle, watchTheme } from '@/utils/theme'; const appStore = useAppStore(); @@ -29,6 +30,11 @@ } }); + // 初始化平台风格和主题色 + watchStyle(appStore.pageConfig.style, appStore.pageConfig); + watchTheme(appStore.pageConfig.theme, appStore.pageConfig); + window.document.title = appStore.pageConfig.title; + onBeforeMount(async () => { try { appStore.initSystemversion(); // 初始化系统版本 diff --git a/frontend/src/api/modules/setting/config.ts b/frontend/src/api/modules/setting/config.ts index d7063f5baf..d7ede4d088 100644 --- a/frontend/src/api/modules/setting/config.ts +++ b/frontend/src/api/modules/setting/config.ts @@ -7,7 +7,12 @@ import { GetEmailInfoUrl, SavePageConfigUrl, GetPageConfigUrl, + GetAuthListUrl, + GetAuthDetailUrl, + UpdateAuthUrl, + AddAuthUrl, } from '@/api/requrls/setting/config'; +import { TableQueryParams } from '@/models/common'; import type { SaveInfoParams, @@ -16,6 +21,8 @@ import type { BaseConfig, SavePageConfigParams, PageConfigReturns, + AuthItem, + AuthParams, } from '@/models/setting/config'; // 测试邮箱连接 @@ -52,3 +59,23 @@ export function savePageConfig(data: SavePageConfigParams) { export function getPageConfig() { return MSR.get({ url: GetPageConfigUrl }); } + +// 获取认证源列表 +export function getAuthList(data: TableQueryParams) { + return MSR.post({ url: GetAuthListUrl, data }); +} + +// 获取认证源详情 +export function getAuthDetail(id: string) { + return MSR.get({ url: GetAuthDetailUrl, params: { id } }); +} + +// 添加认证源 +export function addAuth(data: AuthParams) { + return MSR.post({ url: AddAuthUrl, data }); +} + +// 更新认证源 +export function updateAuth(data: AuthParams) { + return MSR.post({ url: UpdateAuthUrl, data }); +} diff --git a/frontend/src/api/requrls/setting/config.ts b/frontend/src/api/requrls/setting/config.ts index 9488647cb6..eb714749b7 100644 --- a/frontend/src/api/requrls/setting/config.ts +++ b/frontend/src/api/requrls/setting/config.ts @@ -5,3 +5,7 @@ export const GetEmailInfoUrl = '/system/parameter/get/email-info'; export const GetBaseInfoUrl = '/system/parameter/get/base-info'; export const SavePageConfigUrl = '/display/save'; export const GetPageConfigUrl = '/display/info'; +export const UpdateAuthUrl = '/system/authsource/update'; +export const GetAuthListUrl = '/system/authsource/list'; +export const AddAuthUrl = '/system/authsource/add'; +export const GetAuthDetailUrl = '/system/authsource/get'; diff --git a/frontend/src/assets/images/login-bg.jpg b/frontend/src/assets/images/login-bg.jpg deleted file mode 100644 index 481075ed0a67d3fb9ffd6dc28de0df91f268ad7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4580 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 - + - + diff --git a/frontend/src/components/pure/ms-drawer/index.vue b/frontend/src/components/pure/ms-drawer/index.vue index b84bc48a1f..52a7d0881f 100644 --- a/frontend/src/components/pure/ms-drawer/index.vue +++ b/frontend/src/components/pure/ms-drawer/index.vue @@ -37,6 +37,9 @@ {{ t(props.cancelText || 'ms.drawer.cancel') }} + + {{ t(props.saveContinueText || 'ms.drawer.saveContinue') }} + {{ t(props.okText || 'ms.drawer.ok') }} @@ -66,6 +69,8 @@ okLoading?: boolean; okText?: string; cancelText?: string; + saveContinueText?: string; + showContinue?: boolean; width: number; } @@ -73,8 +78,9 @@ footer: true, mask: true, showSkeleton: false, + showContinue: false, }); - const emit = defineEmits(['update:visible', 'confirm', 'cancel']); + const emit = defineEmits(['update:visible', 'confirm', 'cancel', 'continue']); const { t } = useI18n(); @@ -87,6 +93,10 @@ } ); + const handleContinue = () => { + emit('continue'); + }; + const handleOk = () => { emit('confirm'); }; diff --git a/frontend/src/components/pure/ms-drawer/locale/en-US.ts b/frontend/src/components/pure/ms-drawer/locale/en-US.ts index fb71ee1f37..c3011936b8 100644 --- a/frontend/src/components/pure/ms-drawer/locale/en-US.ts +++ b/frontend/src/components/pure/ms-drawer/locale/en-US.ts @@ -1,4 +1,5 @@ export default { 'ms.drawer.cancel': 'Cancel', 'ms.drawer.ok': 'Confirm', + 'ms.drawer.saveContinue': 'Save & Continue', }; diff --git a/frontend/src/components/pure/ms-drawer/locale/zh-CN.ts b/frontend/src/components/pure/ms-drawer/locale/zh-CN.ts index 10d992fecb..b67226f200 100644 --- a/frontend/src/components/pure/ms-drawer/locale/zh-CN.ts +++ b/frontend/src/components/pure/ms-drawer/locale/zh-CN.ts @@ -1,4 +1,5 @@ export default { 'ms.drawer.cancel': '取消', 'ms.drawer.ok': '确认', + 'ms.drawer.saveContinue': '保存并继续添加', }; diff --git a/frontend/src/components/pure/ms-pagination/pagination.tsx b/frontend/src/components/pure/ms-pagination/pagination.tsx index fbb7ed1b92..883a5f329d 100644 --- a/frontend/src/components/pure/ms-pagination/pagination.tsx +++ b/frontend/src/components/pure/ms-pagination/pagination.tsx @@ -414,6 +414,7 @@ export default defineComponent({ 'jumper-prepend': slots['jumper-prepend'], 'jumper-append': slots['jumper-append'], }} + simple disabled={props.disabled} current={computedCurrent.value} pages={pages.value} diff --git a/frontend/src/components/pure/navbar/index.vue b/frontend/src/components/pure/navbar/index.vue index a2e2285e0c..c1a65ad099 100644 --- a/frontend/src/components/pure/navbar/index.vue +++ b/frontend/src/components/pure/navbar/index.vue @@ -191,7 +191,7 @@ import TopMenu from '@/components/bussiness/ms-top-menu/index.vue'; import MessageBox from '../message-box/index.vue'; import { NOT_SHOW_PROJECT_SELECT_MODULE } from '@/router/constants'; - import { getProjectList } from '@/api/modules/setting/project'; + // import { getProjectList } from '@/api/modules/setting/project'; import { useI18n } from '@/hooks/useI18n'; import type { ProjectListItem } from '@/models/setting/project'; @@ -210,12 +210,12 @@ const projectList: Ref = ref([]); onBeforeMount(async () => { - try { - const res = await getProjectList(appStore.getCurrentOrgId); - projectList.value = res; - } catch (error) { - console.log(error); - } + // try { + // const res = await getProjectList(appStore.getCurrentOrgId); + // projectList.value = res; + // } catch (error) { + // console.log(error); + // } }); const showProjectSelect = computed(() => { @@ -279,9 +279,7 @@ diff --git a/frontend/src/models/setting/config.ts b/frontend/src/models/setting/config.ts index 1da55663d6..9df184ed5e 100644 --- a/frontend/src/models/setting/config.ts +++ b/frontend/src/models/setting/config.ts @@ -43,7 +43,7 @@ export interface TestEmailParams { // 界面配置入参 export interface SavePageConfigParams { fileList: (File | undefined)[]; - request: Recordable[]; + request: (Recordable | undefined)[]; } interface FileParamItem extends ParamItem { @@ -54,12 +54,17 @@ interface FileParamItem extends ParamItem { // 页面配置返回参数 export type PageConfigReturns = FileParamItem[]; -// 主题配置对象 +// 平台风格 +export type Style = 'default' | 'custom' | 'follow'; +// 主题 +export type Theme = 'default' | 'custom'; + +// 主题配置对象 export interface ThemeConfig { - style: string; + style: Style; customStyle: string; - theme: string; + theme: Theme; customTheme: string; } @@ -83,3 +88,36 @@ export interface PlatformConfig { export interface PageConfig extends ThemeConfig, LoginConfig, PlatformConfig {} export type PageConfigKeys = keyof PageConfig; + +// 认证源配置列表项对象 +export interface AuthItem { + id: string; + enable: boolean; + createTime: number; + updateTime: number; + description: string; + name: string; + type: string; + configuration: string; +} + +// 认证源配置对象 +export type AuthConfig = Omit; + +// 认证源配置表单对象 +export interface AuthForm { + id?: string; + enable: boolean; + description: string; + name: string; + type: string; + configuration: Recordable; +} + +// 认证源配置接口入参 +export type AuthParams = Omit & { + configuration: string; +}; + +// 认证源配置详情对象 +export type AuthDetail = AuthForm & Omit; diff --git a/frontend/src/store/modules/app/index.ts b/frontend/src/store/modules/app/index.ts index f3028ce263..eb399eb0fc 100644 --- a/frontend/src/store/modules/app/index.ts +++ b/frontend/src/store/modules/app/index.ts @@ -7,18 +7,19 @@ import { useI18n } from '@/hooks/useI18n'; import { cloneDeep } from 'lodash-es'; import { getPageConfig } from '@/api/modules/setting/config'; import { setFavicon } from '@/utils'; +import { watchStyle, watchTheme } from '@/utils/theme'; import type { NotificationReturn } from '@arco-design/web-vue/es/notification/interface'; import type { RouteRecordNormalized, RouteRecordRaw } from 'vue-router'; import type { AppState } from './types'; import type { BreadcrumbItem } from '@/components/bussiness/ms-breadcrumb/types'; -import type { PageConfig, PageConfigKeys } from '@/models/setting/config'; +import type { PageConfig, PageConfigKeys, Style, Theme } from '@/models/setting/config'; const defaultThemeConfig = { - style: 'default', - customStyle: '', - theme: 'default', - customTheme: '', + style: 'default' as Style, + customStyle: '#f9f9fe', + theme: 'default' as Theme, + customTheme: '#811fa3', }; const defaultLoginConfig = { title: 'MeterSphere', @@ -211,6 +212,8 @@ const useAppStore = defineStore('app', { try { const res = await getPageConfig(); if (Array.isArray(res) && res.length > 0) { + let hasStyleChange = false; + let hasThemeChange = false; res.forEach((e) => { const key = e.paramKey.split('ui.')[1] as PageConfigKeys; // 参数名前缀ui.去掉 if (['icon', 'loginLogo', 'loginImage', 'logoPlatform'].includes(key)) { @@ -222,6 +225,19 @@ const useAppStore = defineStore('app', { }, ] as any; } else { + if (key === 'style') { + // 风格是否更改,先判断自定义风格的值是否相等,再判断非自定义的俩值是否相等 + hasStyleChange = !['default', 'follow'].includes(e.paramValue) + ? this.pageConfig.customStyle !== e.paramValue + : this.pageConfig.style !== e.paramValue; + } + if (key === 'theme') { + // 主题是否更改,先判断自定义主题的值是否相等,再判断非自定义的俩值是否相等 + hasThemeChange = + e.paramValue !== 'default' + ? this.pageConfig.customTheme !== e.paramValue + : this.pageConfig.theme !== e.paramValue; + } this.pageConfig[key] = e.paramValue as any; } }); @@ -229,16 +245,29 @@ const useAppStore = defineStore('app', { // 判断是否选择了自定义主题色 this.pageConfig.customTheme = this.pageConfig.theme; this.pageConfig.theme = 'custom'; + } else { + // 非自定义则需要重置自定义主题色为空,避免本地缓存与接口配置不一致 + this.pageConfig.customTheme = defaultThemeConfig.customTheme; } if (!['default', 'follow'].includes(this.pageConfig.style)) { // 判断是否选择了自定义平台风格 this.pageConfig.customStyle = this.pageConfig.style; this.pageConfig.style = 'custom'; + } else { + // 非自定义则需要重置自定义风格,避免本地缓存与接口配置不一致 + this.pageConfig.customStyle = defaultThemeConfig.customStyle; } if (this.pageConfig.icon[0]?.url) { // 设置网站 favicon setFavicon(this.pageConfig.icon[0].url); } + // 如果风格和主题有变化,则初始化一下主题和风格;没有变化则不需要在此初始化,在 App.vue 中初始化过了 + if (hasStyleChange) { + watchStyle(this.pageConfig.style, this.pageConfig); + } + if (hasThemeChange) { + watchTheme(this.pageConfig.theme, this.pageConfig); + } } } catch (error) { console.log(error); diff --git a/frontend/src/theme/default.less b/frontend/src/theme/default.less index dda0976723..b7473e0f2d 100644 --- a/frontend/src/theme/default.less +++ b/frontend/src/theme/default.less @@ -1,4 +1,2 @@ -.theme-defalut { - --primary-6: #811fa3; - --primary-7: #6e1a8b; -} +@primary-6: #811fa3; +@primary-7: #6e1a8b; diff --git a/frontend/src/utils/dom.ts b/frontend/src/utils/dom.ts index 462c8b8fa5..1dfd559d7d 100644 --- a/frontend/src/utils/dom.ts +++ b/frontend/src/utils/dom.ts @@ -4,6 +4,11 @@ export interface ScrollToViewOptions { inline?: 'start' | 'center' | 'end' | 'nearest'; } +/** + * 将指定元素滚动至视图区域内 + * @param targetRef 目标 ref 或 DOM + * @param options 滚动配置 + */ export function scrollIntoView(targetRef: HTMLElement | Element | null, options: ScrollToViewOptions = {}) { const scrollOptions: ScrollToViewOptions = { behavior: options.behavior || 'smooth', diff --git a/frontend/src/utils/theme.ts b/frontend/src/utils/theme.ts new file mode 100644 index 0000000000..5474bd951f --- /dev/null +++ b/frontend/src/utils/theme.ts @@ -0,0 +1,134 @@ +import Color from 'color'; + +import type { PageConfig, Style, Theme } from '@/models/setting/config'; + +/** + * 获取颜色对象的 rgb 色值 + * @param color Color对象 + * @returns 颜色值 + */ +export function getRGBinnerVal(color: Color) { + return color + .rgb() + .toString() + .replace(/rgba?\(|\)/g, ''); +} + +/** + * 设置自定义颜色的主题色 + * @param primaryColor 主题色 + */ +export function setCustomTheme(primaryColor: string) { + const styleTag = document.createElement('style'); + styleTag.id = 'MS-CUSTOM-THEME'; + const primary = new Color(primaryColor); + const white = Color('#fff'); + const P = primary.toString().replace(/rgba?\(|\)/g, ''); + const P1 = getRGBinnerVal(primary.mix(white, 0.95)); + const P2 = getRGBinnerVal(primary.mix(white, 0.8)); + const P3 = getRGBinnerVal(primary.mix(white, 0.7)); + const P4 = getRGBinnerVal(primary.mix(white, 0.15)); + const P7 = getRGBinnerVal(primary.mix(Color('#000'), 0.15)); + const P9 = getRGBinnerVal(primary.mix(white, 0.9)); + styleTag.innerHTML = ` + body{ + --primary-1: ${P1}; + --primary-2: ${P2}; + --primary-3: ${P3}; + --primary-4: ${P4}; + --primary-5: ${P}; + --primary-6: ${P}; + --primary-7: ${P7}; + --primary-9: ${P9}; + } + `; + // 移除之前的 style 标签(如果有) + const prevStyleTag = document.getElementById('MS-CUSTOM-THEME'); + if (prevStyleTag) { + prevStyleTag.remove(); + } + document.body.appendChild(styleTag); +} + +/** + * 主题重置为默认主题 + */ +export function resetTheme() { + const prevStyleTag = document.getElementById('MS-CUSTOM-THEME'); + if (prevStyleTag) { + prevStyleTag.remove(); + } +} + +/** + * 设置平台色 + * @param color 平台色 + */ +export function setPlatformColor(color: string, isFollow = false) { + const styleTag = document.createElement('style'); + styleTag.id = 'MS-CUSTOM-STYLE'; + const white = Color('#fff'); + // 跟随主题色,设置为P1 + const platformColor = isFollow ? new Color(color).mix(white, 0.95) : new Color(color); + styleTag.innerHTML = ` + body{ + --color-bg-3: ${platformColor}; + --color-text-n9: ${platformColor}; + } + `; + // 移除之前的 style 标签(如果有) + const prevStyleTag = document.getElementById('MS-CUSTOM-STYLE'); + if (prevStyleTag) { + prevStyleTag.remove(); + } + document.body.appendChild(styleTag); +} + +/** + * 平台风格重置为默认平台风格 + */ +export function resetStyle() { + const prevStyleTag = document.getElementById('MS-CUSTOM-STYLE'); + if (prevStyleTag) { + prevStyleTag.remove(); + } +} + +/** + * 检测风格变化 + * @param val 风格 + * @param pageConfig 页面配置对象 + */ +export function watchStyle(val: Style, pageConfig: PageConfig) { + if (val === 'default') { + // 默认就是系统自带的颜色 + resetStyle(); + } else if (val === 'custom') { + // 自定义风格颜色 + setPlatformColor(pageConfig.customStyle); + } else { + // 跟随主题色 + setPlatformColor(pageConfig.customTheme, true); + } +} + +/** + * 检测主题色变化 + * @param val 主题色 + * @param pageConfig 页面配置对象 + */ +export function watchTheme(val: Theme, pageConfig: PageConfig) { + if (val === 'default') { + resetTheme(); + if (pageConfig.style === 'follow') { + // 若平台风格跟随主题色 + resetStyle(); + } + } else { + setCustomTheme(pageConfig.customTheme); + if (pageConfig.style === 'follow') { + // 若平台风格跟随主题色 + setPlatformColor(pageConfig.customTheme, true); + } + } +} diff --git a/frontend/src/views/login/components/banner.vue b/frontend/src/views/login/components/banner.vue index 83edc3f742..58b378022d 100644 --- a/frontend/src/views/login/components/banner.vue +++ b/frontend/src/views/login/components/banner.vue @@ -7,7 +7,6 @@ + + diff --git a/frontend/src/views/setting/system/config/components/pageConfig.vue b/frontend/src/views/setting/system/config/components/pageConfig.vue index f931c56e99..83661418c1 100644 --- a/frontend/src/views/setting/system/config/components/pageConfig.vue +++ b/frontend/src/views/setting/system/config/components/pageConfig.vue @@ -3,20 +3,6 @@
- {{ t('system.config.page.style') }} - - - -
- - - {{ item.label }} - - -
- -
-
{{ t('system.config.page.theme') }} @@ -27,8 +13,22 @@ {{ item.label }} -
- +
+ +
+
+ {{ t('system.config.page.style') }} + + + +
+ + + {{ item.label }} + + +
+
@@ -60,7 +60,7 @@
- +
@@ -195,12 +195,12 @@
-