350 lines
10 KiB
Vue
350 lines
10 KiB
Vue
|
<template>
|
|||
|
<h-drawer
|
|||
|
:visible="visible"
|
|||
|
:width="300"
|
|||
|
:getContainer="getContainer"
|
|||
|
@close="() => setShow(false)"
|
|||
|
style="z-index: 99"
|
|||
|
placement="right"
|
|||
|
>
|
|||
|
<template #handle>
|
|||
|
<div :class="`${prefixCls}-handle`" @click="handleClickShowButton">
|
|||
|
<close-outlined v-if="visible" :style="iconStyle" />
|
|||
|
<setting-outlined v-else :style="iconStyle" />
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<div :class="`${prefixCls}-content`">
|
|||
|
<body-wrapper key="pageStyle" :title="t('app.setting.pagestyle')">
|
|||
|
<block-checkbox
|
|||
|
:value="value.navTheme"
|
|||
|
:list="themeList.themeList"
|
|||
|
@change="val => handleChange('theme', val)"
|
|||
|
/>
|
|||
|
</body-wrapper>
|
|||
|
|
|||
|
<h-divider />
|
|||
|
|
|||
|
<body-wrapper key="mode" :title="t('app.setting.navigationmode')">
|
|||
|
<block-checkbox
|
|||
|
:value="value.layout"
|
|||
|
@change="val => handleChange('layout', val)"
|
|||
|
></block-checkbox>
|
|||
|
</body-wrapper>
|
|||
|
|
|||
|
<layout-change
|
|||
|
:contentWidth="value.contentWidth"
|
|||
|
:fixedHeader="value.fixedHeader"
|
|||
|
:fixSiderbar="value.fixSidebar"
|
|||
|
:layout="value.layout"
|
|||
|
:splitMenus="value.splitMenus"
|
|||
|
@change="({ type, value }) => handleChange(type, value)"
|
|||
|
/>
|
|||
|
|
|||
|
<h-divider />
|
|||
|
|
|||
|
<body-wrapper :title="t('app.setting.othersettings')">
|
|||
|
<h-list :split="false">
|
|||
|
<h-list-item>
|
|||
|
<span style="opacity: 1">{{ t('app.setting.transitionname') }}</span>
|
|||
|
<template #actions>
|
|||
|
<h-select
|
|||
|
size="small"
|
|||
|
style="width: 100px"
|
|||
|
:value="value.transitionName || 'null'"
|
|||
|
@change="val => handleChange('transition', val)"
|
|||
|
>
|
|||
|
<h-select-option value="null">Null</h-select-option>
|
|||
|
<h-select-option value="slide-fadein-up">Slide Up</h-select-option>
|
|||
|
<h-select-option value="slide-fadein-right">Slide Right</h-select-option>
|
|||
|
<h-select-option value="fadein">Fade In</h-select-option>
|
|||
|
<h-select-option value="zoom-fadein">Zoom</h-select-option>
|
|||
|
</h-select>
|
|||
|
</template>
|
|||
|
</h-list-item>
|
|||
|
|
|||
|
<h-tooltip>
|
|||
|
<h-list-item>
|
|||
|
<span style="opacity: 1">{{ t('app.setting.multitab') }}</span>
|
|||
|
<template #actions>
|
|||
|
<h-switch
|
|||
|
size="small"
|
|||
|
:checked="value.multiTab"
|
|||
|
@change="() => handleChange('multiTab', !value.multiTab)"
|
|||
|
/>
|
|||
|
</template>
|
|||
|
</h-list-item>
|
|||
|
</h-tooltip>
|
|||
|
|
|||
|
<h-tooltip placement="left" :title="t('app.setting.multitab.fixed.hit')">
|
|||
|
<h-list-item>
|
|||
|
<span :style="{ opacity: !value.multiTab ? '0.5' : '1' }">
|
|||
|
{{ t('app.setting.multitab.fixed') }}
|
|||
|
</span>
|
|||
|
<template #actions>
|
|||
|
<h-switch
|
|||
|
size="small"
|
|||
|
:checked="value.multiTabFixed"
|
|||
|
:disabled="!value.multiTab && !value.fixedHeader"
|
|||
|
@change="() => handleChange('multiTabFixed', !value.multiTabFixed)"
|
|||
|
/>
|
|||
|
</template>
|
|||
|
</h-list-item>
|
|||
|
</h-tooltip>
|
|||
|
|
|||
|
<h-list-item>
|
|||
|
<span style="opacity: 0.5">{{ t('app.setting.weakmode') }}</span>
|
|||
|
<template #actions>
|
|||
|
<h-switch size="small" :checked="false" :disabled="true" />
|
|||
|
</template>
|
|||
|
</h-list-item>
|
|||
|
</h-list>
|
|||
|
</body-wrapper>
|
|||
|
</div>
|
|||
|
</h-drawer>
|
|||
|
</template>
|
|||
|
|
|||
|
<script lang="ts">
|
|||
|
import PropTypes from 'ant-design-vue/es/_util/vue-types';
|
|||
|
import { defineComponent, computed, reactive, ref } from 'vue';
|
|||
|
import { useProProvider } from '../base-layouts/pro-provider';
|
|||
|
import { CloseOutlined, SettingOutlined } from '@ant-design/icons-vue';
|
|||
|
import type { ContentWidth } from '../base-layouts/typing';
|
|||
|
import { useStore } from 'vuex';
|
|||
|
import {
|
|||
|
SET_CONTENT_WIDTH,
|
|||
|
SET_LAYOUT,
|
|||
|
SET_NAV_THEME,
|
|||
|
SET_SPLIT_MENUS,
|
|||
|
SET_TRANSITION_NAME,
|
|||
|
SET_FIXED_HEADER,
|
|||
|
SET_FIXED_SIDEBAR,
|
|||
|
SET_MULTI_TAB,
|
|||
|
SET_FIXED_MULTI_TAB,
|
|||
|
} from '@/store/modules/app/mutations';
|
|||
|
import BodyWrapper from './body-wrapper.vue';
|
|||
|
import BlockCheckbox from './block-checkbox.vue';
|
|||
|
import LayoutChange from './layout-change.vue';
|
|||
|
import { useI18n } from '@crami/locale';
|
|||
|
import type { LayoutBlockTheme } from './layout-block.vue';
|
|||
|
|
|||
|
const iconStyle = {
|
|||
|
color: '#fff',
|
|||
|
fontSize: '20px',
|
|||
|
};
|
|||
|
|
|||
|
export interface ThemeItem {
|
|||
|
disabled?: boolean;
|
|||
|
key: LayoutBlockTheme;
|
|||
|
url?: string;
|
|||
|
title: string;
|
|||
|
}
|
|||
|
export interface ThemeConfig {
|
|||
|
key: string;
|
|||
|
fileName?: string;
|
|||
|
theme: string;
|
|||
|
modifyVars: Record<string, any>;
|
|||
|
}
|
|||
|
|
|||
|
export interface SettingProps {
|
|||
|
theme: 'dark' | 'light' | 'realDrak';
|
|||
|
primaryColor: string;
|
|||
|
layout: 'side' | 'top' | 'mix' | 'left';
|
|||
|
colorWeak: boolean;
|
|||
|
contentWidth: ContentWidth;
|
|||
|
fixedHeader: boolean;
|
|||
|
fixSiderbar: boolean;
|
|||
|
hideHintAlert: boolean;
|
|||
|
hideCopyButton: boolean;
|
|||
|
}
|
|||
|
|
|||
|
export const vueSettingProps = {
|
|||
|
theme: PropTypes.oneOf(['dark', 'light', 'realDark']),
|
|||
|
primaryColor: PropTypes.string,
|
|||
|
layout: PropTypes.oneOf(['side', 'top', 'mix', 'left']),
|
|||
|
colorWeak: PropTypes.bool,
|
|||
|
contentWidth: PropTypes.oneOf(['Fluid', 'Fixed']).def('Fluid'),
|
|||
|
fixedHeader: PropTypes.bool,
|
|||
|
fixSiderbar: PropTypes.bool,
|
|||
|
hideHintAlert: PropTypes.bool.def(false),
|
|||
|
hideCopyButton: PropTypes.bool.def(false),
|
|||
|
};
|
|||
|
|
|||
|
const getThemeList = (t: (s: string) => string) => {
|
|||
|
// @ts-ignoe
|
|||
|
// const list: ThemeConfig[] = window.antdv_pro_plugin_ant_themeVar || [];
|
|||
|
const list: ThemeConfig[] = [];
|
|||
|
const themeList: ThemeItem[] = [
|
|||
|
{
|
|||
|
key: 'light',
|
|||
|
title: t('app.setting.pagestyle.light'),
|
|||
|
},
|
|||
|
{
|
|||
|
key: 'dark',
|
|||
|
title: t('app.setting.pagestyle.dark'),
|
|||
|
},
|
|||
|
{
|
|||
|
key: 'realDark',
|
|||
|
title: t('app.setting.pagestyle.realdark'),
|
|||
|
},
|
|||
|
];
|
|||
|
|
|||
|
const darkColorList = [
|
|||
|
{
|
|||
|
key: '#1890ff',
|
|||
|
color: '#1890ff',
|
|||
|
theme: 'dark',
|
|||
|
},
|
|||
|
];
|
|||
|
|
|||
|
const lightColorList = [
|
|||
|
{
|
|||
|
key: '#1890ff',
|
|||
|
color: '#1890ff',
|
|||
|
theme: 'dark',
|
|||
|
},
|
|||
|
];
|
|||
|
|
|||
|
if (list.find(item => item.theme === 'dark')) {
|
|||
|
themeList.push({
|
|||
|
key: 'realDark',
|
|||
|
url: 'https://gw.alipayobjects.com/zos/antfincdn/hmKaLQvmY2/LCkqqYNmvBEbokSDscrm.svg',
|
|||
|
title: t('app.setting.pagestyle.realdark'),
|
|||
|
});
|
|||
|
}
|
|||
|
// insert theme color List
|
|||
|
list.forEach(item => {
|
|||
|
const color = (item.modifyVars || {})['@primary-color'];
|
|||
|
if (item.theme === 'dark' && color) {
|
|||
|
darkColorList.push({
|
|||
|
color,
|
|||
|
...item,
|
|||
|
});
|
|||
|
}
|
|||
|
if (!item.theme || item.theme === 'light') {
|
|||
|
lightColorList.push({
|
|||
|
color,
|
|||
|
...item,
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
return {
|
|||
|
colorList: {
|
|||
|
dark: darkColorList,
|
|||
|
light: lightColorList,
|
|||
|
},
|
|||
|
themeList,
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
export default defineComponent({
|
|||
|
name: 'SettingDrawer',
|
|||
|
props: {
|
|||
|
// value: {
|
|||
|
// type: Object as PropType<SettingProps>,
|
|||
|
// required: true,
|
|||
|
// },
|
|||
|
getContainer: PropTypes.func,
|
|||
|
},
|
|||
|
emits: ['change'],
|
|||
|
setup() {
|
|||
|
const { getPrefixCls } = useProProvider();
|
|||
|
const prefixCls = getPrefixCls('setting-drawer');
|
|||
|
const visible = ref(false);
|
|||
|
const { t } = useI18n();
|
|||
|
const themeList = getThemeList(t);
|
|||
|
const store = useStore();
|
|||
|
const value = reactive({
|
|||
|
layout: computed(() => store.getters['app/layout']),
|
|||
|
navTheme: computed(() => store.getters['app/navTheme']),
|
|||
|
contentWidth: computed(() => store.getters['app/contentWidth']),
|
|||
|
splitMenus: computed(() => store.getters['app/splitMenus']),
|
|||
|
fixedHeader: computed(() => store.getters['app/fixedHeader']),
|
|||
|
fixSidebar: computed(() => store.getters['app/fixedSidebar']),
|
|||
|
transitionName: computed(() => store.getters['app/transitionName']),
|
|||
|
multiTab: computed(() => store.getters['app/multiTab']),
|
|||
|
multiTabFixed: computed(() => store.getters['app/multiTabFixed']),
|
|||
|
});
|
|||
|
|
|||
|
const setShow = (flag: boolean) => {
|
|||
|
visible.value = flag;
|
|||
|
};
|
|||
|
|
|||
|
const handleClickShowButton = (e: Event) => {
|
|||
|
// 组件库内部会劫持,导致触发两遍,做一下判断,组件库修复后可去除判断
|
|||
|
if (e) {
|
|||
|
visible.value = !visible.value;
|
|||
|
}
|
|||
|
};
|
|||
|
const updateLayoutSetting = (val: string) => {
|
|||
|
if (val !== 'mix') {
|
|||
|
// 强制停止使用分割菜单
|
|||
|
store.commit(`app/${SET_SPLIT_MENUS}`, false);
|
|||
|
} else {
|
|||
|
// Mix 模式下,header 必须被锁定
|
|||
|
store.commit(`app/${SET_FIXED_HEADER}`, true);
|
|||
|
}
|
|||
|
store.commit(`app/${SET_LAYOUT}`, val);
|
|||
|
};
|
|||
|
|
|||
|
const handleChange = (type: string, val: string | boolean) => {
|
|||
|
console.log('change', type, val);
|
|||
|
if (type === 'layout') {
|
|||
|
updateLayoutSetting(val as string);
|
|||
|
} else if (type === 'theme') {
|
|||
|
store.commit(`app/${SET_NAV_THEME}`, val);
|
|||
|
} else if (type === 'splitmenus') {
|
|||
|
store.commit(`app/${SET_SPLIT_MENUS}`, val);
|
|||
|
} else if (type === 'fixSiderbar') {
|
|||
|
store.commit(`app/${SET_FIXED_SIDEBAR}`, val);
|
|||
|
} else if (type === 'fixedHeader') {
|
|||
|
// 关闭 header 固定时,取消 multi-tab 固定
|
|||
|
if (!val) {
|
|||
|
store.commit(`app/${SET_FIXED_MULTI_TAB}`, false);
|
|||
|
}
|
|||
|
store.commit(`app/${SET_FIXED_HEADER}`, val);
|
|||
|
} else if (type === 'contentWidth') {
|
|||
|
store.commit(`app/${SET_CONTENT_WIDTH}`, val);
|
|||
|
} else if (type === 'transition') {
|
|||
|
store.commit(`app/${SET_TRANSITION_NAME}`, val === 'null' ? '' : val);
|
|||
|
} else if (type === 'multiTab') {
|
|||
|
store.commit(`app/${SET_MULTI_TAB}`, val);
|
|||
|
} else if (type === 'multiTabFixed') {
|
|||
|
if (!value.fixedHeader) {
|
|||
|
store.commit(`app/${SET_FIXED_HEADER}`, true);
|
|||
|
}
|
|||
|
store.commit(`app/${SET_FIXED_MULTI_TAB}`, val);
|
|||
|
}
|
|||
|
|
|||
|
// emit('change', { type, value });
|
|||
|
};
|
|||
|
|
|||
|
return {
|
|||
|
t,
|
|||
|
value,
|
|||
|
prefixCls,
|
|||
|
iconStyle,
|
|||
|
themeList,
|
|||
|
|
|||
|
visible,
|
|||
|
setShow,
|
|||
|
handleChange,
|
|||
|
handleClickShowButton,
|
|||
|
};
|
|||
|
},
|
|||
|
components: {
|
|||
|
CloseOutlined,
|
|||
|
SettingOutlined,
|
|||
|
|
|||
|
BodyWrapper,
|
|||
|
BlockCheckbox,
|
|||
|
LayoutChange,
|
|||
|
},
|
|||
|
});
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="less" scoped>
|
|||
|
@import './index.less';
|
|||
|
</style>
|