Commit ed41e5082fd2e6109c2ad3ff77199d15ac14342a

Authored by vben
1 parent 0362ab26

perf(setting-drawer): perf setting-drawer

build/vite/plugin/html.ts 0 → 100644
  1 +import type { Plugin } from 'vite';
  2 +import ViteHtmlPlugin from 'vite-plugin-html';
  3 +import { isProdFn, isSiteMode, ViteEnv } from '../../utils';
  4 +
  5 +import { hmScript } from '../hm';
  6 +// @ts-ignore
  7 +import pkg from '../../../package.json';
  8 +import { GLOB_CONFIG_FILE_NAME } from '../../constant';
  9 +
  10 +export function setupHtmlPlugin(plugins: Plugin[], env: ViteEnv) {
  11 + const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env;
  12 +
  13 + const htmlPlugin = ViteHtmlPlugin({
  14 + // html title
  15 + title: VITE_GLOB_APP_TITLE,
  16 + minify: isProdFn(),
  17 + options: {
  18 + // Package and insert additional configuration files
  19 + injectConfig: isProdFn()
  20 + ? `<script src='${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
  21 + pkg.version
  22 + }-${new Date().getTime()}'></script>`
  23 + : '',
  24 + // Insert Baidu statistics code
  25 + hmScript: isSiteMode() ? hmScript : '',
  26 + title: VITE_GLOB_APP_TITLE,
  27 + },
  28 + });
  29 +
  30 + plugins.push(htmlPlugin);
  31 + return plugins;
  32 +}
... ...
build/vite/plugin/index.ts
1 1 import type { Plugin as VitePlugin } from 'vite';
2 2 import type { Plugin as rollupPlugin } from 'rollup';
3 3  
4   -import { createMockServer } from 'vite-plugin-mock';
5   -import { VitePWA } from 'vite-plugin-pwa';
6   -import ViteHtmlPlugin from 'vite-plugin-html';
7 4 import PurgeIcons from 'vite-plugin-purge-icons';
8 5  
9 6 import visualizer from 'rollup-plugin-visualizer';
10 7 import gzipPlugin from './gzip/index';
11 8  
12   -import { hmScript } from '../hm';
13   -
14 9 // @ts-ignore
15 10 import pkg from '../../../package.json';
16   -import { isDevFn, isProdFn, isSiteMode, ViteEnv, isReportMode, isBuildGzip } from '../../utils';
17   -import { GLOB_CONFIG_FILE_NAME } from '../../constant';
  11 +import { isProdFn, isSiteMode, ViteEnv, isReportMode, isBuildGzip } from '../../utils';
  12 +import { setupHtmlPlugin } from './html';
  13 +import { setupPwaPlugin } from './pwa';
  14 +import { setupMockPlugin } from './mock';
18 15  
19 16 // gen vite plugins
20 17 export function createVitePlugins(viteEnv: ViteEnv) {
21   - const { VITE_USE_MOCK, VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH, VITE_USE_PWA } = viteEnv;
22   -
23 18 const vitePlugins: VitePlugin[] = [];
24 19  
25 20 // vite-plugin-html
26   - vitePlugins.push(
27   - ViteHtmlPlugin({
28   - // html title
29   - title: VITE_GLOB_APP_TITLE,
30   - minify: isProdFn(),
31   - options: {
32   - // Package and insert additional configuration files
33   - injectConfig: isProdFn()
34   - ? `<script src='${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
35   - pkg.version
36   - }-${new Date().getTime()}'></script>`
37   - : '',
38   - // Insert Baidu statistics code
39   - hmScript: isSiteMode() ? hmScript : '',
40   - title: VITE_GLOB_APP_TITLE,
41   - },
42   - })
43   - );
  21 + setupHtmlPlugin(vitePlugins, viteEnv);
  22 + // vite-plugin-pwa
  23 + setupPwaPlugin(vitePlugins, viteEnv);
  24 + // vite-plugin-mock
  25 + setupMockPlugin(vitePlugins, viteEnv);
44 26  
45 27 // vite-plugin-purge-icons
46 28 vitePlugins.push(PurgeIcons());
47 29  
48   - if (isProdFn() && VITE_USE_PWA) {
49   - vitePlugins.push(
50   - VitePWA({
51   - manifest: {
52   - name: 'Vben Admin',
53   - short_name: 'vben_admin',
54   - icons: [
55   - {
56   - src: './resource/img/pwa-192x192.png',
57   - sizes: '192x192',
58   - type: 'image/png',
59   - },
60   - {
61   - src: './resource/img/pwa-512x512.png',
62   - sizes: '512x512',
63   - type: 'image/png',
64   - },
65   - ],
66   - },
67   - })
68   - );
69   - }
70   -
71   - // vite-plugin-mock
72   - if (isDevFn() && VITE_USE_MOCK) {
73   - // open mock
74   - vitePlugins.push(
75   - createMockServer({
76   - ignore: /^\_/,
77   - mockPath: 'mock',
78   - showTime: true,
79   - })
80   - );
81   - }
82 30 return vitePlugins;
83 31 }
84 32  
... ... @@ -86,17 +34,15 @@ export function createVitePlugins(viteEnv: ViteEnv) {
86 34 export function createRollupPlugin() {
87 35 const rollupPlugins: rollupPlugin[] = [];
88 36  
89   - if (isProdFn()) {
90   - if (isReportMode()) {
91   - // rollup-plugin-visualizer
92   - rollupPlugins.push(
93   - visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin
94   - );
95   - }
96   - if (isBuildGzip() || isSiteMode()) {
97   - // rollup-plugin-gizp
98   - rollupPlugins.push(gzipPlugin());
99   - }
  37 + if (!isProdFn() && isReportMode()) {
  38 + // rollup-plugin-visualizer
  39 + rollupPlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
100 40 }
  41 +
  42 + if (!isProdFn() && (isBuildGzip() || isSiteMode())) {
  43 + // rollup-plugin-gizp
  44 + rollupPlugins.push(gzipPlugin());
  45 + }
  46 +
101 47 return rollupPlugins;
102 48 }
... ...
build/vite/plugin/mock.ts 0 → 100644
  1 +import { createMockServer } from 'vite-plugin-mock';
  2 +import type { Plugin } from 'vite';
  3 +import { isDevFn, ViteEnv } from '../../utils';
  4 +
  5 +export function setupMockPlugin(plugins: Plugin[], env: ViteEnv) {
  6 + const { VITE_USE_MOCK } = env;
  7 + const mockPlugin = createMockServer({
  8 + ignore: /^\_/,
  9 + mockPath: 'mock',
  10 + showTime: true,
  11 + });
  12 + if (isDevFn() && VITE_USE_MOCK) {
  13 + plugins.push(mockPlugin);
  14 + }
  15 + return plugins;
  16 +}
... ...
build/vite/plugin/pwa.ts 0 → 100644
  1 +import { VitePWA } from 'vite-plugin-pwa';
  2 +import type { Plugin } from 'vite';
  3 +import { isProdFn, ViteEnv } from '../../utils';
  4 +
  5 +export function setupPwaPlugin(plugins: Plugin[], env: ViteEnv) {
  6 + const { VITE_USE_PWA } = env;
  7 +
  8 + const pwaPlugin = VitePWA({
  9 + manifest: {
  10 + name: 'Vben Admin',
  11 + short_name: 'vben_admin',
  12 + icons: [
  13 + {
  14 + src: './resource/img/pwa-192x192.png',
  15 + sizes: '192x192',
  16 + type: 'image/png',
  17 + },
  18 + {
  19 + src: './resource/img/pwa-512x512.png',
  20 + sizes: '512x512',
  21 + type: 'image/png',
  22 + },
  23 + ],
  24 + },
  25 + });
  26 +
  27 + if (isProdFn() && VITE_USE_PWA) {
  28 + plugins.push(pwaPlugin);
  29 + }
  30 + return plugins;
  31 +}
... ...
src/components/Menu/src/BasicMenu.tsx
... ... @@ -103,7 +103,7 @@ export default defineComponent({
103 103 const isHorizontal = unref(getIsHorizontal) || getSplit.value;
104 104  
105 105 return {
106   - height: isHorizontal ? `calc(100%)` : `calc(100% - ${props.showLogo ? '48px' : '0px'})`,
  106 + height: isHorizontal ? '100%' : `calc(100% - ${props.showLogo ? '48px' : '0px'})`,
107 107 overflowY: isHorizontal ? 'hidden' : 'auto',
108 108 };
109 109 }
... ...
src/hooks/web/useI18n.ts
... ... @@ -25,9 +25,9 @@ export function useI18n(namespace?: string) {
25 25  
26 26 return {
27 27 ...methods,
28   - t: (key: string, ...arg: Parameters<typeof t>) => {
  28 + t: (key: string, ...arg: Partial<Parameters<typeof t>>) => {
29 29 if (!key) return '';
30   - return t(getKey(key), ...arg);
  30 + return t(getKey(key), ...(arg as Parameters<typeof t>));
31 31 },
32 32 };
33 33 }
... ...
src/layouts/default/setting/SettingDrawer.tsx
1   -import type { ProjectConfig } from '/@/types/config';
2   -
3   -import defaultSetting from '/@/settings/projectSetting';
4   -
5   -import { defineComponent, computed, unref, FunctionalComponent } from 'vue';
  1 +import { defineComponent, computed, unref } from 'vue';
6 2 import { BasicDrawer } from '/@/components/Drawer/index';
7   -import { Divider, Switch, Tooltip, InputNumber, Select } from 'ant-design-vue';
8   -import { Button } from '/@/components/Button';
9   -import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue';
  3 +import { Divider } from 'ant-design-vue';
  4 +import {
  5 + TypePicker,
  6 + ThemePicker,
  7 + SettingFooter,
  8 + SwitchItem,
  9 + SelectItem,
  10 + InputNumberItem,
  11 +} from './components';
10 12  
11 13 import { MenuTypeEnum } from '/@/enums/menuEnum';
12   -import { appStore } from '/@/store/modules/app';
13 14  
14   -import { useMessage } from '/@/hooks/web/useMessage';
15   -import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
16 15 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
17 16 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
18 17 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
... ... @@ -20,8 +19,6 @@ import { useMultipleTabSetting } from &#39;/@/hooks/setting/useMultipleTabSetting&#39;;
20 19 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
21 20 import { useI18n } from '/@/hooks/web/useI18n';
22 21  
23   -import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
24   -
25 22 import { baseHandler } from './handler';
26 23  
27 24 import {
... ... @@ -35,146 +32,8 @@ import {
35 32  
36 33 import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST } from '/@/settings/colorSetting';
37 34  
38   -interface SwitchOptions {
39   - config?: DeepPartial<ProjectConfig>;
40   - def?: any;
41   - disabled?: boolean;
42   - handler?: Fn;
43   -}
44   -
45   -interface SelectConfig {
46   - options?: LabelValueOptions;
47   - def?: any;
48   - disabled?: boolean;
49   - handler?: Fn;
50   -}
51   -
52   -interface ThemePickerProps {
53   - colorList: string[];
54   - handler: Fn;
55   - def: string;
56   -}
57   -
58   -const { createSuccessModal, createMessage } = useMessage();
59 35 const { t } = useI18n();
60 36  
61   -/**
62   - * Menu type Picker comp
63   - */
64   -const MenuTypePicker: FunctionalComponent = () => {
65   - const { getIsHorizontal, getMenuType } = useMenuSetting();
66   - return (
67   - <div class={`setting-drawer__siderbar`}>
68   - {menuTypeList.map((item) => {
69   - const { title, type: ItemType, mode, src } = item;
70   - return (
71   - <Tooltip title={title} placement="bottom" key={title}>
72   - {{
73   - default: () => (
74   - <div
75   - onClick={baseHandler.bind(null, HandlerEnum.CHANGE_LAYOUT, {
76   - mode: mode,
77   - type: ItemType,
78   - split: unref(getIsHorizontal) ? false : undefined,
79   - })}
80   - >
81   - <CheckOutlined
82   - class={['check-icon', unref(getMenuType) === ItemType ? 'active' : '']}
83   - />
84   - <img src={src} />
85   - </div>
86   - ),
87   - }}
88   - </Tooltip>
89   - );
90   - })}
91   - </div>
92   - );
93   -};
94   -
95   -const ThemePicker: FunctionalComponent<ThemePickerProps> = (props) => {
96   - return (
97   - <div class={`setting-drawer__theme-item`}>
98   - {props.colorList.map((color) => {
99   - return (
100   - <span
101   - onClick={() => props.handler?.(color)}
102   - key={color}
103   - class={[props.def === color ? 'active' : '']}
104   - style={{
105   - background: color,
106   - }}
107   - >
108   - <CheckOutlined class="icon" />
109   - </span>
110   - );
111   - })}
112   - </div>
113   - );
114   -};
115   -
116   -/**
117   - * FooterButton component
118   - */
119   -const FooterButton: FunctionalComponent = () => {
120   - const { getRootSetting } = useRootSetting();
121   - function handleCopy() {
122   - const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
123   - unref(isSuccessRef) &&
124   - createSuccessModal({
125   - title: t('layout.setting.operatingTitle'),
126   - content: t('layout.setting.operatingContent'),
127   - });
128   - }
129   - function handleResetSetting() {
130   - try {
131   - appStore.commitProjectConfigState(defaultSetting);
132   - const { colorWeak, grayMode } = defaultSetting;
133   - // updateTheme(themeColor);
134   - updateColorWeak(colorWeak);
135   - updateGrayMode(grayMode);
136   - createMessage.success(t('layout.setting.resetSuccess'));
137   - } catch (error) {
138   - createMessage.error(error);
139   - }
140   - }
141   -
142   - function handleClearAndRedo() {
143   - localStorage.clear();
144   - appStore.resumeAllState();
145   - location.reload();
146   - }
147   -
148   - return (
149   - <div class="setting-drawer__footer">
150   - <Button type="primary" block onClick={handleCopy}>
151   - {() => (
152   - <>
153   - <CopyOutlined class="mr-2" />
154   - {t('layout.setting.copyBtn')}
155   - </>
156   - )}
157   - </Button>
158   - <Button block class="mt-2" onClick={handleResetSetting} color="warning">
159   - {() => (
160   - <>
161   - <RedoOutlined class="mr-2" />
162   - {t('layout.setting.resetBtn')}
163   - </>
164   - )}
165   - </Button>
166   - <Button block class="mt-2" onClick={handleClearAndRedo} color="error">
167   - {() => (
168   - <>
169   - <RedoOutlined class="mr-2" />
170   - {t('layout.setting.clearBtn')}
171   - </>
172   - )}
173   - </Button>
174   - </div>
175   - );
176   -};
177   -
178 37 export default defineComponent({
179 38 name: 'SettingDrawer',
180 39 setup(_, { attrs }) {
... ... @@ -187,6 +46,7 @@ export default defineComponent({
187 46 getFullContent,
188 47 getColorWeak,
189 48 getGrayMode,
  49 + getLockTime,
190 50 } = useRootSetting();
191 51  
192 52 const {
... ... @@ -229,38 +89,44 @@ export default defineComponent({
229 89 function renderSidebar() {
230 90 return (
231 91 <>
232   - <MenuTypePicker />
233   - {renderSwitchItem(t('layout.setting.splitMenu'), {
234   - handler: (e) => {
235   - baseHandler(HandlerEnum.MENU_SPLIT, e);
236   - },
237   - def: unref(getSplit),
238   - disabled: !unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX,
239   - })}
  92 + <TypePicker
  93 + menuTypeList={menuTypeList}
  94 + handler={(item: typeof menuTypeList[0]) => {
  95 + baseHandler(HandlerEnum.CHANGE_LAYOUT, {
  96 + mode: item.mode,
  97 + type: item.type,
  98 + split: unref(getIsHorizontal) ? false : undefined,
  99 + });
  100 + }}
  101 + def={unref(getMenuType)}
  102 + />
  103 + <SwitchItem
  104 + title={t('layout.setting.splitMenu')}
  105 + event={HandlerEnum.MENU_SPLIT}
  106 + def={unref(getSplit)}
  107 + disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
  108 + />
240 109 </>
241 110 );
242 111 }
243 112  
244   - function renderTheme() {
  113 + function renderHeaderTheme() {
245 114 return (
246   - <>
247   - <Divider>{() => t('layout.setting.headerTheme')}</Divider>
248   - <ThemePicker
249   - colorList={HEADER_PRESET_BG_COLOR_LIST}
250   - def={unref(getHeaderBgColor)}
251   - handler={(e) => {
252   - baseHandler(HandlerEnum.HEADER_THEME, e);
253   - }}
254   - />
255   - <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
256   - <ThemePicker
257   - colorList={SIDE_BAR_BG_COLOR_LIST}
258   - def={unref(getMenuBgColor)}
259   - handler={(e) => {
260   - baseHandler(HandlerEnum.MENU_THEME, e);
261   - }}
262   - />
263   - </>
  115 + <ThemePicker
  116 + colorList={HEADER_PRESET_BG_COLOR_LIST}
  117 + def={unref(getHeaderBgColor)}
  118 + event={HandlerEnum.HEADER_THEME}
  119 + />
  120 + );
  121 + }
  122 +
  123 + function renderSiderTheme() {
  124 + return (
  125 + <ThemePicker
  126 + colorList={SIDE_BAR_BG_COLOR_LIST}
  127 + def={unref(getMenuBgColor)}
  128 + event={HandlerEnum.MENU_THEME}
  129 + />
264 130 );
265 131 }
266 132  
... ... @@ -268,264 +134,192 @@ export default defineComponent({
268 134 * @description:
269 135 */
270 136 function renderFeatures() {
271   - return [
272   - renderSwitchItem(t('layout.setting.menuDrag'), {
273   - handler: (e) => {
274   - baseHandler(HandlerEnum.MENU_HAS_DRAG, e);
275   - },
276   - def: unref(getCanDrag),
277   - disabled: !unref(getShowMenuRef),
278   - }),
279   - renderSwitchItem(t('layout.setting.menuSearch'), {
280   - handler: (e) => {
281   - baseHandler(HandlerEnum.HEADER_SEARCH, e);
282   - },
283   - def: unref(getShowSearch),
284   - disabled: !unref(getShowHeader),
285   - }),
286   - renderSwitchItem(t('layout.setting.menuAccordion'), {
287   - handler: (e) => {
288   - baseHandler(HandlerEnum.MENU_ACCORDION, e);
289   - },
290   - def: unref(getAccordion),
291   - disabled: !unref(getShowMenuRef),
292   - }),
293   - renderSwitchItem(t('layout.setting.menuCollapse'), {
294   - handler: (e) => {
295   - baseHandler(HandlerEnum.MENU_COLLAPSED, e);
296   - },
297   - def: unref(getCollapsed),
298   - disabled: !unref(getShowMenuRef),
299   - }),
300   - renderSwitchItem(t('layout.setting.collapseMenuDisplayName'), {
301   - handler: (e) => {
302   - baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e);
303   - },
304   - def: unref(getCollapsedShowTitle),
305   - disabled: !unref(getShowMenuRef) || !unref(getCollapsed),
306   - }),
307   - renderSwitchItem(t('layout.setting.fixedHeader'), {
308   - handler: (e) => {
309   - baseHandler(HandlerEnum.HEADER_FIXED, e);
310   - },
311   - def: unref(getHeaderFixed),
312   - disabled: !unref(getShowHeader),
313   - }),
314   - renderSwitchItem(t('layout.setting.fixedSideBar'), {
315   - handler: (e) => {
316   - baseHandler(HandlerEnum.MENU_FIXED, e);
317   - },
318   - def: unref(getMenuFixed),
319   - disabled: !unref(getShowMenuRef),
320   - }),
321   - renderSelectItem(t('layout.setting.topMenuLayout'), {
322   - handler: (e) => {
323   - baseHandler(HandlerEnum.MENU_TOP_ALIGN, e);
324   - },
325   - def: unref(getTopMenuAlign),
326   - options: topMenuAlignOptions,
327   - disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)),
328   - }),
329   - renderSelectItem(t('layout.setting.menuCollapseButton'), {
330   - handler: (e) => {
331   - baseHandler(HandlerEnum.MENU_TRIGGER, e);
332   - },
333   - disabled: !unref(getShowMenuRef),
334   - def: unref(getTrigger),
335   - options: menuTriggerOptions,
336   - }),
337   -
338   - renderSelectItem(t('layout.setting.contentMode'), {
339   - handler: (e) => {
340   - baseHandler(HandlerEnum.CONTENT_MODE, e);
341   - },
342   - def: unref(getContentMode),
343   - options: contentModeOptions,
344   - }),
345   - <div class={`setting-drawer__cell-item`}>
346   - <span>{t('layout.setting.autoScreenLock')}</span>
347   - <InputNumber
348   - style="width:126px"
349   - size="small"
  137 + return (
  138 + <>
  139 + <SwitchItem
  140 + title={t('layout.setting.menuDrag')}
  141 + event={HandlerEnum.MENU_HAS_DRAG}
  142 + def={unref(getCanDrag)}
  143 + disabled={!unref(getShowMenuRef)}
  144 + />
  145 + <SwitchItem
  146 + title={t('layout.setting.menuSearch')}
  147 + event={HandlerEnum.HEADER_SEARCH}
  148 + def={unref(getShowSearch)}
  149 + disabled={!unref(getShowHeader)}
  150 + />
  151 + <SwitchItem
  152 + title={t('layout.setting.menuAccordion')}
  153 + event={HandlerEnum.MENU_ACCORDION}
  154 + def={unref(getAccordion)}
  155 + disabled={!unref(getShowMenuRef)}
  156 + />
  157 + <SwitchItem
  158 + title={t('layout.setting.menuCollapse')}
  159 + event={HandlerEnum.MENU_COLLAPSED}
  160 + def={unref(getCollapsed)}
  161 + disabled={!unref(getShowMenuRef)}
  162 + />
  163 + <SwitchItem
  164 + title={t('layout.setting.collapseMenuDisplayName')}
  165 + event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE}
  166 + def={unref(getCollapsedShowTitle)}
  167 + disabled={!unref(getShowMenuRef) || !unref(getCollapsed)}
  168 + />
  169 + <SwitchItem
  170 + title={t('layout.setting.fixedHeader')}
  171 + event={HandlerEnum.HEADER_FIXED}
  172 + def={unref(getHeaderFixed)}
  173 + disabled={!unref(getShowHeader)}
  174 + />
  175 + <SwitchItem
  176 + title={t('layout.setting.fixedSideBar')}
  177 + event={HandlerEnum.MENU_FIXED}
  178 + def={unref(getMenuFixed)}
  179 + disabled={!unref(getShowMenuRef)}
  180 + />
  181 + <SelectItem
  182 + title={t('layout.setting.topMenuLayout')}
  183 + event={HandlerEnum.MENU_TOP_ALIGN}
  184 + def={unref(getTopMenuAlign)}
  185 + options={topMenuAlignOptions}
  186 + disabled={!unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit))}
  187 + />
  188 + <SelectItem
  189 + title={t('layout.setting.menuCollapseButton')}
  190 + event={HandlerEnum.MENU_TRIGGER}
  191 + def={unref(getTrigger)}
  192 + options={menuTriggerOptions}
  193 + disabled={!unref(getShowMenuRef)}
  194 + />
  195 + <SelectItem
  196 + title={t('layout.setting.contentMode')}
  197 + event={HandlerEnum.CONTENT_MODE}
  198 + def={unref(getContentMode)}
  199 + options={contentModeOptions}
  200 + />
  201 + <InputNumberItem
  202 + title={t('layout.setting.autoScreenLock')}
350 203 min={0}
351   - onChange={(e: any) => {
352   - baseHandler(HandlerEnum.LOCK_TIME, e);
353   - }}
354   - defaultValue={appStore.getProjectConfig.lockTime}
  204 + event={HandlerEnum.LOCK_TIME}
  205 + defaultValue={unref(getLockTime)}
355 206 formatter={(value: string) => {
356   - if (parseInt(value) === 0) {
357   - return `0(${t('layout.setting.notAutoScreenLock')})`;
358   - }
359   - return `${value}${t('layout.setting.minute')}`;
  207 + return parseInt(value) === 0
  208 + ? `0(${t('layout.setting.notAutoScreenLock')})`
  209 + : `${value}${t('layout.setting.minute')}`;
360 210 }}
361 211 />
362   - </div>,
363   - <div class={`setting-drawer__cell-item`}>
364   - <span>{t('layout.setting.expandedMenuWidth')}</span>
365   - <InputNumber
366   - style="width:126px"
367   - size="small"
  212 + <InputNumberItem
  213 + title={t('layout.setting.expandedMenuWidth')}
368 214 max={600}
369 215 min={100}
370 216 step={10}
  217 + event={HandlerEnum.MENU_WIDTH}
371 218 disabled={!unref(getShowMenuRef)}
372 219 defaultValue={unref(getMenuWidth)}
373 220 formatter={(value: string) => `${parseInt(value)}px`}
374   - onChange={(e: any) => {
375   - baseHandler(HandlerEnum.MENU_WIDTH, e);
376   - }}
377 221 />
378   - </div>,
379   - ];
  222 + </>
  223 + );
380 224 }
381 225  
382 226 function renderContent() {
383   - return [
384   - renderSwitchItem(t('layout.setting.breadcrumb'), {
385   - handler: (e) => {
386   - baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
387   - },
388   - def: unref(getShowBreadCrumb),
389   - disabled: !unref(getShowHeader),
390   - }),
391   - renderSwitchItem(t('layout.setting.breadcrumbIcon'), {
392   - handler: (e) => {
393   - baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
394   - },
395   - def: unref(getShowBreadCrumbIcon),
396   - disabled: !unref(getShowHeader),
397   - }),
398   - renderSwitchItem(t('layout.setting.tabs'), {
399   - handler: (e) => {
400   - baseHandler(HandlerEnum.TABS_SHOW, e);
401   - },
402   - def: unref(getShowMultipleTab),
403   - }),
404   - renderSwitchItem(t('layout.setting.tabsQuickBtn'), {
405   - handler: (e) => {
406   - baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
407   - },
408   - def: unref(getShowQuick),
409   - disabled: !unref(getShowMultipleTab),
410   - }),
411   -
412   - renderSwitchItem(t('layout.setting.sidebar'), {
413   - handler: (e) => {
414   - baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
415   - },
416   - def: unref(getShowMenu),
417   - disabled: unref(getIsHorizontal),
418   - }),
419   - renderSwitchItem(t('layout.setting.header'), {
420   - handler: (e) => {
421   - baseHandler(HandlerEnum.HEADER_SHOW, e);
422   - },
423   - def: unref(getShowHeader),
424   - }),
425   - renderSwitchItem('Logo', {
426   - handler: (e) => {
427   - baseHandler(HandlerEnum.SHOW_LOGO, e);
428   - },
429   - def: unref(getShowLogo),
430   - }),
431   - renderSwitchItem(t('layout.setting.footer'), {
432   - handler: (e) => {
433   - baseHandler(HandlerEnum.SHOW_FOOTER, e);
434   - },
435   - def: unref(getShowFooter),
436   - }),
437   - renderSwitchItem(t('layout.setting.fullContent'), {
438   - handler: (e) => {
439   - baseHandler(HandlerEnum.FULL_CONTENT, e);
440   - },
441   - def: unref(getFullContent),
442   - }),
443   - renderSwitchItem(t('layout.setting.grayMode'), {
444   - handler: (e) => {
445   - baseHandler(HandlerEnum.GRAY_MODE, e);
446   - },
447   - def: unref(getGrayMode),
448   - }),
449   - renderSwitchItem(t('layout.setting.colorWeak'), {
450   - handler: (e) => {
451   - baseHandler(HandlerEnum.COLOR_WEAK, e);
452   - },
453   - def: unref(getColorWeak),
454   - }),
455   - ];
456   - }
457   -
458   - function renderTransition() {
459 227 return (
460 228 <>
461   - {renderSwitchItem(t('layout.setting.progress'), {
462   - handler: (e) => {
463   - baseHandler(HandlerEnum.OPEN_PROGRESS, e);
464   - },
465   - def: unref(getOpenNProgress),
466   - })}
467   - {renderSwitchItem(t('layout.setting.switchLoading'), {
468   - handler: (e) => {
469   - baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e);
470   - },
471   - def: unref(getOpenPageLoading),
472   - })}
  229 + <SwitchItem
  230 + title={t('layout.setting.breadcrumb')}
  231 + event={HandlerEnum.SHOW_BREADCRUMB}
  232 + def={unref(getShowBreadCrumb)}
  233 + disabled={!unref(getShowHeader)}
  234 + />
  235 +
  236 + <SwitchItem
  237 + title={t('layout.setting.breadcrumbIcon')}
  238 + event={HandlerEnum.SHOW_BREADCRUMB_ICON}
  239 + def={unref(getShowBreadCrumbIcon)}
  240 + disabled={!unref(getShowHeader)}
  241 + />
  242 +
  243 + <SwitchItem
  244 + title={t('layout.setting.tabs')}
  245 + event={HandlerEnum.TABS_SHOW}
  246 + def={unref(getShowMultipleTab)}
  247 + />
  248 +
  249 + <SwitchItem
  250 + title={t('layout.setting.tabsQuickBtn')}
  251 + event={HandlerEnum.TABS_SHOW_QUICK}
  252 + def={unref(getShowQuick)}
  253 + disabled={!unref(getShowMultipleTab)}
  254 + />
  255 +
  256 + <SwitchItem
  257 + title={t('layout.setting.sidebar')}
  258 + event={HandlerEnum.MENU_SHOW_SIDEBAR}
  259 + def={unref(getShowMenu)}
  260 + disabled={unref(getIsHorizontal)}
  261 + />
  262 +
  263 + <SwitchItem
  264 + title={t('layout.setting.header')}
  265 + event={HandlerEnum.HEADER_SHOW}
  266 + def={unref(getShowHeader)}
  267 + />
  268 + <SwitchItem title="Logo" event={HandlerEnum.SHOW_LOGO} def={unref(getShowLogo)} />
  269 + <SwitchItem
  270 + title={t('layout.setting.footer')}
  271 + event={HandlerEnum.SHOW_FOOTER}
  272 + def={unref(getShowFooter)}
  273 + />
  274 + <SwitchItem
  275 + title={t('layout.setting.fullContent')}
  276 + event={HandlerEnum.FULL_CONTENT}
  277 + def={unref(getFullContent)}
  278 + />
473 279  
474   - {renderSwitchItem(t('layout.setting.switchAnimation'), {
475   - handler: (e) => {
476   - baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e);
477   - },
478   - def: unref(getEnableTransition),
479   - })}
  280 + <SwitchItem
  281 + title={t('layout.setting.grayMode')}
  282 + event={HandlerEnum.GRAY_MODE}
  283 + def={unref(getGrayMode)}
  284 + />
480 285  
481   - {renderSelectItem(t('layout.setting.animationType'), {
482   - handler: (e) => {
483   - baseHandler(HandlerEnum.ROUTER_TRANSITION, e);
484   - },
485   - def: unref(getBasicTransition),
486   - options: routerTransitionOptions,
487   - disabled: !unref(getEnableTransition),
488   - })}
  286 + <SwitchItem
  287 + title={t('layout.setting.colorWeak')}
  288 + event={HandlerEnum.COLOR_WEAK}
  289 + def={unref(getColorWeak)}
  290 + />
489 291 </>
490 292 );
491 293 }
492 294  
493   - function renderSelectItem(text: string, config?: SelectConfig) {
494   - const { handler, def, disabled = false, options } = config || {};
495   - const opt = def ? { value: def, defaultValue: def } : {};
  295 + function renderTransition() {
496 296 return (
497   - <div class={`setting-drawer__cell-item`}>
498   - <span>{text}</span>
499   - <Select
500   - {...opt}
501   - disabled={disabled}
502   - size="small"
503   - style={{ width: '126px' }}
504   - onChange={(e) => {
505   - handler && handler(e);
506   - }}
507   - options={options}
  297 + <>
  298 + <SwitchItem
  299 + title={t('layout.setting.progress')}
  300 + event={HandlerEnum.OPEN_PROGRESS}
  301 + def={unref(getOpenNProgress)}
  302 + />
  303 + <SwitchItem
  304 + title={t('layout.setting.switchLoading')}
  305 + event={HandlerEnum.OPEN_PAGE_LOADING}
  306 + def={unref(getOpenPageLoading)}
508 307 />
509   - </div>
510   - );
511   - }
512 308  
513   - function renderSwitchItem(text: string, options?: SwitchOptions) {
514   - const { handler, def, disabled = false } = options || {};
515   - const opt = def ? { checked: def } : {};
516   - return (
517   - <div class={`setting-drawer__cell-item`}>
518   - <span>{text}</span>
519   - <Switch
520   - {...opt}
521   - disabled={disabled}
522   - onChange={(e: any) => {
523   - handler && handler(e);
524   - }}
525   - checkedChildren={t('layout.setting.on')}
526   - unCheckedChildren={t('layout.setting.off')}
  309 + <SwitchItem
  310 + title={t('layout.setting.switchAnimation')}
  311 + event={HandlerEnum.OPEN_ROUTE_TRANSITION}
  312 + def={unref(getEnableTransition)}
527 313 />
528   - </div>
  314 +
  315 + <SelectItem
  316 + title={t('layout.setting.animationType')}
  317 + event={HandlerEnum.ROUTER_TRANSITION}
  318 + def={unref(getBasicTransition)}
  319 + options={routerTransitionOptions}
  320 + disabled={!unref(getEnableTransition)}
  321 + />
  322 + </>
529 323 );
530 324 }
531 325  
... ... @@ -541,7 +335,10 @@ export default defineComponent({
541 335 <>
542 336 <Divider>{() => t('layout.setting.navMode')}</Divider>
543 337 {renderSidebar()}
544   - {renderTheme()}
  338 + <Divider>{() => t('layout.setting.headerTheme')}</Divider>
  339 + {renderHeaderTheme()}
  340 + <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
  341 + {renderSiderTheme()}
545 342 <Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
546 343 {renderFeatures()}
547 344 <Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
... ... @@ -549,7 +346,7 @@ export default defineComponent({
549 346 <Divider>{() => t('layout.setting.animation')}</Divider>
550 347 {renderTransition()}
551 348 <Divider />
552   - <FooterButton />
  349 + <SettingFooter />
553 350 </>
554 351 ),
555 352 }}
... ...
src/layouts/default/setting/components/InputNumberItem.vue 0 → 100644
  1 +<template>
  2 + <div :class="prefixCls">
  3 + <span> {{ title }}</span>
  4 + <InputNumber
  5 + v-bind="$attrs"
  6 + size="small"
  7 + :class="`${prefixCls}-input-number`"
  8 + @change="handleChange"
  9 + />
  10 + </div>
  11 +</template>
  12 +<script lang="ts">
  13 + import { defineComponent, PropType } from 'vue';
  14 +
  15 + import { InputNumber } from 'ant-design-vue';
  16 + import { useDesign } from '/@/hooks/web/useDesign';
  17 + import { baseHandler } from '../handler';
  18 + import { HandlerEnum } from '../enum';
  19 +
  20 + export default defineComponent({
  21 + name: 'InputNumberItem',
  22 + components: { InputNumber },
  23 + props: {
  24 + event: {
  25 + type: Number as PropType<HandlerEnum>,
  26 + default: () => {},
  27 + },
  28 + title: {
  29 + type: String,
  30 + },
  31 + },
  32 + setup(props) {
  33 + const { prefixCls } = useDesign('setting-input-number-item');
  34 +
  35 + function handleChange(e: ChangeEvent) {
  36 + props.event && baseHandler(props.event, e);
  37 + }
  38 + return {
  39 + prefixCls,
  40 + handleChange,
  41 + };
  42 + },
  43 + });
  44 +</script>
  45 +<style lang="less" scoped>
  46 + @import (reference) '../../../../design/index.less';
  47 + @prefix-cls: ~'@{namespace}-setting-input-number-item';
  48 +
  49 + .@{prefix-cls} {
  50 + display: flex;
  51 + justify-content: space-between;
  52 + margin: 16px 0;
  53 +
  54 + &-input-number {
  55 + width: 126px;
  56 + }
  57 + }
  58 +</style>
... ...
src/layouts/default/setting/components/SelectItem.vue 0 → 100644
  1 +<template>
  2 + <div :class="prefixCls">
  3 + <span> {{ title }}</span>
  4 + <Select
  5 + v-bind="getBindValue"
  6 + :class="`${prefixCls}-select`"
  7 + @change="handleChange"
  8 + :disabled="disabled"
  9 + size="small"
  10 + :options="options"
  11 + />
  12 + </div>
  13 +</template>
  14 +<script lang="ts">
  15 + import { defineComponent, PropType, computed } from 'vue';
  16 +
  17 + import { Select } from 'ant-design-vue';
  18 + import { useDesign } from '/@/hooks/web/useDesign';
  19 + import { baseHandler } from '../handler';
  20 + import { HandlerEnum } from '../enum';
  21 +
  22 + export default defineComponent({
  23 + name: 'SelectItem',
  24 + components: { Select },
  25 + props: {
  26 + event: {
  27 + type: Number as PropType<HandlerEnum>,
  28 + default: () => {},
  29 + },
  30 + disabled: {
  31 + type: Boolean,
  32 + },
  33 + title: {
  34 + type: String,
  35 + },
  36 + def: {
  37 + type: [String, Number] as PropType<string | number>,
  38 + },
  39 + initValue: {
  40 + type: [String, Number] as PropType<string | number>,
  41 + },
  42 + options: {
  43 + type: Array as PropType<LabelValueOptions>,
  44 + default: [],
  45 + },
  46 + },
  47 + setup(props) {
  48 + const { prefixCls } = useDesign('setting-select-item');
  49 + const getBindValue = computed(() => {
  50 + return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
  51 + });
  52 +
  53 + function handleChange(e: ChangeEvent) {
  54 + props.event && baseHandler(props.event, e);
  55 + }
  56 + return {
  57 + prefixCls,
  58 + handleChange,
  59 + getBindValue,
  60 + };
  61 + },
  62 + });
  63 +</script>
  64 +<style lang="less" scoped>
  65 + @import (reference) '../../../../design/index.less';
  66 + @prefix-cls: ~'@{namespace}-setting-select-item';
  67 +
  68 + .@{prefix-cls} {
  69 + display: flex;
  70 + justify-content: space-between;
  71 + margin: 16px 0;
  72 +
  73 + &-select {
  74 + width: 126px;
  75 + }
  76 + }
  77 +</style>
... ...
src/layouts/default/setting/components/SettingFooter.vue 0 → 100644
  1 +<template>
  2 + <div :class="prefixCls">
  3 + <a-button type="primary" block @click="handleCopy">
  4 + <CopyOutlined class="mr-2" />
  5 + {{ t('layout.setting.copyBtn') }}
  6 + </a-button>
  7 +
  8 + <a-button color="warning" block @click="handleResetSetting" class="my-3">
  9 + <RedoOutlined class="mr-2" />
  10 + {{ t('layout.setting.resetBtn') }}
  11 + </a-button>
  12 +
  13 + <a-button color="error" block @click="handleClearAndRedo">
  14 + <RedoOutlined class="mr-2" />
  15 + {{ t('layout.setting.clearBtn') }}
  16 + </a-button>
  17 + </div>
  18 +</template>
  19 +<script lang="ts">
  20 + import { defineComponent, unref } from 'vue';
  21 +
  22 + import { useDesign } from '/@/hooks/web/useDesign';
  23 + import { useI18n } from '/@/hooks/web/useI18n';
  24 + import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
  25 + import { appStore } from '/@/store/modules/app';
  26 + import defaultSetting from '/@/settings/projectSetting';
  27 + import { useMessage } from '/@/hooks/web/useMessage';
  28 + import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  29 + import { useRootSetting } from '/@/hooks/setting/useRootSetting';
  30 + import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
  31 +
  32 + export default defineComponent({
  33 + name: 'SettingFooter',
  34 + components: { CopyOutlined, RedoOutlined },
  35 + setup() {
  36 + const { getRootSetting } = useRootSetting();
  37 + const { prefixCls } = useDesign('setting-footer');
  38 + const { t } = useI18n();
  39 + const { createSuccessModal, createMessage } = useMessage();
  40 +
  41 + function handleCopy() {
  42 + const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
  43 + unref(isSuccessRef) &&
  44 + createSuccessModal({
  45 + title: t('layout.setting.operatingTitle'),
  46 + content: t('layout.setting.operatingContent'),
  47 + });
  48 + }
  49 + function handleResetSetting() {
  50 + try {
  51 + appStore.commitProjectConfigState(defaultSetting);
  52 + const { colorWeak, grayMode } = defaultSetting;
  53 + // updateTheme(themeColor);
  54 + updateColorWeak(colorWeak);
  55 + updateGrayMode(grayMode);
  56 + createMessage.success(t('layout.setting.resetSuccess'));
  57 + } catch (error) {
  58 + createMessage.error(error);
  59 + }
  60 + }
  61 +
  62 + function handleClearAndRedo() {
  63 + localStorage.clear();
  64 + appStore.resumeAllState();
  65 + location.reload();
  66 + }
  67 + return {
  68 + prefixCls,
  69 + t,
  70 + handleCopy,
  71 + handleResetSetting,
  72 + handleClearAndRedo,
  73 + };
  74 + },
  75 + });
  76 +</script>
  77 +<style lang="less" scoped>
  78 + @import (reference) '../../../../design/index.less';
  79 + @prefix-cls: ~'@{namespace}-setting-footer';
  80 +
  81 + .@{prefix-cls} {
  82 + display: flex;
  83 + flex-direction: column;
  84 + align-items: center;
  85 + }
  86 +</style>
... ...
src/layouts/default/setting/components/SwitchItem.vue 0 → 100644
  1 +<template>
  2 + <div :class="prefixCls">
  3 + <span> {{ title }}</span>
  4 + <Switch
  5 + v-bind="getBindValue"
  6 + @change="handleChange"
  7 + :disabled="disabled"
  8 + :checkedChildren="t('layout.setting.on')"
  9 + :unCheckedChildren="t('layout.setting.off')"
  10 + />
  11 + </div>
  12 +</template>
  13 +<script lang="ts">
  14 + import { defineComponent, PropType, computed } from 'vue';
  15 +
  16 + import { Switch } from 'ant-design-vue';
  17 + import { useDesign } from '/@/hooks/web/useDesign';
  18 + import { useI18n } from '/@/hooks/web/useI18n';
  19 + import { baseHandler } from '../handler';
  20 + import { HandlerEnum } from '../enum';
  21 +
  22 + export default defineComponent({
  23 + name: 'SwitchItem',
  24 + components: { Switch },
  25 + props: {
  26 + event: {
  27 + type: Number as PropType<HandlerEnum>,
  28 + default: () => {},
  29 + },
  30 + disabled: {
  31 + type: Boolean,
  32 + },
  33 + title: {
  34 + type: String,
  35 + },
  36 + def: {
  37 + type: Boolean,
  38 + },
  39 + },
  40 + setup(props) {
  41 + const { prefixCls } = useDesign('setting-switch-item');
  42 + const { t } = useI18n();
  43 +
  44 + const getBindValue = computed(() => {
  45 + return props.def ? { checked: props.def } : {};
  46 + });
  47 + function handleChange(e: ChangeEvent) {
  48 + props.event && baseHandler(props.event, e);
  49 + }
  50 + return {
  51 + prefixCls,
  52 + t,
  53 + handleChange,
  54 + getBindValue,
  55 + };
  56 + },
  57 + });
  58 +</script>
  59 +<style lang="less" scoped>
  60 + @import (reference) '../../../../design/index.less';
  61 + @prefix-cls: ~'@{namespace}-setting-switch-item';
  62 +
  63 + .@{prefix-cls} {
  64 + display: flex;
  65 + justify-content: space-between;
  66 + margin: 16px 0;
  67 + }
  68 +</style>
... ...
src/layouts/default/setting/components/ThemePicker.vue 0 → 100644
  1 +<template>
  2 + <div :class="prefixCls">
  3 + <template v-for="color in colorList || []" :key="color">
  4 + <span
  5 + @click="handleClick(color)"
  6 + :class="[
  7 + `${prefixCls}__item`,
  8 + {
  9 + [`${prefixCls}__item--active`]: def === color,
  10 + },
  11 + ]"
  12 + :style="{ background: color }"
  13 + >
  14 + <CheckOutlined />
  15 + </span>
  16 + </template>
  17 + </div>
  18 +</template>
  19 +<script lang="ts">
  20 + import { defineComponent, PropType } from 'vue';
  21 + import { CheckOutlined } from '@ant-design/icons-vue';
  22 +
  23 + import { useDesign } from '/@/hooks/web/useDesign';
  24 +
  25 + import { baseHandler } from '../handler';
  26 + import { HandlerEnum } from '../enum';
  27 +
  28 + export default defineComponent({
  29 + name: 'ThemePicker',
  30 + components: { CheckOutlined },
  31 + props: {
  32 + colorList: {
  33 + type: Array as PropType<string[]>,
  34 + defualt: [],
  35 + },
  36 + event: {
  37 + type: Number as PropType<HandlerEnum>,
  38 + default: () => {},
  39 + },
  40 + def: {
  41 + type: String,
  42 + },
  43 + },
  44 + setup(props) {
  45 + const { prefixCls } = useDesign('setting-theme-picker');
  46 +
  47 + function handleClick(color: string) {
  48 + props.event && baseHandler(props.event, color);
  49 + }
  50 + return {
  51 + prefixCls,
  52 + handleClick,
  53 + };
  54 + },
  55 + });
  56 +</script>
  57 +<style lang="less">
  58 + @import (reference) '../../../../design/index.less';
  59 + @prefix-cls: ~'@{namespace}-setting-theme-picker';
  60 +
  61 + .@{prefix-cls} {
  62 + display: flex;
  63 + flex-wrap: wrap;
  64 + margin: 16px 0;
  65 + justify-content: space-around;
  66 +
  67 + &__item {
  68 + width: 20px;
  69 + height: 20px;
  70 + cursor: pointer;
  71 + border: 1px solid #ddd;
  72 + border-radius: 2px;
  73 +
  74 + svg {
  75 + display: none;
  76 + }
  77 +
  78 + &--active {
  79 + border: 1px solid lighten(@primary-color, 10%);
  80 +
  81 + svg {
  82 + display: inline-block;
  83 + margin: 0 0 3px 3px;
  84 + font-size: 12px;
  85 + fill: @white !important;
  86 + }
  87 + }
  88 + }
  89 + }
  90 +</style>
... ...
src/layouts/default/setting/components/TypePicker.vue 0 → 100644
  1 +<template>
  2 + <div :class="prefixCls">
  3 + <template v-for="item in menuTypeList || []" :key="item.title">
  4 + <Tooltip :title="item.title" placement="bottom">
  5 + <div
  6 + @click="handler(item)"
  7 + :class="[
  8 + `${prefixCls}__item`,
  9 + {
  10 + [`${prefixCls}__item--active`]: def === item.type,
  11 + },
  12 + ]"
  13 + >
  14 + <img :src="item.src" />
  15 + </div>
  16 + </Tooltip>
  17 + </template>
  18 + </div>
  19 +</template>
  20 +<script lang="ts">
  21 + import { defineComponent, PropType } from 'vue';
  22 +
  23 + import { Tooltip } from 'ant-design-vue';
  24 + import { useDesign } from '/@/hooks/web/useDesign';
  25 +
  26 + import { menuTypeList } from '../enum';
  27 + export default defineComponent({
  28 + name: 'MenuTypePicker',
  29 + components: { Tooltip },
  30 + props: {
  31 + menuTypeList: {
  32 + type: Array as PropType<typeof menuTypeList>,
  33 + defualt: [],
  34 + },
  35 + handler: {
  36 + type: Function as PropType<Fn>,
  37 + default: () => {},
  38 + },
  39 + def: {
  40 + type: String,
  41 + },
  42 + },
  43 + setup() {
  44 + const { prefixCls } = useDesign('setting-menu-type-picker');
  45 +
  46 + return {
  47 + prefixCls,
  48 + };
  49 + },
  50 + });
  51 +</script>
  52 +<style lang="less" scoped>
  53 + @import (reference) '../../../../design/index.less';
  54 + @prefix-cls: ~'@{namespace}-setting-menu-type-picker';
  55 +
  56 + .@{prefix-cls} {
  57 + display: flex;
  58 +
  59 + &__item {
  60 + position: relative;
  61 + width: 70px;
  62 + height: 50px;
  63 + margin: 0 20px 20px 0;
  64 + cursor: pointer;
  65 + border-radius: 6px;
  66 +
  67 + &::after {
  68 + position: absolute;
  69 + top: 50%;
  70 + left: 50%;
  71 + width: 0;
  72 + height: 0;
  73 + content: '';
  74 + opacity: 0;
  75 + transition: all 0.3s;
  76 + }
  77 +
  78 + &:hover,
  79 + &--active {
  80 + &::after {
  81 + top: -8px;
  82 + left: -4px;
  83 + width: 80px;
  84 + height: 64px;
  85 + border: 2px solid @primary-color;
  86 + border-radius: 6px;
  87 + opacity: 1;
  88 + }
  89 + }
  90 + }
  91 +
  92 + img {
  93 + width: 100%;
  94 + height: 100%;
  95 + cursor: pointer;
  96 + }
  97 + }
  98 +</style>
... ...
src/layouts/default/setting/components/index.ts 0 → 100644
  1 +import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
  2 +
  3 +export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue'));
  4 +export const ThemePicker = createAsyncComponent(() => import('./ThemePicker.vue'));
  5 +export const SettingFooter = createAsyncComponent(() => import('./SettingFooter.vue'));
  6 +export const SwitchItem = createAsyncComponent(() => import('./SwitchItem.vue'));
  7 +export const SelectItem = createAsyncComponent(() => import('./SelectItem.vue'));
  8 +export const InputNumberItem = createAsyncComponent(() => import('./InputNumberItem.vue'));
... ...
src/layouts/default/setting/index.less deleted 100644 → 0
1   -.setting-drawer {
2   - .ant-drawer-body {
3   - padding-top: 0;
4   - background: @white;
5   - }
6   -
7   - &__footer {
8   - display: flex;
9   - flex-direction: column;
10   - align-items: center;
11   - }
12   -
13   - &__cell-item {
14   - display: flex;
15   - justify-content: space-between;
16   - margin: 16px 0;
17   - }
18   -
19   - &__theme-item {
20   - display: flex;
21   - flex-wrap: wrap;
22   - margin: 16px 0;
23   - justify-content: space-around;
24   -
25   - > span {
26   - width: 20px;
27   - height: 20px;
28   - cursor: pointer;
29   - border: 1px solid #ddd;
30   - border-radius: 2px;
31   -
32   - svg {
33   - display: none;
34   - }
35   -
36   - &.active {
37   - border: 1px solid lighten(@primary-color, 10%);
38   -
39   - svg {
40   - display: inline-block;
41   - margin: 0 0 3px 3px;
42   - font-size: 12px;
43   - fill: @white;
44   - }
45   - }
46   - }
47   - }
48   -
49   - &__siderbar {
50   - display: flex;
51   -
52   - > div {
53   - position: relative;
54   -
55   - .check-icon {
56   - position: absolute;
57   - top: 40%;
58   - left: 40%;
59   - display: none;
60   - color: @primary-color;
61   -
62   - &.active {
63   - display: inline-block;
64   - }
65   - }
66   - }
67   -
68   - img {
69   - margin-right: 10px;
70   - cursor: pointer;
71   - }
72   - }
73   -}
src/layouts/default/setting/index.vue
1 1 <template>
2   - <div @click="openDrawer" class="setting-button">
  2 + <div @click="openDrawer" :class="prefixCls">
3 3 <SettingOutlined />
4 4 <SettingDrawer @register="register" />
5 5 </div>
... ... @@ -10,13 +10,17 @@
10 10 import SettingDrawer from './SettingDrawer';
11 11  
12 12 import { useDrawer } from '/@/components/Drawer';
  13 + import { useDesign } from '/@/hooks/web/useDesign';
13 14  
14 15 export default defineComponent({
15 16 name: 'SettingBtn',
16 17 components: { SettingOutlined, SettingDrawer },
17 18 setup() {
18 19 const [register, { openDrawer }] = useDrawer();
  20 +
  21 + const { prefixCls } = useDesign('setting-button');
19 22 return {
  23 + prefixCls,
20 24 register,
21 25 openDrawer,
22 26 };
... ... @@ -25,9 +29,9 @@
25 29 </script>
26 30 <style lang="less">
27 31 @import (reference) '../../../design/index.less';
28   - @import './index.less';
  32 + @prefix-cls: ~'@{namespace}-setting-button';
29 33  
30   - .setting-button {
  34 + .@{prefix-cls} {
31 35 position: absolute;
32 36 top: 45%;
33 37 right: 0;
... ...