提交 ed41e508 作者: vben

perf(setting-drawer): perf setting-drawer

上级 0362ab26
import type { Plugin } from 'vite';
import ViteHtmlPlugin from 'vite-plugin-html';
import { isProdFn, isSiteMode, ViteEnv } from '../../utils';
import { hmScript } from '../hm';
// @ts-ignore
import pkg from '../../../package.json';
import { GLOB_CONFIG_FILE_NAME } from '../../constant';
export function setupHtmlPlugin(plugins: Plugin[], env: ViteEnv) {
const { VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH } = env;
const htmlPlugin = ViteHtmlPlugin({
// html title
title: VITE_GLOB_APP_TITLE,
minify: isProdFn(),
options: {
// Package and insert additional configuration files
injectConfig: isProdFn()
? `<script src='${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
pkg.version
}-${new Date().getTime()}'></script>`
: '',
// Insert Baidu statistics code
hmScript: isSiteMode() ? hmScript : '',
title: VITE_GLOB_APP_TITLE,
},
});
plugins.push(htmlPlugin);
return plugins;
}
import type { Plugin as VitePlugin } from 'vite'; import type { Plugin as VitePlugin } from 'vite';
import type { Plugin as rollupPlugin } from 'rollup'; import type { Plugin as rollupPlugin } from 'rollup';
import { createMockServer } from 'vite-plugin-mock';
import { VitePWA } from 'vite-plugin-pwa';
import ViteHtmlPlugin from 'vite-plugin-html';
import PurgeIcons from 'vite-plugin-purge-icons'; import PurgeIcons from 'vite-plugin-purge-icons';
import visualizer from 'rollup-plugin-visualizer'; import visualizer from 'rollup-plugin-visualizer';
import gzipPlugin from './gzip/index'; import gzipPlugin from './gzip/index';
import { hmScript } from '../hm';
// @ts-ignore // @ts-ignore
import pkg from '../../../package.json'; import pkg from '../../../package.json';
import { isDevFn, isProdFn, isSiteMode, ViteEnv, isReportMode, isBuildGzip } from '../../utils'; import { isProdFn, isSiteMode, ViteEnv, isReportMode, isBuildGzip } from '../../utils';
import { GLOB_CONFIG_FILE_NAME } from '../../constant'; import { setupHtmlPlugin } from './html';
import { setupPwaPlugin } from './pwa';
import { setupMockPlugin } from './mock';
// gen vite plugins // gen vite plugins
export function createVitePlugins(viteEnv: ViteEnv) { export function createVitePlugins(viteEnv: ViteEnv) {
const { VITE_USE_MOCK, VITE_GLOB_APP_TITLE, VITE_PUBLIC_PATH, VITE_USE_PWA } = viteEnv;
const vitePlugins: VitePlugin[] = []; const vitePlugins: VitePlugin[] = [];
// vite-plugin-html // vite-plugin-html
vitePlugins.push( setupHtmlPlugin(vitePlugins, viteEnv);
ViteHtmlPlugin({ // vite-plugin-pwa
// html title setupPwaPlugin(vitePlugins, viteEnv);
title: VITE_GLOB_APP_TITLE, // vite-plugin-mock
minify: isProdFn(), setupMockPlugin(vitePlugins, viteEnv);
options: {
// Package and insert additional configuration files
injectConfig: isProdFn()
? `<script src='${VITE_PUBLIC_PATH || './'}${GLOB_CONFIG_FILE_NAME}?v=${
pkg.version
}-${new Date().getTime()}'></script>`
: '',
// Insert Baidu statistics code
hmScript: isSiteMode() ? hmScript : '',
title: VITE_GLOB_APP_TITLE,
},
})
);
// vite-plugin-purge-icons // vite-plugin-purge-icons
vitePlugins.push(PurgeIcons()); vitePlugins.push(PurgeIcons());
if (isProdFn() && VITE_USE_PWA) {
vitePlugins.push(
VitePWA({
manifest: {
name: 'Vben Admin',
short_name: 'vben_admin',
icons: [
{
src: './resource/img/pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: './resource/img/pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
],
},
})
);
}
// vite-plugin-mock
if (isDevFn() && VITE_USE_MOCK) {
// open mock
vitePlugins.push(
createMockServer({
ignore: /^\_/,
mockPath: 'mock',
showTime: true,
})
);
}
return vitePlugins; return vitePlugins;
} }
...@@ -86,17 +34,15 @@ export function createVitePlugins(viteEnv: ViteEnv) { ...@@ -86,17 +34,15 @@ export function createVitePlugins(viteEnv: ViteEnv) {
export function createRollupPlugin() { export function createRollupPlugin() {
const rollupPlugins: rollupPlugin[] = []; const rollupPlugins: rollupPlugin[] = [];
if (isProdFn()) { if (!isProdFn() && isReportMode()) {
if (isReportMode()) {
// rollup-plugin-visualizer // rollup-plugin-visualizer
rollupPlugins.push( rollupPlugins.push(visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin);
visualizer({ filename: './build/.cache/stats.html', open: true }) as Plugin
);
} }
if (isBuildGzip() || isSiteMode()) {
if (!isProdFn() && (isBuildGzip() || isSiteMode())) {
// rollup-plugin-gizp // rollup-plugin-gizp
rollupPlugins.push(gzipPlugin()); rollupPlugins.push(gzipPlugin());
} }
}
return rollupPlugins; return rollupPlugins;
} }
import { createMockServer } from 'vite-plugin-mock';
import type { Plugin } from 'vite';
import { isDevFn, ViteEnv } from '../../utils';
export function setupMockPlugin(plugins: Plugin[], env: ViteEnv) {
const { VITE_USE_MOCK } = env;
const mockPlugin = createMockServer({
ignore: /^\_/,
mockPath: 'mock',
showTime: true,
});
if (isDevFn() && VITE_USE_MOCK) {
plugins.push(mockPlugin);
}
return plugins;
}
import { VitePWA } from 'vite-plugin-pwa';
import type { Plugin } from 'vite';
import { isProdFn, ViteEnv } from '../../utils';
export function setupPwaPlugin(plugins: Plugin[], env: ViteEnv) {
const { VITE_USE_PWA } = env;
const pwaPlugin = VitePWA({
manifest: {
name: 'Vben Admin',
short_name: 'vben_admin',
icons: [
{
src: './resource/img/pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: './resource/img/pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
],
},
});
if (isProdFn() && VITE_USE_PWA) {
plugins.push(pwaPlugin);
}
return plugins;
}
...@@ -103,7 +103,7 @@ export default defineComponent({ ...@@ -103,7 +103,7 @@ export default defineComponent({
const isHorizontal = unref(getIsHorizontal) || getSplit.value; const isHorizontal = unref(getIsHorizontal) || getSplit.value;
return { return {
height: isHorizontal ? `calc(100%)` : `calc(100% - ${props.showLogo ? '48px' : '0px'})`, height: isHorizontal ? '100%' : `calc(100% - ${props.showLogo ? '48px' : '0px'})`,
overflowY: isHorizontal ? 'hidden' : 'auto', overflowY: isHorizontal ? 'hidden' : 'auto',
}; };
} }
......
...@@ -25,9 +25,9 @@ export function useI18n(namespace?: string) { ...@@ -25,9 +25,9 @@ export function useI18n(namespace?: string) {
return { return {
...methods, ...methods,
t: (key: string, ...arg: Parameters<typeof t>) => { t: (key: string, ...arg: Partial<Parameters<typeof t>>) => {
if (!key) return ''; if (!key) return '';
return t(getKey(key), ...arg); return t(getKey(key), ...(arg as Parameters<typeof t>));
}, },
}; };
} }
......
import type { ProjectConfig } from '/@/types/config'; import { defineComponent, computed, unref } from 'vue';
import defaultSetting from '/@/settings/projectSetting';
import { defineComponent, computed, unref, FunctionalComponent } from 'vue';
import { BasicDrawer } from '/@/components/Drawer/index'; import { BasicDrawer } from '/@/components/Drawer/index';
import { Divider, Switch, Tooltip, InputNumber, Select } from 'ant-design-vue'; import { Divider } from 'ant-design-vue';
import { Button } from '/@/components/Button'; import {
import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue'; TypePicker,
ThemePicker,
SettingFooter,
SwitchItem,
SelectItem,
InputNumberItem,
} from './components';
import { MenuTypeEnum } from '/@/enums/menuEnum'; import { MenuTypeEnum } from '/@/enums/menuEnum';
import { appStore } from '/@/store/modules/app';
import { useMessage } from '/@/hooks/web/useMessage';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import { useRootSetting } from '/@/hooks/setting/useRootSetting'; import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
...@@ -20,8 +19,6 @@ import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; ...@@ -20,8 +19,6 @@ import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
import { baseHandler } from './handler'; import { baseHandler } from './handler';
import { import {
...@@ -35,146 +32,8 @@ import { ...@@ -35,146 +32,8 @@ import {
import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST } from '/@/settings/colorSetting'; import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST } from '/@/settings/colorSetting';
interface SwitchOptions {
config?: DeepPartial<ProjectConfig>;
def?: any;
disabled?: boolean;
handler?: Fn;
}
interface SelectConfig {
options?: LabelValueOptions;
def?: any;
disabled?: boolean;
handler?: Fn;
}
interface ThemePickerProps {
colorList: string[];
handler: Fn;
def: string;
}
const { createSuccessModal, createMessage } = useMessage();
const { t } = useI18n(); const { t } = useI18n();
/**
* Menu type Picker comp
*/
const MenuTypePicker: FunctionalComponent = () => {
const { getIsHorizontal, getMenuType } = useMenuSetting();
return (
<div class={`setting-drawer__siderbar`}>
{menuTypeList.map((item) => {
const { title, type: ItemType, mode, src } = item;
return (
<Tooltip title={title} placement="bottom" key={title}>
{{
default: () => (
<div
onClick={baseHandler.bind(null, HandlerEnum.CHANGE_LAYOUT, {
mode: mode,
type: ItemType,
split: unref(getIsHorizontal) ? false : undefined,
})}
>
<CheckOutlined
class={['check-icon', unref(getMenuType) === ItemType ? 'active' : '']}
/>
<img src={src} />
</div>
),
}}
</Tooltip>
);
})}
</div>
);
};
const ThemePicker: FunctionalComponent<ThemePickerProps> = (props) => {
return (
<div class={`setting-drawer__theme-item`}>
{props.colorList.map((color) => {
return (
<span
onClick={() => props.handler?.(color)}
key={color}
class={[props.def === color ? 'active' : '']}
style={{
background: color,
}}
>
<CheckOutlined class="icon" />
</span>
);
})}
</div>
);
};
/**
* FooterButton component
*/
const FooterButton: FunctionalComponent = () => {
const { getRootSetting } = useRootSetting();
function handleCopy() {
const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
unref(isSuccessRef) &&
createSuccessModal({
title: t('layout.setting.operatingTitle'),
content: t('layout.setting.operatingContent'),
});
}
function handleResetSetting() {
try {
appStore.commitProjectConfigState(defaultSetting);
const { colorWeak, grayMode } = defaultSetting;
// updateTheme(themeColor);
updateColorWeak(colorWeak);
updateGrayMode(grayMode);
createMessage.success(t('layout.setting.resetSuccess'));
} catch (error) {
createMessage.error(error);
}
}
function handleClearAndRedo() {
localStorage.clear();
appStore.resumeAllState();
location.reload();
}
return (
<div class="setting-drawer__footer">
<Button type="primary" block onClick={handleCopy}>
{() => (
<>
<CopyOutlined class="mr-2" />
{t('layout.setting.copyBtn')}
</>
)}
</Button>
<Button block class="mt-2" onClick={handleResetSetting} color="warning">
{() => (
<>
<RedoOutlined class="mr-2" />
{t('layout.setting.resetBtn')}
</>
)}
</Button>
<Button block class="mt-2" onClick={handleClearAndRedo} color="error">
{() => (
<>
<RedoOutlined class="mr-2" />
{t('layout.setting.clearBtn')}
</>
)}
</Button>
</div>
);
};
export default defineComponent({ export default defineComponent({
name: 'SettingDrawer', name: 'SettingDrawer',
setup(_, { attrs }) { setup(_, { attrs }) {
...@@ -187,6 +46,7 @@ export default defineComponent({ ...@@ -187,6 +46,7 @@ export default defineComponent({
getFullContent, getFullContent,
getColorWeak, getColorWeak,
getGrayMode, getGrayMode,
getLockTime,
} = useRootSetting(); } = useRootSetting();
const { const {
...@@ -229,38 +89,44 @@ export default defineComponent({ ...@@ -229,38 +89,44 @@ export default defineComponent({
function renderSidebar() { function renderSidebar() {
return ( return (
<> <>
<MenuTypePicker /> <TypePicker
{renderSwitchItem(t('layout.setting.splitMenu'), { menuTypeList={menuTypeList}
handler: (e) => { handler={(item: typeof menuTypeList[0]) => {
baseHandler(HandlerEnum.MENU_SPLIT, e); baseHandler(HandlerEnum.CHANGE_LAYOUT, {
}, mode: item.mode,
def: unref(getSplit), type: item.type,
disabled: !unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX, split: unref(getIsHorizontal) ? false : undefined,
})} });
}}
def={unref(getMenuType)}
/>
<SwitchItem
title={t('layout.setting.splitMenu')}
event={HandlerEnum.MENU_SPLIT}
def={unref(getSplit)}
disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
/>
</> </>
); );
} }
function renderTheme() { function renderHeaderTheme() {
return ( return (
<>
<Divider>{() => t('layout.setting.headerTheme')}</Divider>
<ThemePicker <ThemePicker
colorList={HEADER_PRESET_BG_COLOR_LIST} colorList={HEADER_PRESET_BG_COLOR_LIST}
def={unref(getHeaderBgColor)} def={unref(getHeaderBgColor)}
handler={(e) => { event={HandlerEnum.HEADER_THEME}
baseHandler(HandlerEnum.HEADER_THEME, e);
}}
/> />
<Divider>{() => t('layout.setting.sidebarTheme')}</Divider> );
}
function renderSiderTheme() {
return (
<ThemePicker <ThemePicker
colorList={SIDE_BAR_BG_COLOR_LIST} colorList={SIDE_BAR_BG_COLOR_LIST}
def={unref(getMenuBgColor)} def={unref(getMenuBgColor)}
handler={(e) => { event={HandlerEnum.MENU_THEME}
baseHandler(HandlerEnum.MENU_THEME, e);
}}
/> />
</>
); );
} }
...@@ -268,264 +134,192 @@ export default defineComponent({ ...@@ -268,264 +134,192 @@ export default defineComponent({
* @description: * @description:
*/ */
function renderFeatures() { function renderFeatures() {
return [ return (
renderSwitchItem(t('layout.setting.menuDrag'), { <>
handler: (e) => { <SwitchItem
baseHandler(HandlerEnum.MENU_HAS_DRAG, e); title={t('layout.setting.menuDrag')}
}, event={HandlerEnum.MENU_HAS_DRAG}
def: unref(getCanDrag), def={unref(getCanDrag)}
disabled: !unref(getShowMenuRef), disabled={!unref(getShowMenuRef)}
}), />
renderSwitchItem(t('layout.setting.menuSearch'), { <SwitchItem
handler: (e) => { title={t('layout.setting.menuSearch')}
baseHandler(HandlerEnum.HEADER_SEARCH, e); event={HandlerEnum.HEADER_SEARCH}
}, def={unref(getShowSearch)}
def: unref(getShowSearch), disabled={!unref(getShowHeader)}
disabled: !unref(getShowHeader), />
}), <SwitchItem
renderSwitchItem(t('layout.setting.menuAccordion'), { title={t('layout.setting.menuAccordion')}
handler: (e) => { event={HandlerEnum.MENU_ACCORDION}
baseHandler(HandlerEnum.MENU_ACCORDION, e); def={unref(getAccordion)}
}, disabled={!unref(getShowMenuRef)}
def: unref(getAccordion), />
disabled: !unref(getShowMenuRef), <SwitchItem
}), title={t('layout.setting.menuCollapse')}
renderSwitchItem(t('layout.setting.menuCollapse'), { event={HandlerEnum.MENU_COLLAPSED}
handler: (e) => { def={unref(getCollapsed)}
baseHandler(HandlerEnum.MENU_COLLAPSED, e); disabled={!unref(getShowMenuRef)}
}, />
def: unref(getCollapsed), <SwitchItem
disabled: !unref(getShowMenuRef), title={t('layout.setting.collapseMenuDisplayName')}
}), event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE}
renderSwitchItem(t('layout.setting.collapseMenuDisplayName'), { def={unref(getCollapsedShowTitle)}
handler: (e) => { disabled={!unref(getShowMenuRef) || !unref(getCollapsed)}
baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e); />
}, <SwitchItem
def: unref(getCollapsedShowTitle), title={t('layout.setting.fixedHeader')}
disabled: !unref(getShowMenuRef) || !unref(getCollapsed), event={HandlerEnum.HEADER_FIXED}
}), def={unref(getHeaderFixed)}
renderSwitchItem(t('layout.setting.fixedHeader'), { disabled={!unref(getShowHeader)}
handler: (e) => { />
baseHandler(HandlerEnum.HEADER_FIXED, e); <SwitchItem
}, title={t('layout.setting.fixedSideBar')}
def: unref(getHeaderFixed), event={HandlerEnum.MENU_FIXED}
disabled: !unref(getShowHeader), def={unref(getMenuFixed)}
}), disabled={!unref(getShowMenuRef)}
renderSwitchItem(t('layout.setting.fixedSideBar'), { />
handler: (e) => { <SelectItem
baseHandler(HandlerEnum.MENU_FIXED, e); title={t('layout.setting.topMenuLayout')}
}, event={HandlerEnum.MENU_TOP_ALIGN}
def: unref(getMenuFixed), def={unref(getTopMenuAlign)}
disabled: !unref(getShowMenuRef), options={topMenuAlignOptions}
}), disabled={!unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit))}
renderSelectItem(t('layout.setting.topMenuLayout'), { />
handler: (e) => { <SelectItem
baseHandler(HandlerEnum.MENU_TOP_ALIGN, e); title={t('layout.setting.menuCollapseButton')}
}, event={HandlerEnum.MENU_TRIGGER}
def: unref(getTopMenuAlign), def={unref(getTrigger)}
options: topMenuAlignOptions, options={menuTriggerOptions}
disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)), disabled={!unref(getShowMenuRef)}
}), />
renderSelectItem(t('layout.setting.menuCollapseButton'), { <SelectItem
handler: (e) => { title={t('layout.setting.contentMode')}
baseHandler(HandlerEnum.MENU_TRIGGER, e); event={HandlerEnum.CONTENT_MODE}
}, def={unref(getContentMode)}
disabled: !unref(getShowMenuRef), options={contentModeOptions}
def: unref(getTrigger), />
options: menuTriggerOptions, <InputNumberItem
}), title={t('layout.setting.autoScreenLock')}
renderSelectItem(t('layout.setting.contentMode'), {
handler: (e) => {
baseHandler(HandlerEnum.CONTENT_MODE, e);
},
def: unref(getContentMode),
options: contentModeOptions,
}),
<div class={`setting-drawer__cell-item`}>
<span>{t('layout.setting.autoScreenLock')}</span>
<InputNumber
style="width:126px"
size="small"
min={0} min={0}
onChange={(e: any) => { event={HandlerEnum.LOCK_TIME}
baseHandler(HandlerEnum.LOCK_TIME, e); defaultValue={unref(getLockTime)}
}}
defaultValue={appStore.getProjectConfig.lockTime}
formatter={(value: string) => { formatter={(value: string) => {
if (parseInt(value) === 0) { return parseInt(value) === 0
return `0(${t('layout.setting.notAutoScreenLock')})`; ? `0(${t('layout.setting.notAutoScreenLock')})`
} : `${value}${t('layout.setting.minute')}`;
return `${value}${t('layout.setting.minute')}`;
}} }}
/> />
</div>, <InputNumberItem
<div class={`setting-drawer__cell-item`}> title={t('layout.setting.expandedMenuWidth')}
<span>{t('layout.setting.expandedMenuWidth')}</span>
<InputNumber
style="width:126px"
size="small"
max={600} max={600}
min={100} min={100}
step={10} step={10}
event={HandlerEnum.MENU_WIDTH}
disabled={!unref(getShowMenuRef)} disabled={!unref(getShowMenuRef)}
defaultValue={unref(getMenuWidth)} defaultValue={unref(getMenuWidth)}
formatter={(value: string) => `${parseInt(value)}px`} formatter={(value: string) => `${parseInt(value)}px`}
onChange={(e: any) => {
baseHandler(HandlerEnum.MENU_WIDTH, e);
}}
/> />
</div>, </>
]; );
} }
function renderContent() { function renderContent() {
return [
renderSwitchItem(t('layout.setting.breadcrumb'), {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
},
def: unref(getShowBreadCrumb),
disabled: !unref(getShowHeader),
}),
renderSwitchItem(t('layout.setting.breadcrumbIcon'), {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
},
def: unref(getShowBreadCrumbIcon),
disabled: !unref(getShowHeader),
}),
renderSwitchItem(t('layout.setting.tabs'), {
handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW, e);
},
def: unref(getShowMultipleTab),
}),
renderSwitchItem(t('layout.setting.tabsQuickBtn'), {
handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
},
def: unref(getShowQuick),
disabled: !unref(getShowMultipleTab),
}),
renderSwitchItem(t('layout.setting.sidebar'), {
handler: (e) => {
baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
},
def: unref(getShowMenu),
disabled: unref(getIsHorizontal),
}),
renderSwitchItem(t('layout.setting.header'), {
handler: (e) => {
baseHandler(HandlerEnum.HEADER_SHOW, e);
},
def: unref(getShowHeader),
}),
renderSwitchItem('Logo', {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_LOGO, e);
},
def: unref(getShowLogo),
}),
renderSwitchItem(t('layout.setting.footer'), {
handler: (e) => {
baseHandler(HandlerEnum.SHOW_FOOTER, e);
},
def: unref(getShowFooter),
}),
renderSwitchItem(t('layout.setting.fullContent'), {
handler: (e) => {
baseHandler(HandlerEnum.FULL_CONTENT, e);
},
def: unref(getFullContent),
}),
renderSwitchItem(t('layout.setting.grayMode'), {
handler: (e) => {
baseHandler(HandlerEnum.GRAY_MODE, e);
},
def: unref(getGrayMode),
}),
renderSwitchItem(t('layout.setting.colorWeak'), {
handler: (e) => {
baseHandler(HandlerEnum.COLOR_WEAK, e);
},
def: unref(getColorWeak),
}),
];
}
function renderTransition() {
return ( return (
<> <>
{renderSwitchItem(t('layout.setting.progress'), { <SwitchItem
handler: (e) => { title={t('layout.setting.breadcrumb')}
baseHandler(HandlerEnum.OPEN_PROGRESS, e); event={HandlerEnum.SHOW_BREADCRUMB}
}, def={unref(getShowBreadCrumb)}
def: unref(getOpenNProgress), disabled={!unref(getShowHeader)}
})} />
{renderSwitchItem(t('layout.setting.switchLoading'), {
handler: (e) => {
baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e);
},
def: unref(getOpenPageLoading),
})}
{renderSwitchItem(t('layout.setting.switchAnimation'), { <SwitchItem
handler: (e) => { title={t('layout.setting.breadcrumbIcon')}
baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e); event={HandlerEnum.SHOW_BREADCRUMB_ICON}
}, def={unref(getShowBreadCrumbIcon)}
def: unref(getEnableTransition), disabled={!unref(getShowHeader)}
})} />
{renderSelectItem(t('layout.setting.animationType'), { <SwitchItem
handler: (e) => { title={t('layout.setting.tabs')}
baseHandler(HandlerEnum.ROUTER_TRANSITION, e); event={HandlerEnum.TABS_SHOW}
}, def={unref(getShowMultipleTab)}
def: unref(getBasicTransition), />
options: routerTransitionOptions,
disabled: !unref(getEnableTransition), <SwitchItem
})} title={t('layout.setting.tabsQuickBtn')}
event={HandlerEnum.TABS_SHOW_QUICK}
def={unref(getShowQuick)}
disabled={!unref(getShowMultipleTab)}
/>
<SwitchItem
title={t('layout.setting.sidebar')}
event={HandlerEnum.MENU_SHOW_SIDEBAR}
def={unref(getShowMenu)}
disabled={unref(getIsHorizontal)}
/>
<SwitchItem
title={t('layout.setting.header')}
event={HandlerEnum.HEADER_SHOW}
def={unref(getShowHeader)}
/>
<SwitchItem title="Logo" event={HandlerEnum.SHOW_LOGO} def={unref(getShowLogo)} />
<SwitchItem
title={t('layout.setting.footer')}
event={HandlerEnum.SHOW_FOOTER}
def={unref(getShowFooter)}
/>
<SwitchItem
title={t('layout.setting.fullContent')}
event={HandlerEnum.FULL_CONTENT}
def={unref(getFullContent)}
/>
<SwitchItem
title={t('layout.setting.grayMode')}
event={HandlerEnum.GRAY_MODE}
def={unref(getGrayMode)}
/>
<SwitchItem
title={t('layout.setting.colorWeak')}
event={HandlerEnum.COLOR_WEAK}
def={unref(getColorWeak)}
/>
</> </>
); );
} }
function renderSelectItem(text: string, config?: SelectConfig) { function renderTransition() {
const { handler, def, disabled = false, options } = config || {};
const opt = def ? { value: def, defaultValue: def } : {};
return ( return (
<div class={`setting-drawer__cell-item`}> <>
<span>{text}</span> <SwitchItem
<Select title={t('layout.setting.progress')}
{...opt} event={HandlerEnum.OPEN_PROGRESS}
disabled={disabled} def={unref(getOpenNProgress)}
size="small" />
style={{ width: '126px' }} <SwitchItem
onChange={(e) => { title={t('layout.setting.switchLoading')}
handler && handler(e); event={HandlerEnum.OPEN_PAGE_LOADING}
}} def={unref(getOpenPageLoading)}
options={options}
/> />
</div>
);
}
function renderSwitchItem(text: string, options?: SwitchOptions) { <SwitchItem
const { handler, def, disabled = false } = options || {}; title={t('layout.setting.switchAnimation')}
const opt = def ? { checked: def } : {}; event={HandlerEnum.OPEN_ROUTE_TRANSITION}
return ( def={unref(getEnableTransition)}
<div class={`setting-drawer__cell-item`}> />
<span>{text}</span>
<Switch <SelectItem
{...opt} title={t('layout.setting.animationType')}
disabled={disabled} event={HandlerEnum.ROUTER_TRANSITION}
onChange={(e: any) => { def={unref(getBasicTransition)}
handler && handler(e); options={routerTransitionOptions}
}} disabled={!unref(getEnableTransition)}
checkedChildren={t('layout.setting.on')}
unCheckedChildren={t('layout.setting.off')}
/> />
</div> </>
); );
} }
...@@ -541,7 +335,10 @@ export default defineComponent({ ...@@ -541,7 +335,10 @@ export default defineComponent({
<> <>
<Divider>{() => t('layout.setting.navMode')}</Divider> <Divider>{() => t('layout.setting.navMode')}</Divider>
{renderSidebar()} {renderSidebar()}
{renderTheme()} <Divider>{() => t('layout.setting.headerTheme')}</Divider>
{renderHeaderTheme()}
<Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
{renderSiderTheme()}
<Divider>{() => t('layout.setting.interfaceFunction')}</Divider> <Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
{renderFeatures()} {renderFeatures()}
<Divider>{() => t('layout.setting.interfaceDisplay')}</Divider> <Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
...@@ -549,7 +346,7 @@ export default defineComponent({ ...@@ -549,7 +346,7 @@ export default defineComponent({
<Divider>{() => t('layout.setting.animation')}</Divider> <Divider>{() => t('layout.setting.animation')}</Divider>
{renderTransition()} {renderTransition()}
<Divider /> <Divider />
<FooterButton /> <SettingFooter />
</> </>
), ),
}} }}
......
<template>
<div :class="prefixCls">
<span> {{ title }}</span>
<InputNumber
v-bind="$attrs"
size="small"
:class="`${prefixCls}-input-number`"
@change="handleChange"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { InputNumber } from 'ant-design-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { baseHandler } from '../handler';
import { HandlerEnum } from '../enum';
export default defineComponent({
name: 'InputNumberItem',
components: { InputNumber },
props: {
event: {
type: Number as PropType<HandlerEnum>,
default: () => {},
},
title: {
type: String,
},
},
setup(props) {
const { prefixCls } = useDesign('setting-input-number-item');
function handleChange(e: ChangeEvent) {
props.event && baseHandler(props.event, e);
}
return {
prefixCls,
handleChange,
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-setting-input-number-item';
.@{prefix-cls} {
display: flex;
justify-content: space-between;
margin: 16px 0;
&-input-number {
width: 126px;
}
}
</style>
<template>
<div :class="prefixCls">
<span> {{ title }}</span>
<Select
v-bind="getBindValue"
:class="`${prefixCls}-select`"
@change="handleChange"
:disabled="disabled"
size="small"
:options="options"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from 'vue';
import { Select } from 'ant-design-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { baseHandler } from '../handler';
import { HandlerEnum } from '../enum';
export default defineComponent({
name: 'SelectItem',
components: { Select },
props: {
event: {
type: Number as PropType<HandlerEnum>,
default: () => {},
},
disabled: {
type: Boolean,
},
title: {
type: String,
},
def: {
type: [String, Number] as PropType<string | number>,
},
initValue: {
type: [String, Number] as PropType<string | number>,
},
options: {
type: Array as PropType<LabelValueOptions>,
default: [],
},
},
setup(props) {
const { prefixCls } = useDesign('setting-select-item');
const getBindValue = computed(() => {
return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
});
function handleChange(e: ChangeEvent) {
props.event && baseHandler(props.event, e);
}
return {
prefixCls,
handleChange,
getBindValue,
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-setting-select-item';
.@{prefix-cls} {
display: flex;
justify-content: space-between;
margin: 16px 0;
&-select {
width: 126px;
}
}
</style>
<template>
<div :class="prefixCls">
<a-button type="primary" block @click="handleCopy">
<CopyOutlined class="mr-2" />
{{ t('layout.setting.copyBtn') }}
</a-button>
<a-button color="warning" block @click="handleResetSetting" class="my-3">
<RedoOutlined class="mr-2" />
{{ t('layout.setting.resetBtn') }}
</a-button>
<a-button color="error" block @click="handleClearAndRedo">
<RedoOutlined class="mr-2" />
{{ t('layout.setting.clearBtn') }}
</a-button>
</div>
</template>
<script lang="ts">
import { defineComponent, unref } from 'vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
import { appStore } from '/@/store/modules/app';
import defaultSetting from '/@/settings/projectSetting';
import { useMessage } from '/@/hooks/web/useMessage';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
export default defineComponent({
name: 'SettingFooter',
components: { CopyOutlined, RedoOutlined },
setup() {
const { getRootSetting } = useRootSetting();
const { prefixCls } = useDesign('setting-footer');
const { t } = useI18n();
const { createSuccessModal, createMessage } = useMessage();
function handleCopy() {
const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
unref(isSuccessRef) &&
createSuccessModal({
title: t('layout.setting.operatingTitle'),
content: t('layout.setting.operatingContent'),
});
}
function handleResetSetting() {
try {
appStore.commitProjectConfigState(defaultSetting);
const { colorWeak, grayMode } = defaultSetting;
// updateTheme(themeColor);
updateColorWeak(colorWeak);
updateGrayMode(grayMode);
createMessage.success(t('layout.setting.resetSuccess'));
} catch (error) {
createMessage.error(error);
}
}
function handleClearAndRedo() {
localStorage.clear();
appStore.resumeAllState();
location.reload();
}
return {
prefixCls,
t,
handleCopy,
handleResetSetting,
handleClearAndRedo,
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-setting-footer';
.@{prefix-cls} {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
<template>
<div :class="prefixCls">
<span> {{ title }}</span>
<Switch
v-bind="getBindValue"
@change="handleChange"
:disabled="disabled"
:checkedChildren="t('layout.setting.on')"
:unCheckedChildren="t('layout.setting.off')"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from 'vue';
import { Switch } from 'ant-design-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
import { baseHandler } from '../handler';
import { HandlerEnum } from '../enum';
export default defineComponent({
name: 'SwitchItem',
components: { Switch },
props: {
event: {
type: Number as PropType<HandlerEnum>,
default: () => {},
},
disabled: {
type: Boolean,
},
title: {
type: String,
},
def: {
type: Boolean,
},
},
setup(props) {
const { prefixCls } = useDesign('setting-switch-item');
const { t } = useI18n();
const getBindValue = computed(() => {
return props.def ? { checked: props.def } : {};
});
function handleChange(e: ChangeEvent) {
props.event && baseHandler(props.event, e);
}
return {
prefixCls,
t,
handleChange,
getBindValue,
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-setting-switch-item';
.@{prefix-cls} {
display: flex;
justify-content: space-between;
margin: 16px 0;
}
</style>
<template>
<div :class="prefixCls">
<template v-for="color in colorList || []" :key="color">
<span
@click="handleClick(color)"
:class="[
`${prefixCls}__item`,
{
[`${prefixCls}__item--active`]: def === color,
},
]"
:style="{ background: color }"
>
<CheckOutlined />
</span>
</template>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { CheckOutlined } from '@ant-design/icons-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { baseHandler } from '../handler';
import { HandlerEnum } from '../enum';
export default defineComponent({
name: 'ThemePicker',
components: { CheckOutlined },
props: {
colorList: {
type: Array as PropType<string[]>,
defualt: [],
},
event: {
type: Number as PropType<HandlerEnum>,
default: () => {},
},
def: {
type: String,
},
},
setup(props) {
const { prefixCls } = useDesign('setting-theme-picker');
function handleClick(color: string) {
props.event && baseHandler(props.event, color);
}
return {
prefixCls,
handleClick,
};
},
});
</script>
<style lang="less">
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-setting-theme-picker';
.@{prefix-cls} {
display: flex;
flex-wrap: wrap;
margin: 16px 0;
justify-content: space-around;
&__item {
width: 20px;
height: 20px;
cursor: pointer;
border: 1px solid #ddd;
border-radius: 2px;
svg {
display: none;
}
&--active {
border: 1px solid lighten(@primary-color, 10%);
svg {
display: inline-block;
margin: 0 0 3px 3px;
font-size: 12px;
fill: @white !important;
}
}
}
}
</style>
<template>
<div :class="prefixCls">
<template v-for="item in menuTypeList || []" :key="item.title">
<Tooltip :title="item.title" placement="bottom">
<div
@click="handler(item)"
:class="[
`${prefixCls}__item`,
{
[`${prefixCls}__item--active`]: def === item.type,
},
]"
>
<img :src="item.src" />
</div>
</Tooltip>
</template>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { Tooltip } from 'ant-design-vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { menuTypeList } from '../enum';
export default defineComponent({
name: 'MenuTypePicker',
components: { Tooltip },
props: {
menuTypeList: {
type: Array as PropType<typeof menuTypeList>,
defualt: [],
},
handler: {
type: Function as PropType<Fn>,
default: () => {},
},
def: {
type: String,
},
},
setup() {
const { prefixCls } = useDesign('setting-menu-type-picker');
return {
prefixCls,
};
},
});
</script>
<style lang="less" scoped>
@import (reference) '../../../../design/index.less';
@prefix-cls: ~'@{namespace}-setting-menu-type-picker';
.@{prefix-cls} {
display: flex;
&__item {
position: relative;
width: 70px;
height: 50px;
margin: 0 20px 20px 0;
cursor: pointer;
border-radius: 6px;
&::after {
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
content: '';
opacity: 0;
transition: all 0.3s;
}
&:hover,
&--active {
&::after {
top: -8px;
left: -4px;
width: 80px;
height: 64px;
border: 2px solid @primary-color;
border-radius: 6px;
opacity: 1;
}
}
}
img {
width: 100%;
height: 100%;
cursor: pointer;
}
}
</style>
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
export const TypePicker = createAsyncComponent(() => import('./TypePicker.vue'));
export const ThemePicker = createAsyncComponent(() => import('./ThemePicker.vue'));
export const SettingFooter = createAsyncComponent(() => import('./SettingFooter.vue'));
export const SwitchItem = createAsyncComponent(() => import('./SwitchItem.vue'));
export const SelectItem = createAsyncComponent(() => import('./SelectItem.vue'));
export const InputNumberItem = createAsyncComponent(() => import('./InputNumberItem.vue'));
.setting-drawer {
.ant-drawer-body {
padding-top: 0;
background: @white;
}
&__footer {
display: flex;
flex-direction: column;
align-items: center;
}
&__cell-item {
display: flex;
justify-content: space-between;
margin: 16px 0;
}
&__theme-item {
display: flex;
flex-wrap: wrap;
margin: 16px 0;
justify-content: space-around;
> span {
width: 20px;
height: 20px;
cursor: pointer;
border: 1px solid #ddd;
border-radius: 2px;
svg {
display: none;
}
&.active {
border: 1px solid lighten(@primary-color, 10%);
svg {
display: inline-block;
margin: 0 0 3px 3px;
font-size: 12px;
fill: @white;
}
}
}
}
&__siderbar {
display: flex;
> div {
position: relative;
.check-icon {
position: absolute;
top: 40%;
left: 40%;
display: none;
color: @primary-color;
&.active {
display: inline-block;
}
}
}
img {
margin-right: 10px;
cursor: pointer;
}
}
}
<template> <template>
<div @click="openDrawer" class="setting-button"> <div @click="openDrawer" :class="prefixCls">
<SettingOutlined /> <SettingOutlined />
<SettingDrawer @register="register" /> <SettingDrawer @register="register" />
</div> </div>
...@@ -10,13 +10,17 @@ ...@@ -10,13 +10,17 @@
import SettingDrawer from './SettingDrawer'; import SettingDrawer from './SettingDrawer';
import { useDrawer } from '/@/components/Drawer'; import { useDrawer } from '/@/components/Drawer';
import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({ export default defineComponent({
name: 'SettingBtn', name: 'SettingBtn',
components: { SettingOutlined, SettingDrawer }, components: { SettingOutlined, SettingDrawer },
setup() { setup() {
const [register, { openDrawer }] = useDrawer(); const [register, { openDrawer }] = useDrawer();
const { prefixCls } = useDesign('setting-button');
return { return {
prefixCls,
register, register,
openDrawer, openDrawer,
}; };
...@@ -25,9 +29,9 @@ ...@@ -25,9 +29,9 @@
</script> </script>
<style lang="less"> <style lang="less">
@import (reference) '../../../design/index.less'; @import (reference) '../../../design/index.less';
@import './index.less'; @prefix-cls: ~'@{namespace}-setting-button';
.setting-button { .@{prefix-cls} {
position: absolute; position: absolute;
top: 45%; top: 45%;
right: 0; right: 0;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论