提交 da04913e 编写于 作者: V vben

feat: added settingButtonPosition configuration close #275

上级 7d9b521c
## Wip
### ✨ Features
- 新增 `settingButtonPosition`配置项,用于配置`设置`按钮位置
## 2.0.0 (2021-02-18)
## (破坏性更新) Breaking changes
......
/**
* Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated
* https://github.com/anncwb/vite-plugin-compression
*/
import type { Plugin } from 'vite';
......
// Image resource files used to compress the output of the production environment
// https://github.com/anncwb/vite-plugin-imagemin
import viteImagemin from 'vite-plugin-imagemin';
......
......@@ -4,7 +4,6 @@ import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import legacy from '@vitejs/plugin-legacy';
import windiCSS from 'vite-plugin-windicss';
import PurgeIcons from 'vite-plugin-purge-icons';
import { ViteEnv } from '../../utils';
......@@ -16,6 +15,7 @@ import { configStyleImportPlugin } from './styleImport';
import { configVisualizerConfig } from './visualizer';
import { configThemePlugin } from './theme';
import { configImageminPlugin } from './imagemin';
import { configWindiCssPlugin } from './windicss';
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
const { VITE_USE_IMAGEMIN, VITE_USE_MOCK, VITE_LEGACY, VITE_BUILD_COMPRESS } = viteEnv;
......@@ -25,7 +25,6 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
vue(),
// have to
vueJsx(),
...windiCSS(),
];
// @vitejs/plugin-legacy
......@@ -34,6 +33,9 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// vite-plugin-html
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
// vite-plugin-windicss
vitePlugins.push(configWindiCssPlugin());
// vite-plugin-mock
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild));
......
import windiCSS from 'vite-plugin-windicss';
import type { Plugin } from 'vite';
export function configWindiCssPlugin(): Plugin[] {
return windiCSS({
safelist: 'shadow shadow-xl',
preflight: {
enableAll: true,
},
});
}
......@@ -22,6 +22,12 @@ export enum ThemeEnum {
LIGHT = 'light',
}
export enum SettingButtonPositionEnum {
AUTO = 'auto',
HEADER = 'header',
FIXED = 'fixed',
}
/**
* 权限模式
*/
......
......@@ -160,13 +160,5 @@ export function getTargetElement(
if (!target) {
return defaultElement;
}
let targetElement: TargetElement | undefined | null;
if (isFunction(target)) {
targetElement = target();
} else {
targetElement = unref(target);
}
return targetElement;
return isFunction(target) ? target() : unref(target);
}
......@@ -16,6 +16,8 @@ const getPageLoading = computed(() => appStore.getPageLoading);
const getOpenKeepAlive = computed(() => unref(getRootSetting).openKeepAlive);
const getSettingButtonPosition = computed(() => unref(getRootSetting).settingButtonPosition);
const getCanEmbedIFramePage = computed(() => unref(getRootSetting).canEmbedIFramePage);
const getPermissionMode = computed(() => unref(getRootSetting).permissionMode);
......@@ -58,6 +60,7 @@ export function useRootSetting() {
return {
setRootSetting,
getSettingButtonPosition,
getFullContent,
getColorWeak,
getGrayMode,
......
......@@ -57,12 +57,7 @@ export function useFullscreen(
async function toggleFullscreen(): Promise<void> {
if (!unref(target)) return;
if (isFullscreen()) {
return exitFullscreen();
} else {
return enterFullscreen();
}
return isFullscreen() ? exitFullscreen() : enterFullscreen();
}
return {
......
<template>
<LayoutLockPage />
<BackTop v-if="getUseOpenBackTop" :target="getTarget" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
import { defineComponent, computed, unref } from 'vue';
import { BackTop } from 'ant-design-vue';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useDesign } from '/@/hooks/web/useDesign';
import { SettingButtonPositionEnum } from '/@/enums/appEnum';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
export default defineComponent({
name: 'LayoutFeatures',
components: {
BackTop,
LayoutLockPage: createAsyncComponent(() => import('/@/views/sys/lock/index.vue')),
SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue')),
},
setup() {
const { getUseOpenBackTop } = useRootSetting();
const {
getUseOpenBackTop,
getShowSettingButton,
getSettingButtonPosition,
getFullContent,
} = useRootSetting();
const { prefixCls } = useDesign('setting-drawer-fearure');
const { getShowHeader } = useHeaderSetting();
const getIsFixedSettingDrawer = computed(() => {
if (!unref(getShowSettingButton)) {
return false;
}
const settingButtonPosition = unref(getSettingButtonPosition);
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
return !unref(getShowHeader) || unref(getFullContent);
}
return settingButtonPosition === SettingButtonPositionEnum.FIXED;
});
return {
getTarget: () => document.body,
getUseOpenBackTop,
getIsFixedSettingDrawer,
prefixCls,
};
},
});
</script>
<template>
<LayoutLockPage />
<BackTop v-if="getUseOpenBackTop" :target="getTarget" />
<SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" />
</template>
<style lang="less">
@prefix-cls: ~'@{namespace}-setting-drawer-fearure';
.@{prefix-cls} {
position: absolute;
top: 45%;
right: 0;
z-index: 10;
display: flex;
padding: 10px;
color: @white;
cursor: pointer;
background: @primary-color;
border-radius: 6px 0 0 6px;
justify-content: center;
align-items: center;
svg {
width: 1em;
height: 1em;
}
}
</style>
......@@ -22,7 +22,7 @@
icon="ion:lock-closed-outline"
/>
<MenuItem
key="loginOut"
key="logout"
:text="t('layout.header.dropdownItemLoginOut')"
icon="ion:power-outline"
/>
......@@ -51,7 +51,7 @@
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
type MenuEvent = 'loginOut' | 'doc' | 'lock';
type MenuEvent = 'logout' | 'doc' | 'lock';
export default defineComponent({
name: 'UserDropdown',
......@@ -93,7 +93,7 @@
function handleMenuClick(e: { key: MenuEvent }) {
switch (e.key) {
case 'loginOut':
case 'logout':
handleLoginOut();
break;
case 'doc':
......
......@@ -50,7 +50,7 @@
<UserDropDown :theme="getHeaderTheme" />
<SettingDrawer v-if="getShowSettingButton" :class="`${prefixCls}-action__item`" />
<SettingDrawer v-if="getShowSetting" :class="`${prefixCls}-action__item`" />
</div>
</Header>
</template>
......@@ -72,6 +72,7 @@
import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
import { SettingButtonPositionEnum } from '/@/enums/appEnum';
import { AppLocalePicker } from '/@/components/Application';
import { UserDropDown, LayoutBreadcrumb, FullScreen, Notify, ErrorAction } from './components';
......@@ -112,7 +113,11 @@
getIsMixSidebar,
} = useMenuSetting();
const { getShowLocale } = useLocaleSetting();
const { getUseErrorHandle, getShowSettingButton } = useRootSetting();
const {
getUseErrorHandle,
getShowSettingButton,
getSettingButtonPosition,
} = useRootSetting();
const {
getHeaderTheme,
......@@ -122,6 +127,7 @@
getShowContent,
getShowBread,
getShowHeaderLogo,
getShowHeader,
} = useHeaderSetting();
const { getIsMobile } = useAppInject();
......@@ -138,6 +144,18 @@
];
});
const getShowSetting = computed(() => {
if (!unref(getShowSettingButton)) {
return false;
}
const settingButtonPosition = unref(getSettingButtonPosition);
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
return unref(getShowHeader);
}
return settingButtonPosition === SettingButtonPositionEnum.HEADER;
});
const getLogoWidth = computed(() => {
if (!unref(getIsMixMode) || unref(getIsMobile)) {
return {};
......@@ -175,6 +193,7 @@
getLogoWidth,
getIsMixSidebar,
getShowSettingButton,
getShowSetting,
};
},
});
......
<template>
<div @click="openDrawer" :class="prefixCls">
<div @click="openDrawer">
<Icon icon="ion:settings-outline" />
<SettingDrawer @register="register" />
</div>
......@@ -10,7 +10,6 @@
import Icon from '/@/components/Icon';
import { useDrawer } from '/@/components/Drawer';
import { useDesign } from '/@/hooks/web/useDesign';
export default defineComponent({
name: 'SettingButton',
......@@ -18,9 +17,7 @@
setup() {
const [register, { openDrawer }] = useDrawer();
const { prefixCls } = useDesign('setting-button');
return {
prefixCls,
register,
openDrawer,
};
......
export default {
loginOutTip: 'Reminder',
loginOutMessage: 'Confirm to exit the system?',
logoutTip: 'Reminder',
logoutMessage: 'Confirm to exit the system?',
menuLoading: 'Menu loading...',
};
export default {
loginOutTip: '温馨提醒',
loginOutMessage: '是否确认退出系统?',
logoutTip: '温馨提醒',
logoutMessage: '是否确认退出系统?',
menuLoading: '菜单加载中...',
};
......@@ -2,7 +2,13 @@ import type { ProjectConfig } from '/@/types/config';
import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '/@/enums/menuEnum';
import { CacheTypeEnum } from '/@/enums/cacheEnum';
import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
import {
ContentEnum,
PermissionModeEnum,
ThemeEnum,
RouterTransitionEnum,
SettingButtonPositionEnum,
} from '/@/enums/appEnum';
import { primaryColor, themeMode } from '../../build/config/themeConfig';
// ! You need to clear the browser cache after the change
......@@ -10,6 +16,9 @@ const setting: ProjectConfig = {
// Whether to show the configuration button
showSettingButton: true,
// `Settings` button position
settingButtonPosition: SettingButtonPositionEnum.AUTO,
// Permission mode
permissionMode: PermissionModeEnum.ROLE,
......
......@@ -98,22 +98,22 @@ class Permission extends VuexModule {
if (!roles) return true;
return roleList.some((role) => roles.includes(role));
});
// 如果确定不需要做后台动态权限,请将下面整个判断注释
// If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
} else if (permissionMode === PermissionModeEnum.BACK) {
createMessage.loading({
content: t('sys.app.menuLoading'),
duration: 1,
});
// 这里获取后台路由菜单逻辑自行修改
// Here to get the background routing menu logic to modify by yourself
const paramId = id || userStore.getUserInfoState.userId;
if (!paramId) {
throw new Error('paramId is undefined!');
}
let routeList = (await getMenuListById({ id: paramId })) as AppRouteRecordRaw[];
// 动态引入组件
// Dynamically introduce components
routeList = transformObjToRoute(routeList);
// 后台路由转菜单结构
// Background routing to menu structure
const backMenuList = transformRouteToMenu(routeList);
this.commitBackMenuListState(backMenuList);
......
......@@ -131,10 +131,10 @@ class User extends VuexModule {
}
/**
* @description: login out
* @description: logout
*/
@Action
async loginOut(goLogin = false) {
async logout(goLogin = false) {
goLogin && router.push(PageEnum.BASE_LOGIN);
}
......@@ -147,10 +147,10 @@ class User extends VuexModule {
const { t } = useI18n();
createConfirm({
iconType: 'warning',
title: t('sys.app.loginOutTip'),
content: t('sys.app.loginOutMessage'),
title: t('sys.app.logoutTip'),
content: t('sys.app.logoutMessage'),
onOk: async () => {
await this.loginOut(true);
await this.logout(true);
},
});
}
......
import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '/@/enums/menuEnum';
import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
import {
ContentEnum,
PermissionModeEnum,
ThemeEnum,
RouterTransitionEnum,
SettingButtonPositionEnum,
} from '/@/enums/appEnum';
import { CacheTypeEnum } from '/@/enums/cacheEnum';
import type { LocaleType } from '/@/locales/types';
import { ThemeMode } from '../../build/config/lessModifyVars';
......@@ -88,6 +94,7 @@ export interface ProjectConfig {
// 是否显示配置按钮
showSettingButton: boolean;
settingButtonPosition: SettingButtonPositionEnum;
// 权限模式
permissionMode: PermissionModeEnum;
// 网站灰色模式,用于可能悼念的日期开启
......
......@@ -100,9 +100,9 @@ export function findPath<T = any>(
export function findPathAll(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) {
config = getConfig(config);
const path = [];
const path: any[] = [];
const list = [...tree];
const result = [];
const result: any[] = [];
const visitedSet = new Set(),
{ children } = config;
while (list.length) {
......@@ -153,14 +153,14 @@ export function forEach<T = any>(
}
/**
* @description: 提取tree指定结构
* @description: Extract tree specified structure
*/
export function treeMap<T = any>(treeData: T[], opt: { children?: string; conversion: Fn }): T[] {
return treeData.map((item) => treeMapEach(item, opt));
}
/**
* @description: 提取tree指定结构
* @description: Extract tree specified structure
*/
export function treeMapEach(
data: any,
......
......@@ -15,7 +15,7 @@ export function checkStatus(status: number, msg: string): void {
// Return to the current page after successful login. This step needs to be operated on the login page.
case 401:
error(t('sys.api.errMsg401'));
userStore.loginOut(true);
userStore.logout(true);
break;
case 403:
error(t('sys.api.errMsg403'));
......
......@@ -23,17 +23,11 @@ export function getPopupContainer(node?: HTMLElement): HTMLElement {
*/
export function setObjToUrlParams(baseUrl: string, obj: any): string {
let parameters = '';
let url = '';
for (const key in obj) {
parameters += key + '=' + encodeURIComponent(obj[key]) + '&';
}
parameters = parameters.replace(/&$/, '');
if (/\?$/.test(baseUrl)) {
url = baseUrl + parameters;
} else {
url = baseUrl.replace(/\/?$/, '?') + parameters;
}
return url;
return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters;
}
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
......@@ -45,7 +39,7 @@ export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
}
/**
* @description: 根据数组中某个对象值去重
* @description: Deduplication according to the value of an object in the array
*/
export function unique<T = any>(arr: T[], key: string): T[] {
const map = new Map();
......@@ -56,7 +50,7 @@ export function unique<T = any>(arr: T[], key: string): T[] {
}
/**
* @description: es6数组去重复
* @description: es6 array to repeat
*/
export function es6Unique<T>(arr: T[]): T[] {
return Array.from(new Set(arr));
......
......@@ -115,7 +115,7 @@
}
function goLogin() {
userStore.loginOut(true);
userStore.logout(true);
lockStore.resetLockInfo();
}
......@@ -287,6 +287,7 @@
&-img {
width: 70px;
margin: 0 auto;
border-radius: 50%;
}
......
......@@ -9370,12 +9370,13 @@ vite-plugin-theme@^0.4.3:
es-module-lexer "^0.3.26"
tinycolor2 "^1.4.2"
vite-plugin-windicss@0.2.2:
version "0.2.2"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.2.2.tgz#2abf1533153f5dc214a9e1a06fb58274e5892c19"
integrity sha512-P+iyrcuLjLfjiYP+bBisfKbg9bmeQMUBpjsTFJ9kWWX2fyqo968CHmS3euz+MzRcK5ZECccpOxx60ZXzc12VAw==
vite-plugin-windicss@0.3.3:
version "0.3.3"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.3.3.tgz#9ff2fc485dd5cf1717cde6eed462fd9893ea9eab"
integrity sha512-2gm0sTexkmvx9PR4NP1UESly8hX2souOruQztu1qghfw4M3tlUUvwneRpJG5HVJCKCctmAgYRcW4e04TE5R1fA==
dependencies:
fast-glob "^3.2.5"
micromatch "^4.0.2"
windicss "^2.1.11"
vite@2.0.1:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册