mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 06:58:53 +08:00
feat: support mobile layout adaptation
This commit is contained in:
@@ -3,17 +3,21 @@
|
|||||||
### ✨ Features
|
### ✨ Features
|
||||||
|
|
||||||
- 移除左侧菜单搜索,新增顶部菜单搜索功能
|
- 移除左侧菜单搜索,新增顶部菜单搜索功能
|
||||||
|
- layout 移动端适配。页面未适配
|
||||||
|
|
||||||
### ⚡ Performance Improvements
|
### ⚡ Performance Improvements
|
||||||
|
|
||||||
- 异步引入组件
|
- 异步引入组件
|
||||||
- 优化整体结构
|
- 优化整体结构
|
||||||
|
- 替换菜单默认滚动条为滚动组件
|
||||||
|
- 菜单性能优化
|
||||||
|
|
||||||
### 🎫 Chores
|
### 🎫 Chores
|
||||||
|
|
||||||
- 返回顶部样式调整,避免遮住其他元素
|
- 返回顶部样式调整,避免遮住其他元素
|
||||||
- 升级`ant-design-vue`到`2.0.0-rc.5`
|
- 升级`ant-design-vue`到`2.0.0-rc.5`
|
||||||
- 刷新按钮布局调整
|
- 刷新按钮布局调整
|
||||||
|
- `route.meta` 移除 `externalLink` 属性
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
@@ -37,7 +37,7 @@
|
|||||||
"sortablejs": "^1.12.0",
|
"sortablejs": "^1.12.0",
|
||||||
"vditor": "^3.7.2",
|
"vditor": "^3.7.2",
|
||||||
"vue": "^3.0.4",
|
"vue": "^3.0.4",
|
||||||
"vue-i18n": "^9.0.0-beta.12",
|
"vue-i18n": "^9.0.0-beta.13",
|
||||||
"vue-router": "^4.0.1",
|
"vue-router": "^4.0.1",
|
||||||
"vue-types": "^3.0.1",
|
"vue-types": "^3.0.1",
|
||||||
"vuex": "^4.0.0-rc.2",
|
"vuex": "^4.0.0-rc.2",
|
||||||
|
@@ -1,13 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="prefixCls" v-if="getShowSearch" @click="handleSearch">
|
<div :class="prefixCls" v-if="getShowSearch" @click.stop="handleSearch">
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<template #title> {{ t('component.app.search') }} </template>
|
<template #title> {{ t('component.app.search') }} </template>
|
||||||
<SearchOutlined />
|
<SearchOutlined />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<transition name="zoom-fade" mode="out-in">
|
<AppSearchModal @close="handleClose" :visible="showModal" />
|
||||||
<AppSearchModal @close="handleClose" v-if="showModal" />
|
|
||||||
</transition>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@@ -1,48 +1,58 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="prefixCls" @click.stop>
|
<Teleport to="body">
|
||||||
<ClickOutSide @clickOutside="handleClose">
|
<transition name="zoom-fade" mode="out-in">
|
||||||
<div :class="`${prefixCls}-content`">
|
<div :class="getClass" @click.stop v-if="visible">
|
||||||
<a-input
|
<ClickOutSide @clickOutside="handleClose">
|
||||||
:class="`${prefixCls}-input`"
|
<div :class="`${prefixCls}-content`">
|
||||||
:placeholder="t('component.app.search')"
|
<div :class="`${prefixCls}-input__wrapper`">
|
||||||
allow-clear
|
<a-input
|
||||||
@change="handleSearch"
|
:class="`${prefixCls}-input`"
|
||||||
>
|
:placeholder="t('component.app.search')"
|
||||||
<template #prefix>
|
allow-clear
|
||||||
<SearchOutlined />
|
@change="handleSearch"
|
||||||
</template>
|
>
|
||||||
</a-input>
|
<template #prefix>
|
||||||
<div :class="`${prefixCls}-not-data`" v-show="getIsNotData">
|
<SearchOutlined />
|
||||||
{{ t('component.app.searchNotData') }}
|
</template>
|
||||||
</div>
|
</a-input>
|
||||||
<ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap">
|
<span :class="`${prefixCls}-cancel`" @click="handleClose">{{
|
||||||
<li
|
t('component.app.cancel')
|
||||||
:ref="setRefs(index)"
|
}}</span>
|
||||||
v-for="(item, index) in searchResult"
|
|
||||||
:key="item.path"
|
|
||||||
:data-index="index"
|
|
||||||
@mouseenter="handleMouseenter"
|
|
||||||
@click="handleEnter"
|
|
||||||
:class="[
|
|
||||||
`${prefixCls}-list__item`,
|
|
||||||
{
|
|
||||||
[`${prefixCls}-list__item--active`]: activeIndex === index,
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<div :class="`${prefixCls}-list__item-icon`">
|
|
||||||
<g-icon :icon="item.icon || 'mdi:form-select'" :size="20" />
|
|
||||||
</div>
|
</div>
|
||||||
<div :class="`${prefixCls}-list__item-text`">{{ item.name }}</div>
|
|
||||||
<div :class="`${prefixCls}-list__item-enter`">
|
<div :class="`${prefixCls}-not-data`" v-show="getIsNotData">
|
||||||
<g-icon icon="ant-design:enter-outlined" :size="20" />
|
{{ t('component.app.searchNotData') }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
<ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap">
|
||||||
</ul>
|
<li
|
||||||
<AppSearchFooter />
|
:ref="setRefs(index)"
|
||||||
|
v-for="(item, index) in searchResult"
|
||||||
|
:key="item.path"
|
||||||
|
:data-index="index"
|
||||||
|
@mouseenter="handleMouseenter"
|
||||||
|
@click="handleEnter"
|
||||||
|
:class="[
|
||||||
|
`${prefixCls}-list__item`,
|
||||||
|
{
|
||||||
|
[`${prefixCls}-list__item--active`]: activeIndex === index,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<div :class="`${prefixCls}-list__item-icon`">
|
||||||
|
<g-icon :icon="item.icon || 'mdi:form-select'" :size="20" />
|
||||||
|
</div>
|
||||||
|
<div :class="`${prefixCls}-list__item-text`">{{ item.name }}</div>
|
||||||
|
<div :class="`${prefixCls}-list__item-enter`">
|
||||||
|
<g-icon icon="ant-design:enter-outlined" :size="20" />
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<AppSearchFooter />
|
||||||
|
</div>
|
||||||
|
</ClickOutSide>
|
||||||
</div>
|
</div>
|
||||||
</ClickOutSide>
|
</transition>
|
||||||
</div>
|
</Teleport>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed, unref, ref } from 'vue';
|
import { defineComponent, computed, unref, ref } from 'vue';
|
||||||
@@ -54,15 +64,20 @@
|
|||||||
import AppSearchFooter from './AppSearchFooter.vue';
|
import AppSearchFooter from './AppSearchFooter.vue';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
import { ClickOutSide } from '/@/components/ClickOutSide';
|
import { ClickOutSide } from '/@/components/ClickOutSide';
|
||||||
|
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AppSearchModal',
|
name: 'AppSearchModal',
|
||||||
components: { SearchOutlined, ClickOutSide, AppSearchFooter },
|
components: { SearchOutlined, ClickOutSide, AppSearchFooter },
|
||||||
emits: ['close'],
|
emits: ['close'],
|
||||||
|
props: {
|
||||||
|
visible: Boolean,
|
||||||
|
},
|
||||||
setup(_, { emit }) {
|
setup(_, { emit }) {
|
||||||
const scrollWrap = ref<ElRef>(null);
|
const scrollWrap = ref<ElRef>(null);
|
||||||
const { prefixCls } = useDesign('app-search-modal');
|
const { prefixCls } = useDesign('app-search-modal');
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const [refs, setRefs] = useRefs();
|
const [refs, setRefs] = useRefs();
|
||||||
|
const { getIsMobile } = useAppInject();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSearch,
|
handleSearch,
|
||||||
@@ -77,9 +92,19 @@
|
|||||||
return !keyword || unref(searchResult).length === 0;
|
return !keyword || unref(searchResult).length === 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getClass = computed(() => {
|
||||||
|
return [
|
||||||
|
prefixCls,
|
||||||
|
{
|
||||||
|
[`${prefixCls}--mobile`]: unref(getIsMobile),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
t,
|
t,
|
||||||
prefixCls,
|
prefixCls,
|
||||||
|
getClass,
|
||||||
handleSearch,
|
handleSearch,
|
||||||
searchResult,
|
searchResult,
|
||||||
activeIndex,
|
activeIndex,
|
||||||
@@ -98,12 +123,12 @@
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
@import (reference) '../../../../design/index.less';
|
@import (reference) '../../../../design/index.less';
|
||||||
@prefix-cls: ~'@{namespace}-app-search-modal';
|
@prefix-cls: ~'@{namespace}-app-search-modal';
|
||||||
|
@footer-prefix-cls: ~'@{namespace}-app-search-footer';
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 100;
|
z-index: 800;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -113,6 +138,43 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
// backdrop-filter: blur(2px);
|
// backdrop-filter: blur(2px);
|
||||||
|
|
||||||
|
&--mobile {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{prefix-cls}-input {
|
||||||
|
width: calc(100% - 38px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{prefix-cls}-cancel {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{prefix-cls}-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{footer-prefix-cls} {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{prefix-cls}-list {
|
||||||
|
height: calc(100% - 80px);
|
||||||
|
max-height: unset;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
&-enter {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 532px;
|
width: 532px;
|
||||||
@@ -124,10 +186,16 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-input__wrapper {
|
||||||
|
display: flex;
|
||||||
|
padding: 14px 14px 0 14px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
&-input {
|
&-input {
|
||||||
width: calc(100% - 28px);
|
width: 100%;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
margin: 14px 14px 0 14px;
|
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
color: #1c1e21;
|
color: #1c1e21;
|
||||||
|
|
||||||
@@ -136,6 +204,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-cancel {
|
||||||
|
display: none;
|
||||||
|
font-size: 1em;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
&-not-data {
|
&-not-data {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@@ -151,7 +151,7 @@
|
|||||||
if (props.mode !== MenuModeEnum.HORIZONTAL) {
|
if (props.mode !== MenuModeEnum.HORIZONTAL) {
|
||||||
setOpenKeys(path);
|
setOpenKeys(path);
|
||||||
}
|
}
|
||||||
if (unref(getIsTopMenu)) {
|
if (props.isHorizontal && unref(getSplit)) {
|
||||||
const parentPath = await getCurrentParentPath(path);
|
const parentPath = await getCurrentParentPath(path);
|
||||||
menuState.selectedKeys = [parentPath];
|
menuState.selectedKeys = [parentPath];
|
||||||
} else {
|
} else {
|
||||||
|
@@ -50,11 +50,7 @@ const getShowTopMenu = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const getShowHeaderTrigger = computed(() => {
|
const getShowHeaderTrigger = computed(() => {
|
||||||
if (
|
if (unref(getMenuType) === MenuTypeEnum.TOP_MENU || !unref(getShowMenu) || unref(getMenuHidden)) {
|
||||||
unref(getMenuType) === MenuTypeEnum.TOP_MENU ||
|
|
||||||
!unref(getShowMenu) ||
|
|
||||||
!unref(getMenuHidden)
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +75,11 @@ const getMiniWidthNumber = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const getCalcContentWidth = computed(() => {
|
const getCalcContentWidth = computed(() => {
|
||||||
const width = unref(getIsTopMenu) || !unref(getShowMenu) ? 0 : unref(getRealWidth);
|
const width =
|
||||||
|
unref(getIsTopMenu) || !unref(getShowMenu) || (unref(getSplit) && unref(getMenuHidden))
|
||||||
|
? 0
|
||||||
|
: unref(getRealWidth);
|
||||||
|
|
||||||
return `calc(100% - ${unref(width)}px)`;
|
return `calc(100% - ${unref(width)}px)`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,214 +0,0 @@
|
|||||||
import './index.less';
|
|
||||||
|
|
||||||
import type { FunctionalComponent } from 'vue';
|
|
||||||
import type { Component } from '/@/components/types';
|
|
||||||
|
|
||||||
import { defineComponent, unref, computed } from 'vue';
|
|
||||||
|
|
||||||
import { Layout, Tooltip, Badge } from 'ant-design-vue';
|
|
||||||
import { AppLogo } from '/@/components/Application';
|
|
||||||
import LayoutMenu from '../menu';
|
|
||||||
import LockAction from './actions/LockAction';
|
|
||||||
import LayoutTrigger from '../trigger/index.vue';
|
|
||||||
import NoticeAction from './notice/NoticeActionItem.vue';
|
|
||||||
import { LockOutlined, BugOutlined } from '@ant-design/icons-vue';
|
|
||||||
|
|
||||||
import { AppSearch } from '/@/components/Application';
|
|
||||||
import { useModal } from '/@/components/Modal';
|
|
||||||
|
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
|
||||||
import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
|
|
||||||
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
|
|
||||||
import { errorStore } from '/@/store/modules/error';
|
|
||||||
|
|
||||||
import { PageEnum } from '/@/enums/pageEnum';
|
|
||||||
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
|
||||||
import { AppLocalePicker } from '/@/components/Application';
|
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
|
||||||
|
|
||||||
import { UserDropDown, LayoutBreadcrumb, FullScreen } from './components';
|
|
||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
|
||||||
import { useDesign } from '../../../hooks/web/useDesign';
|
|
||||||
interface TooltipItemProps {
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TooltipItem: FunctionalComponent<TooltipItemProps> = (props, { slots }) => {
|
|
||||||
return (
|
|
||||||
<Tooltip>
|
|
||||||
{{
|
|
||||||
title: () => props.title,
|
|
||||||
default: () => slots.default?.(),
|
|
||||||
}}
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'LayoutHeader',
|
|
||||||
props: {
|
|
||||||
fixed: propTypes.bool,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { t } = useI18n();
|
|
||||||
const { prefixCls } = useDesign('layout-header');
|
|
||||||
const { getShowTopMenu, getShowHeaderTrigger, getSplit } = useMenuSetting();
|
|
||||||
const { getShowLocale } = useLocaleSetting();
|
|
||||||
const { getUseErrorHandle } = useRootSetting();
|
|
||||||
|
|
||||||
const {
|
|
||||||
getHeaderTheme,
|
|
||||||
getUseLockPage,
|
|
||||||
getShowFullScreen,
|
|
||||||
getShowNotice,
|
|
||||||
getShowContent,
|
|
||||||
getShowBread,
|
|
||||||
getShowHeaderLogo,
|
|
||||||
} = useHeaderSetting();
|
|
||||||
|
|
||||||
const { push } = useRouter();
|
|
||||||
const [register, { openModal }] = useModal();
|
|
||||||
const { getIsMobile } = useAppInject();
|
|
||||||
|
|
||||||
const headerClass = computed(() => {
|
|
||||||
const theme = unref(getHeaderTheme);
|
|
||||||
return theme ? `${prefixCls}__header--${theme}` : '';
|
|
||||||
});
|
|
||||||
|
|
||||||
const getSplitType = computed(() => {
|
|
||||||
return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE;
|
|
||||||
});
|
|
||||||
|
|
||||||
const getMenuMode = computed(() => {
|
|
||||||
return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null;
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleToErrorList() {
|
|
||||||
push(PageEnum.ERROR_LOG_PAGE).then(() => {
|
|
||||||
errorStore.commitErrorListCountState(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleLockPage() {
|
|
||||||
openModal(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderHeaderLeft() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{unref(getShowContent) && (
|
|
||||||
<div class={`${prefixCls}__left`}>
|
|
||||||
{unref(getShowHeaderTrigger) && (
|
|
||||||
<LayoutTrigger theme={unref(getHeaderTheme)} sider={false} />
|
|
||||||
)}
|
|
||||||
{unref(getShowBread) && !unref(getIsMobile) && (
|
|
||||||
<LayoutBreadcrumb theme={unref(getHeaderTheme)} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderHeaderContent() {
|
|
||||||
return (
|
|
||||||
<div class={`${prefixCls}__content`}>
|
|
||||||
{unref(getShowTopMenu) && !unref(getIsMobile) && (
|
|
||||||
<div class={[`${prefixCls}__menu `]}>
|
|
||||||
{/* <div class={[`layout-header__menu `]}> */}
|
|
||||||
<LayoutMenu
|
|
||||||
isHorizontal={true}
|
|
||||||
// class={`justify-${unref(getTopMenuAlign)}`}
|
|
||||||
theme={unref(getHeaderTheme)}
|
|
||||||
splitType={unref(getSplitType)}
|
|
||||||
menuMode={unref(getMenuMode)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderActionDefault(Comp: Component | any, event: Fn) {
|
|
||||||
return (
|
|
||||||
<div class={`${prefixCls}__action-item`} onClick={event}>
|
|
||||||
<Comp class={`${prefixCls}__action-icon`} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderAction() {
|
|
||||||
return (
|
|
||||||
<div class={`${prefixCls}__action`}>
|
|
||||||
{!unref(getIsMobile) && <AppSearch class={`${prefixCls}__action-item`} />}
|
|
||||||
|
|
||||||
{unref(getUseErrorHandle) && !unref(getIsMobile) && (
|
|
||||||
<TooltipItem title={t('layout.header.tooltipErrorLog')}>
|
|
||||||
{() => (
|
|
||||||
<Badge
|
|
||||||
count={errorStore.getErrorListCountState}
|
|
||||||
offset={[0, 10]}
|
|
||||||
dot
|
|
||||||
overflowCount={99}
|
|
||||||
>
|
|
||||||
{() => renderActionDefault(BugOutlined, handleToErrorList)}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</TooltipItem>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{unref(getUseLockPage) && !unref(getIsMobile) && (
|
|
||||||
<TooltipItem title={t('layout.header.tooltipLock')}>
|
|
||||||
{() => renderActionDefault(LockOutlined, handleLockPage)}
|
|
||||||
</TooltipItem>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{unref(getShowNotice) && !unref(getIsMobile) && (
|
|
||||||
<TooltipItem title={t('layout.header.tooltipNotify')}>
|
|
||||||
{() => <NoticeAction />}
|
|
||||||
</TooltipItem>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{unref(getShowFullScreen) && !unref(getIsMobile) && <FullScreen />}
|
|
||||||
|
|
||||||
<UserDropDown theme={unref(getHeaderTheme)} />
|
|
||||||
|
|
||||||
{unref(getShowLocale) && (
|
|
||||||
<AppLocalePicker
|
|
||||||
reload={true}
|
|
||||||
showText={false}
|
|
||||||
class={`${prefixCls}__action-item locale`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderHeaderDefault() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{unref(getShowHeaderLogo) && (
|
|
||||||
<AppLogo class={`${prefixCls}__logo`} theme={unref(getHeaderTheme)} />
|
|
||||||
)}
|
|
||||||
{renderHeaderLeft()}
|
|
||||||
{renderHeaderContent()}
|
|
||||||
{renderAction()}
|
|
||||||
<LockAction onRegister={register} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
return (
|
|
||||||
<Layout.Header class={[prefixCls, unref(headerClass), { fixed: props.fixed }]}>
|
|
||||||
{() => renderHeaderDefault()}
|
|
||||||
</Layout.Header>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,18 +0,0 @@
|
|||||||
@import (reference) '../../../design/index.less';
|
|
||||||
|
|
||||||
.multiple-tab-header {
|
|
||||||
margin-left: 1px;
|
|
||||||
transition: width 0.2s;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
&.dark {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fixed {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
z-index: @multiple-tab-fixed-z-index;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,125 +0,0 @@
|
|||||||
import './LayoutMultipleHeader.less';
|
|
||||||
|
|
||||||
import { defineComponent, unref, computed, ref, watch, nextTick, CSSProperties } from 'vue';
|
|
||||||
|
|
||||||
import LayoutHeader from './index.vue';
|
|
||||||
import MultipleTabs from '../tabs/index.vue';
|
|
||||||
|
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
|
||||||
import { useFullContent } from '/@/hooks/web/useFullContent';
|
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
|
||||||
import { useLayoutContext } from '../useLayoutContext';
|
|
||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'LayoutMultipleHeader',
|
|
||||||
setup() {
|
|
||||||
const placeholderHeightRef = ref(0);
|
|
||||||
const fullHeaderHeightRef = ref(0);
|
|
||||||
const headerElRef = ref<ComponentRef>(null);
|
|
||||||
const tabElRef = ref<ComponentRef>(null);
|
|
||||||
|
|
||||||
const injectValue = useLayoutContext();
|
|
||||||
|
|
||||||
const { getCalcContentWidth, getSplit } = useMenuSetting();
|
|
||||||
const { getIsMobile } = useAppInject();
|
|
||||||
const {
|
|
||||||
getFixed,
|
|
||||||
getShowInsetHeaderRef,
|
|
||||||
getShowFullHeaderRef,
|
|
||||||
getShowHeader,
|
|
||||||
getUnFixedAndFull,
|
|
||||||
getHeaderTheme,
|
|
||||||
} = useHeaderSetting();
|
|
||||||
|
|
||||||
const { getFullContent } = useFullContent();
|
|
||||||
|
|
||||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
|
||||||
|
|
||||||
const getShowTabs = computed(() => {
|
|
||||||
return unref(getShowMultipleTab) && !unref(getFullContent);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getPlaceholderDomStyle = computed(
|
|
||||||
(): CSSProperties => {
|
|
||||||
return {
|
|
||||||
height: `${unref(placeholderHeightRef)}px`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const getIsShowPlaceholderDom = computed(() => {
|
|
||||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
|
||||||
});
|
|
||||||
|
|
||||||
const getWrapStyle = computed(
|
|
||||||
(): CSSProperties => {
|
|
||||||
const style: CSSProperties = {};
|
|
||||||
if (unref(getFixed)) {
|
|
||||||
style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth);
|
|
||||||
}
|
|
||||||
if (unref(getShowFullHeaderRef)) {
|
|
||||||
style.top = `${unref(fullHeaderHeightRef)}px`;
|
|
||||||
}
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const getIsFixed = computed(() => {
|
|
||||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => [
|
|
||||||
unref(getFixed),
|
|
||||||
unref(getShowFullHeaderRef),
|
|
||||||
unref(getShowHeader),
|
|
||||||
unref(getShowMultipleTab),
|
|
||||||
],
|
|
||||||
() => {
|
|
||||||
if (unref(getUnFixedAndFull)) return;
|
|
||||||
nextTick(() => {
|
|
||||||
const headerEl = unref(headerElRef)?.$el;
|
|
||||||
const tabEl = unref(tabElRef)?.$el;
|
|
||||||
const fullHeaderEl = unref(injectValue.fullHeader)?.$el;
|
|
||||||
|
|
||||||
let height = 0;
|
|
||||||
if (headerEl && !unref(getShowFullHeaderRef) && !unref(getSplit)) {
|
|
||||||
height += headerEl.offsetHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tabEl) {
|
|
||||||
height += tabEl.offsetHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fullHeaderEl && unref(getShowFullHeaderRef)) {
|
|
||||||
const fullHeaderHeight = fullHeaderEl.offsetHeight;
|
|
||||||
height += fullHeaderHeight;
|
|
||||||
fullHeaderHeightRef.value = fullHeaderHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
placeholderHeightRef.value = height;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{
|
|
||||||
immediate: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{unref(getIsShowPlaceholderDom) && <div style={unref(getPlaceholderDomStyle)} />}
|
|
||||||
<div
|
|
||||||
style={unref(getWrapStyle)}
|
|
||||||
class={['multiple-tab-header', unref(getHeaderTheme), { fixed: unref(getIsFixed) }]}
|
|
||||||
>
|
|
||||||
{unref(getShowInsetHeaderRef) && <LayoutHeader ref={headerElRef} />}
|
|
||||||
{unref(getShowTabs) && <MultipleTabs ref={tabElRef} />}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
124
src/layouts/default/header/MultipleHeader.vue
Normal file
124
src/layouts/default/header/MultipleHeader.vue
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<template>
|
||||||
|
<div :style="getPlaceholderDomStyle" v-if="getIsShowPlaceholderDom" />
|
||||||
|
<div :style="getWrapStyle" :class="getClass">
|
||||||
|
<LayoutHeader v-if="getShowInsetHeaderRef" />
|
||||||
|
<MultipleTabs v-if="getShowTabs" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, unref, computed, CSSProperties } from 'vue';
|
||||||
|
|
||||||
|
import LayoutHeader from './index.vue';
|
||||||
|
import MultipleTabs from '../tabs/index.vue';
|
||||||
|
|
||||||
|
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||||
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
|
import { useFullContent } from '/@/hooks/web/useFullContent';
|
||||||
|
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||||
|
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||||
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
|
|
||||||
|
const HEADER_HEIGHT = 48;
|
||||||
|
|
||||||
|
const TABS_HEIGHT = 32;
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'LayoutMultipleHeader',
|
||||||
|
components: { LayoutHeader, MultipleTabs },
|
||||||
|
setup() {
|
||||||
|
const { prefixCls } = useDesign('layout-multiple-header');
|
||||||
|
|
||||||
|
const { getCalcContentWidth, getSplit } = useMenuSetting();
|
||||||
|
const { getIsMobile } = useAppInject();
|
||||||
|
const {
|
||||||
|
getFixed,
|
||||||
|
getShowInsetHeaderRef,
|
||||||
|
getShowFullHeaderRef,
|
||||||
|
getHeaderTheme,
|
||||||
|
} = useHeaderSetting();
|
||||||
|
|
||||||
|
const { getFullContent } = useFullContent();
|
||||||
|
|
||||||
|
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||||
|
|
||||||
|
const getShowTabs = computed(() => {
|
||||||
|
return unref(getShowMultipleTab) && !unref(getFullContent);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getIsShowPlaceholderDom = computed(() => {
|
||||||
|
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getWrapStyle = computed(
|
||||||
|
(): CSSProperties => {
|
||||||
|
const style: CSSProperties = {};
|
||||||
|
if (unref(getFixed)) {
|
||||||
|
style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth);
|
||||||
|
}
|
||||||
|
if (unref(getShowFullHeaderRef)) {
|
||||||
|
style.top = `${HEADER_HEIGHT}px`;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getIsFixed = computed(() => {
|
||||||
|
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getPlaceholderDomStyle = computed(
|
||||||
|
(): CSSProperties => {
|
||||||
|
let height = 0;
|
||||||
|
if (unref(getShowFullHeaderRef) || !unref(getSplit)) {
|
||||||
|
height += HEADER_HEIGHT;
|
||||||
|
}
|
||||||
|
if (unref(getShowMultipleTab)) {
|
||||||
|
height += TABS_HEIGHT;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
height: `${height}px`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const getClass = computed(() => {
|
||||||
|
return [
|
||||||
|
prefixCls,
|
||||||
|
`${prefixCls}--${unref(getHeaderTheme)}`,
|
||||||
|
{ [`${prefixCls}--fixed`]: unref(getIsFixed) },
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
getClass,
|
||||||
|
prefixCls,
|
||||||
|
getPlaceholderDomStyle,
|
||||||
|
getIsFixed,
|
||||||
|
getWrapStyle,
|
||||||
|
getIsShowPlaceholderDom,
|
||||||
|
getShowTabs,
|
||||||
|
getShowInsetHeaderRef,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import (reference) '../../../design/index.less';
|
||||||
|
@prefix-cls: ~'@{namespace}-layout-multiple-header';
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
|
margin-left: 1px;
|
||||||
|
transition: width 0.2s;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
&--dark {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--fixed {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
z-index: @multiple-tab-fixed-z-index;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -2,6 +2,8 @@
|
|||||||
@header-trigger-prefix-cls: ~'@{namespace}-layout-header-trigger';
|
@header-trigger-prefix-cls: ~'@{namespace}-layout-header-trigger';
|
||||||
@header-prefix-cls: ~'@{namespace}-layout-header';
|
@header-prefix-cls: ~'@{namespace}-layout-header';
|
||||||
@locale-prefix-cls: ~'@{namespace}-app-locale-picker';
|
@locale-prefix-cls: ~'@{namespace}-app-locale-picker';
|
||||||
|
@breadcrumb-prefix-cls: ~'@{namespace}-layout-breadcrumb';
|
||||||
|
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||||
|
|
||||||
.@{header-prefix-cls} {
|
.@{header-prefix-cls} {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -14,6 +16,30 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&--mobile {
|
||||||
|
.@{breadcrumb-prefix-cls},
|
||||||
|
.error-action,
|
||||||
|
.notify-item,
|
||||||
|
.fullscreen-item {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.@{logo-prefix-cls} {
|
||||||
|
min-width: unset;
|
||||||
|
padding-right: 0;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.@{header-trigger-prefix-cls} {
|
||||||
|
padding: 0 4px 0 8px !important;
|
||||||
|
}
|
||||||
|
.@{header-prefix-cls}-action {
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&--fixed {
|
&--fixed {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -78,7 +104,7 @@
|
|||||||
|
|
||||||
&-action {
|
&-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 200px;
|
min-width: 180px;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
@@ -3,17 +3,17 @@
|
|||||||
<!-- left start -->
|
<!-- left start -->
|
||||||
<div :class="`${prefixCls}-left`">
|
<div :class="`${prefixCls}-left`">
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<AppLogo v-if="getShowHeaderLogo" :class="`${prefixCls}-logo`" :theme="getHeaderTheme" />
|
<AppLogo
|
||||||
|
v-if="getShowHeaderLogo || getIsMobile"
|
||||||
|
:class="`${prefixCls}-logo`"
|
||||||
|
:theme="getHeaderTheme"
|
||||||
|
/>
|
||||||
<LayoutTrigger
|
<LayoutTrigger
|
||||||
v-if="getShowContent && getShowHeaderTrigger"
|
v-if="(getShowContent && getShowHeaderTrigger && !getSplit) || getIsMobile"
|
||||||
:theme="getHeaderTheme"
|
:theme="getHeaderTheme"
|
||||||
:sider="false"
|
:sider="false"
|
||||||
/>
|
/>
|
||||||
<LayoutBreadcrumb
|
<LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" />
|
||||||
v-if="getShowContent && getShowBread && !getIsMobile"
|
|
||||||
:theme="getHeaderTheme"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- left end -->
|
<!-- left end -->
|
||||||
|
|
||||||
@@ -30,15 +30,15 @@
|
|||||||
|
|
||||||
<!-- action -->
|
<!-- action -->
|
||||||
<div :class="`${prefixCls}-action`">
|
<div :class="`${prefixCls}-action`">
|
||||||
<AppSearch v-if="!getIsMobile" :class="`${prefixCls}-action__item`" />
|
<AppSearch :class="`${prefixCls}-action__item `" />
|
||||||
|
|
||||||
<ErrorAction v-if="getUseErrorHandle && !getIsMobile" :class="`${prefixCls}-action__item`" />
|
<ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" />
|
||||||
|
|
||||||
<LockItem v-if="getUseLockPage && !getIsMobile" :class="`${prefixCls}-action__item`" />
|
<LockItem v-if="getUseLockPage" :class="`${prefixCls}-action__item lock-item`" />
|
||||||
|
|
||||||
<Notify v-if="getShowNotice && !getIsMobile" :class="`${prefixCls}-action__item`" />
|
<Notify v-if="getShowNotice" :class="`${prefixCls}-action__item notify-item`" />
|
||||||
|
|
||||||
<FullScreen v-if="getShowFullScreen && !getIsMobile" :class="`${prefixCls}-action__item`" />
|
<FullScreen v-if="getShowFullScreen" :class="`${prefixCls}-action__item fullscreen-item`" />
|
||||||
|
|
||||||
<UserDropDown :theme="getHeaderTheme" />
|
<UserDropDown :theme="getHeaderTheme" />
|
||||||
|
|
||||||
@@ -123,7 +123,11 @@
|
|||||||
const theme = unref(getHeaderTheme);
|
const theme = unref(getHeaderTheme);
|
||||||
return [
|
return [
|
||||||
prefixCls,
|
prefixCls,
|
||||||
{ [`${prefixCls}--fixed`]: props.fixed, [`${prefixCls}--${theme}`]: theme },
|
{
|
||||||
|
[`${prefixCls}--fixed`]: props.fixed,
|
||||||
|
[`${prefixCls}--mobile`]: unref(getIsMobile),
|
||||||
|
[`${prefixCls}--${theme}`]: theme,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -145,6 +149,7 @@
|
|||||||
getShowBread,
|
getShowBread,
|
||||||
getShowContent,
|
getShowContent,
|
||||||
getSplitType,
|
getSplitType,
|
||||||
|
getSplit,
|
||||||
getMenuMode,
|
getMenuMode,
|
||||||
getShowTopMenu,
|
getShowTopMenu,
|
||||||
getShowLocale,
|
getShowLocale,
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<Layout :class="prefixCls">
|
<Layout :class="prefixCls">
|
||||||
<LayoutFeatures />
|
<LayoutFeatures />
|
||||||
<LayoutHeader fixed ref="headerRef" v-if="getShowFullHeaderRef" />
|
<LayoutHeader fixed v-if="getShowFullHeaderRef" />
|
||||||
<Layout>
|
<Layout>
|
||||||
<LayoutSideBar v-if="getShowSidebar" />
|
<LayoutSideBar v-if="getShowSidebar || getIsMobile" />
|
||||||
<Layout :class="`${prefixCls}__main`">
|
<Layout :class="`${prefixCls}__main`">
|
||||||
<LayoutMultipleHeader />
|
<LayoutMultipleHeader />
|
||||||
<LayoutContent />
|
<LayoutContent />
|
||||||
@@ -14,21 +14,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { Layout } from 'ant-design-vue';
|
import { Layout } from 'ant-design-vue';
|
||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||||
|
|
||||||
import LayoutHeader from './header/index.vue';
|
import LayoutHeader from './header/index.vue';
|
||||||
import LayoutContent from './content/index.vue';
|
import LayoutContent from './content/index.vue';
|
||||||
import LayoutSideBar from './sider';
|
import LayoutSideBar from './sider/index.vue';
|
||||||
import LayoutMultipleHeader from './header/LayoutMultipleHeader';
|
import LayoutMultipleHeader from './header/MultipleHeader.vue';
|
||||||
|
|
||||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
import { createLayoutContext } from './useLayoutContext';
|
|
||||||
|
|
||||||
import { registerGlobComp } from '/@/components/registerGlobComp';
|
import { registerGlobComp } from '/@/components/registerGlobComp';
|
||||||
|
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'DefaultLayout',
|
name: 'DefaultLayout',
|
||||||
@@ -47,11 +47,9 @@
|
|||||||
// default layout It is loaded after login. So it won’t be packaged to the first screen
|
// default layout It is loaded after login. So it won’t be packaged to the first screen
|
||||||
registerGlobComp();
|
registerGlobComp();
|
||||||
|
|
||||||
const headerRef = ref<ComponentRef>(null);
|
|
||||||
|
|
||||||
const { prefixCls } = useDesign('default-layout');
|
const { prefixCls } = useDesign('default-layout');
|
||||||
|
|
||||||
createLayoutContext({ fullHeader: headerRef });
|
const { getIsMobile } = useAppInject();
|
||||||
|
|
||||||
const { getShowFullHeaderRef } = useHeaderSetting();
|
const { getShowFullHeaderRef } = useHeaderSetting();
|
||||||
|
|
||||||
@@ -60,8 +58,8 @@
|
|||||||
return {
|
return {
|
||||||
getShowFullHeaderRef,
|
getShowFullHeaderRef,
|
||||||
getShowSidebar,
|
getShowSidebar,
|
||||||
headerRef,
|
|
||||||
prefixCls,
|
prefixCls,
|
||||||
|
getIsMobile,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
@import (reference) '../../../design/index.less';
|
@import (reference) '../../../design/index.less';
|
||||||
|
|
||||||
.layout-menu {
|
@prefix-cls: ~'@{namespace}-layout-menu';
|
||||||
&__logo {
|
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
|
&-logo {
|
||||||
height: @header-height;
|
height: @header-height;
|
||||||
padding: 10px 4px 10px 10px;
|
padding: 10px 4px 10px 10px;
|
||||||
|
|
||||||
@@ -10,4 +13,12 @@
|
|||||||
height: @logo-width;
|
height: @logo-width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--mobile {
|
||||||
|
.@{logo-prefix-cls} {
|
||||||
|
&__title {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
import { PropType, toRef } from 'vue';
|
import type { PropType, CSSProperties } from 'vue';
|
||||||
|
|
||||||
import { computed, defineComponent, unref } from 'vue';
|
import { computed, defineComponent, unref, toRef } from 'vue';
|
||||||
import { BasicMenu } from '/@/components/Menu';
|
import { BasicMenu } from '/@/components/Menu';
|
||||||
import { AppLogo } from '/@/components/Application';
|
import { AppLogo } from '/@/components/Application';
|
||||||
|
|
||||||
@@ -17,7 +17,8 @@ import { openWindow } from '/@/utils';
|
|||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
import { isUrl } from '/@/utils/is';
|
import { isUrl } from '/@/utils/is';
|
||||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||||
import { CSSProperties } from 'vue';
|
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||||
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'LayoutMenu',
|
name: 'LayoutMenu',
|
||||||
@@ -50,9 +51,15 @@ export default defineComponent({
|
|||||||
} = useMenuSetting();
|
} = useMenuSetting();
|
||||||
const { getShowLogo } = useRootSetting();
|
const { getShowLogo } = useRootSetting();
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('layout-menu');
|
||||||
|
|
||||||
const { menusRef } = useSplitMenu(toRef(props, 'splitType'));
|
const { menusRef } = useSplitMenu(toRef(props, 'splitType'));
|
||||||
|
|
||||||
const getComputedMenuMode = computed(() => props.menuMode || unref(getMenuMode));
|
const { getIsMobile } = useAppInject();
|
||||||
|
|
||||||
|
const getComputedMenuMode = computed(() =>
|
||||||
|
unref(getIsMobile) ? MenuModeEnum.INLINE : props.menuMode || unref(getMenuMode)
|
||||||
|
);
|
||||||
|
|
||||||
const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme));
|
const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme));
|
||||||
|
|
||||||
@@ -69,6 +76,16 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const getLogoClass = computed(() => {
|
||||||
|
return [
|
||||||
|
`${prefixCls}-logo`,
|
||||||
|
unref(getComputedMenuTheme),
|
||||||
|
{
|
||||||
|
[`${prefixCls}--mobile`]: unref(getIsMobile),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* click menu
|
* click menu
|
||||||
* @param menu
|
* @param menu
|
||||||
@@ -91,12 +108,12 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderHeader() {
|
function renderHeader() {
|
||||||
if (!unref(getIsShowLogo)) return null;
|
if (!unref(getIsShowLogo) && !unref(getIsMobile)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLogo
|
<AppLogo
|
||||||
showTitle={!unref(getCollapsed)}
|
showTitle={!unref(getCollapsed)}
|
||||||
class={[`layout-menu__logo`, unref(getComputedMenuTheme)]}
|
class={unref(getLogoClass)}
|
||||||
theme={unref(getComputedMenuTheme)}
|
theme={unref(getComputedMenuTheme)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -128,7 +145,6 @@ export default defineComponent({
|
|||||||
) : (
|
) : (
|
||||||
renderMenu()
|
renderMenu()
|
||||||
)}
|
)}
|
||||||
;
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -10,11 +10,13 @@ import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
|||||||
|
|
||||||
import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '/@/router/menus';
|
import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '/@/router/menus';
|
||||||
import { permissionStore } from '/@/store/modules/permission';
|
import { permissionStore } from '/@/store/modules/permission';
|
||||||
|
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||||
|
|
||||||
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
||||||
// Menu array
|
// Menu array
|
||||||
const menusRef = ref<Menu[]>([]);
|
const menusRef = ref<Menu[]>([]);
|
||||||
const { currentRoute } = useRouter();
|
const { currentRoute } = useRouter();
|
||||||
|
const { getIsMobile } = useAppInject();
|
||||||
const { setMenuSetting, getIsHorizontal, getSplit } = useMenuSetting();
|
const { setMenuSetting, getIsHorizontal, getSplit } = useMenuSetting();
|
||||||
|
|
||||||
const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
|
const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
|
||||||
@@ -36,7 +38,7 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
|||||||
watch(
|
watch(
|
||||||
[() => unref(currentRoute).path, () => unref(splitType)],
|
[() => unref(currentRoute).path, () => unref(splitType)],
|
||||||
async ([path]: [string, MenuSplitTyeEnum]) => {
|
async ([path]: [string, MenuSplitTyeEnum]) => {
|
||||||
if (unref(splitNotLeft)) return;
|
if (unref(splitNotLeft) || unref(getIsMobile)) return;
|
||||||
|
|
||||||
const parentPath = await getCurrentParentPath(path);
|
const parentPath = await getCurrentParentPath(path);
|
||||||
parentPath && throttleHandleSplitLeftMenu(parentPath);
|
parentPath && throttleHandleSplitLeftMenu(parentPath);
|
||||||
@@ -65,24 +67,24 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
|
|||||||
|
|
||||||
// Handle left menu split
|
// Handle left menu split
|
||||||
async function handleSplitLeftMenu(parentPath: string) {
|
async function handleSplitLeftMenu(parentPath: string) {
|
||||||
if (unref(getSplitLeft)) return;
|
if (unref(getSplitLeft) || unref(getIsMobile)) return;
|
||||||
|
|
||||||
// spilt mode left
|
// spilt mode left
|
||||||
const children = await getChildrenMenus(parentPath);
|
const children = await getChildrenMenus(parentPath);
|
||||||
if (!children) {
|
if (!children) {
|
||||||
setMenuSetting({ hidden: false });
|
setMenuSetting({ hidden: true });
|
||||||
menusRef.value = [];
|
menusRef.value = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setMenuSetting({ hidden: true });
|
setMenuSetting({ hidden: false });
|
||||||
menusRef.value = children;
|
menusRef.value = children;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get menus
|
// get menus
|
||||||
async function genMenus() {
|
async function genMenus() {
|
||||||
// normal mode
|
// normal mode
|
||||||
if (unref(normalType)) {
|
if (unref(normalType) || unref(getIsMobile)) {
|
||||||
menusRef.value = await getMenus();
|
menusRef.value = await getMenus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
67
src/layouts/default/sider/DragBar.vue
Normal file
67
src/layouts/default/sider/DragBar.vue
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="getClass" :style="getDragBarStyle" />
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, computed, unref } from 'vue';
|
||||||
|
|
||||||
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DargBar',
|
||||||
|
props: {
|
||||||
|
mobile: Boolean,
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const { getMiniWidthNumber, getCollapsed, getCanDrag } = useMenuSetting();
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('darg-bar');
|
||||||
|
const getDragBarStyle = computed(() => {
|
||||||
|
if (unref(getCollapsed)) {
|
||||||
|
return { left: `${unref(getMiniWidthNumber)}px` };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getClass = computed(() => {
|
||||||
|
return [
|
||||||
|
prefixCls,
|
||||||
|
{
|
||||||
|
[`${prefixCls}--hide`]: !unref(getCanDrag) || props.mobile,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
prefixCls,
|
||||||
|
getDragBarStyle,
|
||||||
|
getClass,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import (reference) '../../../design/index.less';
|
||||||
|
@prefix-cls: ~'@{namespace}-darg-bar';
|
||||||
|
|
||||||
|
.@{prefix-cls} {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -2px;
|
||||||
|
z-index: @side-drag-z-index;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
cursor: col-resize;
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: none;
|
||||||
|
|
||||||
|
&--hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: @primary-color;
|
||||||
|
box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -12,6 +12,7 @@ import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider';
|
|||||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
|
|
||||||
|
import DragBar from './DragBar.vue';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'LayoutSideBar',
|
name: 'LayoutSideBar',
|
||||||
setup() {
|
setup() {
|
||||||
@@ -31,11 +32,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
const { prefixCls } = useDesign('layout-sideBar');
|
const { prefixCls } = useDesign('layout-sideBar');
|
||||||
|
|
||||||
const { getTriggerAttr, getTriggerSlot } = useTrigger();
|
|
||||||
|
|
||||||
const { getIsMobile } = useAppInject();
|
const { getIsMobile } = useAppInject();
|
||||||
|
|
||||||
const { renderDragLine } = useDragLine(sideRef, dragBarRef);
|
const { getTriggerAttr, getTriggerSlot } = useTrigger(getIsMobile);
|
||||||
|
|
||||||
|
useDragLine(sideRef, dragBarRef);
|
||||||
|
|
||||||
const { getCollapsedWidth, onBreakpointChange, onCollapseChange } = useSiderEvent();
|
const { getCollapsedWidth, onBreakpointChange, onCollapseChange } = useSiderEvent();
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const showClassSideBarRef = computed(() => {
|
const showClassSideBarRef = computed(() => {
|
||||||
return unref(getSplit) ? unref(getMenuHidden) : true;
|
return unref(getSplit) ? !unref(getMenuHidden) : true;
|
||||||
});
|
});
|
||||||
|
|
||||||
const getSiderClass = computed(() => {
|
const getSiderClass = computed(() => {
|
||||||
@@ -57,7 +58,7 @@ export default defineComponent({
|
|||||||
{
|
{
|
||||||
[`${prefixCls}--fixed`]: unref(getMenuFixed),
|
[`${prefixCls}--fixed`]: unref(getMenuFixed),
|
||||||
hidden: !unref(showClassSideBarRef),
|
hidden: !unref(showClassSideBarRef),
|
||||||
[`${prefixCls}--mix`]: unref(getIsMixMode),
|
[`${prefixCls}--mix`]: unref(getIsMixMode) && !unref(getIsMobile),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
@@ -84,7 +85,7 @@ export default defineComponent({
|
|||||||
menuMode={unref(getMode)}
|
menuMode={unref(getMode)}
|
||||||
splitType={unref(getSplitType)}
|
splitType={unref(getSplitType)}
|
||||||
/>
|
/>
|
||||||
{renderDragLine()}
|
<DragBar ref={dragBarRef} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -101,7 +102,7 @@ export default defineComponent({
|
|||||||
collapsible
|
collapsible
|
||||||
class={unref(getSiderClass)}
|
class={unref(getSiderClass)}
|
||||||
width={unref(getMenuWidth)}
|
width={unref(getMenuWidth)}
|
||||||
collapsed={unref(getCollapsed)}
|
collapsed={unref(getIsMobile) ? false : unref(getCollapsed)}
|
||||||
collapsedWidth={unref(getCollapsedWidth)}
|
collapsedWidth={unref(getCollapsedWidth)}
|
||||||
theme={unref(getMenuTheme)}
|
theme={unref(getMenuTheme)}
|
||||||
onCollapse={onCollapseChange}
|
onCollapse={onCollapseChange}
|
@@ -44,27 +44,6 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__darg-bar {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: -2px;
|
|
||||||
z-index: @side-drag-z-index;
|
|
||||||
width: 2px;
|
|
||||||
height: 100%;
|
|
||||||
cursor: col-resize;
|
|
||||||
border-top: none;
|
|
||||||
border-bottom: none;
|
|
||||||
|
|
||||||
&.hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: @primary-color;
|
|
||||||
box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .ant-layout-sider-trigger {
|
& .ant-layout-sider-trigger {
|
||||||
height: 36px;
|
height: 36px;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
|
54
src/layouts/default/sider/index.vue
Normal file
54
src/layouts/default/sider/index.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<Drawer
|
||||||
|
v-if="getIsMobile"
|
||||||
|
placement="left"
|
||||||
|
:class="prefixCls"
|
||||||
|
:width="getMenuWidth"
|
||||||
|
:getContainer="null"
|
||||||
|
:visible="!getCollapsed"
|
||||||
|
@close="handleClose"
|
||||||
|
>
|
||||||
|
<Sider />
|
||||||
|
</Drawer>
|
||||||
|
<Sider v-else />
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
import Sider from './LayoutSider';
|
||||||
|
import { Drawer } from 'ant-design-vue';
|
||||||
|
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||||
|
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||||
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'SiderWrapper',
|
||||||
|
components: { Sider, Drawer },
|
||||||
|
setup() {
|
||||||
|
const { prefixCls } = useDesign('layout-sider-wrapper');
|
||||||
|
const { getIsMobile } = useAppInject();
|
||||||
|
const { setMenuSetting, getCollapsed, getMenuWidth } = useMenuSetting();
|
||||||
|
|
||||||
|
function handleClose() {
|
||||||
|
setMenuSetting({
|
||||||
|
collapsed: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { prefixCls, getIsMobile, getCollapsed, handleClose, getMenuWidth };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less">
|
||||||
|
@import (reference) '../../../design/index.less';
|
||||||
|
@prefix-cls: ~'@{namespace}-layout-sider-wrapper';
|
||||||
|
.@{prefix-cls} {
|
||||||
|
.ant-drawer-body {
|
||||||
|
height: 100vh;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-header-no-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -42,12 +42,17 @@ export function useSiderEvent() {
|
|||||||
/**
|
/**
|
||||||
* Handle related operations of menu folding
|
* Handle related operations of menu folding
|
||||||
*/
|
*/
|
||||||
export function useTrigger() {
|
export function useTrigger(getIsMobile: Ref<boolean>) {
|
||||||
const { getTrigger } = useMenuSetting();
|
const { getTrigger, getSplit } = useMenuSetting();
|
||||||
|
|
||||||
const showTrigger = computed(() => {
|
const showTrigger = computed(() => {
|
||||||
const trigger = unref(getTrigger);
|
const trigger = unref(getTrigger);
|
||||||
return trigger !== TriggerEnum.NONE && trigger === TriggerEnum.FOOTER;
|
|
||||||
|
return (
|
||||||
|
trigger !== TriggerEnum.NONE &&
|
||||||
|
!unref(getIsMobile) &&
|
||||||
|
(trigger === TriggerEnum.FOOTER || unref(getSplit))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const getTriggerAttr = computed(() => {
|
const getTriggerAttr = computed(() => {
|
||||||
@@ -77,14 +82,7 @@ export function useTrigger() {
|
|||||||
* @param dragBarRef
|
* @param dragBarRef
|
||||||
*/
|
*/
|
||||||
export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>) {
|
export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>) {
|
||||||
const { getMiniWidthNumber, getCollapsed, setMenuSetting, getCanDrag } = useMenuSetting();
|
const { getMiniWidthNumber, getCollapsed, setMenuSetting } = useMenuSetting();
|
||||||
|
|
||||||
const getDragBarStyle = computed(() => {
|
|
||||||
if (unref(getCollapsed)) {
|
|
||||||
return { left: `${unref(getMiniWidthNumber)}px` };
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -93,16 +91,6 @@ export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function renderDragLine() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
class={[`layout-sidebar__darg-bar`, { hide: !unref(getCanDrag) }]}
|
|
||||||
style={unref(getDragBarStyle)}
|
|
||||||
ref={dragBarRef}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMouseMove(ele: HTMLElement, wrap: HTMLElement, clientX: number) {
|
function handleMouseMove(ele: HTMLElement, wrap: HTMLElement, clientX: number) {
|
||||||
document.onmousemove = function (innerE) {
|
document.onmousemove = function (innerE) {
|
||||||
let iT = (ele as any).left + (innerE.clientX - clientX);
|
let iT = (ele as any).left + (innerE.clientX - clientX);
|
||||||
@@ -138,21 +126,22 @@ export function useDragLine(siderRef: Ref<any>, dragBarRef: Ref<any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function changeWrapWidth() {
|
function changeWrapWidth() {
|
||||||
const ele = unref(dragBarRef) as any;
|
const ele = unref(dragBarRef)?.$el;
|
||||||
|
if (!ele) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const side = unref(siderRef);
|
const side = unref(siderRef);
|
||||||
|
|
||||||
const wrap = (side || {}).$el;
|
const wrap = (side || {}).$el;
|
||||||
ele &&
|
ele.onmousedown = (e: any) => {
|
||||||
(ele.onmousedown = (e: any) => {
|
wrap.style.transition = 'unset';
|
||||||
wrap.style.transition = 'unset';
|
const clientX = e?.clientX;
|
||||||
const clientX = e?.clientX;
|
ele.left = ele.offsetLeft;
|
||||||
ele.left = ele.offsetLeft;
|
handleMouseMove(ele, wrap, clientX);
|
||||||
handleMouseMove(ele, wrap, clientX);
|
removeMouseup(ele);
|
||||||
removeMouseup(ele);
|
ele.setCapture?.();
|
||||||
ele.setCapture?.();
|
return false;
|
||||||
return false;
|
};
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { renderDragLine };
|
return {};
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
import { InjectionKey, Ref } from 'vue';
|
|
||||||
import { createContext, useContext } from '/@/hooks/core/useContext';
|
|
||||||
|
|
||||||
export interface LayoutContextProps {
|
|
||||||
fullHeader: Ref<ComponentRef>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const key: InjectionKey<LayoutContextProps> = Symbol();
|
|
||||||
|
|
||||||
export function createLayoutContext(context: LayoutContextProps) {
|
|
||||||
return createContext<LayoutContextProps>(context, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useLayoutContext() {
|
|
||||||
return useContext<LayoutContextProps>(key);
|
|
||||||
}
|
|
@@ -1,5 +1,6 @@
|
|||||||
export default {
|
export default {
|
||||||
search: 'Search',
|
search: 'Search',
|
||||||
|
cancel: 'Cancel',
|
||||||
searchNotData: 'No search results yet',
|
searchNotData: 'No search results yet',
|
||||||
toSearch: 'to search',
|
toSearch: 'to search',
|
||||||
toNavigate: 'to navigate',
|
toNavigate: 'to navigate',
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
export default {
|
export default {
|
||||||
search: '搜索',
|
search: '搜索',
|
||||||
|
cancel: '取消',
|
||||||
searchNotData: '暂无搜索结果',
|
searchNotData: '暂无搜索结果',
|
||||||
toSearch: '确认',
|
toSearch: '确认',
|
||||||
toNavigate: '切换',
|
toNavigate: '切换',
|
||||||
|
@@ -13,8 +13,9 @@ const key = Symbol();
|
|||||||
let lastChangeTab: RouteLocationNormalized;
|
let lastChangeTab: RouteLocationNormalized;
|
||||||
|
|
||||||
export function setLastChangeTab(lastChangeRoute: RouteLocationNormalized) {
|
export function setLastChangeTab(lastChangeRoute: RouteLocationNormalized) {
|
||||||
mitt.emit(key, getRoute(lastChangeRoute));
|
const r = getRoute(lastChangeRoute);
|
||||||
lastChangeTab = getRoute(lastChangeRoute);
|
mitt.emit(key, r);
|
||||||
|
lastChangeTab = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listenerLastChangeTab(
|
export function listenerLastChangeTab(
|
||||||
|
@@ -51,6 +51,5 @@ if (isDevMode()) {
|
|||||||
if (isProdMode() && isUseMock()) {
|
if (isProdMode() && isUseMock()) {
|
||||||
setupProdMockServer();
|
setupProdMockServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to share app instances in other modules
|
// Used to share app instances in other modules
|
||||||
setApp(app);
|
setApp(app);
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { AppRouteModule } from '/@/router/types.d';
|
import { AppRouteModule } from '/@/router/types.d';
|
||||||
import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
|
import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
|
||||||
|
|
||||||
import { findPath, forEach, treeMap, treeToList } from '/@/utils/helper/treeHelper';
|
import { findPath, forEach, treeMap } from '/@/utils/helper/treeHelper';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
import { isUrl } from '/@/utils/is';
|
import { isUrl } from '/@/utils/is';
|
||||||
|
|
||||||
@@ -10,10 +10,6 @@ export function getAllParentPath(treeData: any[], path: string) {
|
|||||||
return (menuList || []).map((item) => item.path);
|
return (menuList || []).map((item) => item.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flatMenus(menus: Menu[]) {
|
|
||||||
return treeToList(menus);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拼接父级路径
|
// 拼接父级路径
|
||||||
function joinParentPath(list: any, node: any) {
|
function joinParentPath(list: any, node: any) {
|
||||||
let allPaths = getAllParentPath(list, node.path);
|
let allPaths = getAllParentPath(list, node.path);
|
||||||
|
@@ -5,6 +5,10 @@ import { getParentLayout, LAYOUT } from '/@/router/constant';
|
|||||||
import dynamicImport from './dynamicImport';
|
import dynamicImport from './dynamicImport';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
|
export type LayoutMapKey = 'LAYOUT';
|
||||||
|
|
||||||
|
const LayoutMap = new Map<LayoutMapKey, () => Promise<typeof import('*.vue')>>();
|
||||||
|
|
||||||
// 动态引入
|
// 动态引入
|
||||||
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
||||||
if (!routes) return;
|
if (!routes) return;
|
||||||
@@ -20,16 +24,14 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLayoutComp(comp: string) {
|
|
||||||
return comp === 'LAYOUT' ? LAYOUT : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn background objects into routing objects
|
// Turn background objects into routing objects
|
||||||
export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
|
export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
|
||||||
|
LayoutMap.set('LAYOUT', LAYOUT);
|
||||||
|
|
||||||
routeList.forEach((route) => {
|
routeList.forEach((route) => {
|
||||||
if (route.component) {
|
if (route.component) {
|
||||||
if ((route.component as string).toUpperCase() === 'LAYOUT') {
|
if ((route.component as string).toUpperCase() === 'LAYOUT') {
|
||||||
route.component = getLayoutComp(route.component);
|
route.component = LayoutMap.get(route.component);
|
||||||
} else {
|
} else {
|
||||||
route.children = [cloneDeep(route)];
|
route.children = [cloneDeep(route)];
|
||||||
route.component = LAYOUT;
|
route.component = LAYOUT;
|
||||||
@@ -46,16 +48,6 @@ export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModul
|
|||||||
return (routeList as unknown) as T[];
|
return (routeList as unknown) as T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getParams(data: any = {}) {
|
|
||||||
const { params = {} } = data;
|
|
||||||
let ret = '';
|
|
||||||
Object.keys(params).forEach((key) => {
|
|
||||||
const p = params[key];
|
|
||||||
ret += `/${p}`;
|
|
||||||
});
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return to the new routing structure, not affected by the original example
|
// Return to the new routing structure, not affected by the original example
|
||||||
export function getRoute(route: RouteLocationNormalized): RouteLocationNormalized {
|
export function getRoute(route: RouteLocationNormalized): RouteLocationNormalized {
|
||||||
if (!route) return route;
|
if (!route) return route;
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
import type { Menu, MenuModule } from '/@/router/types';
|
import type { Menu, MenuModule } from '/@/router/types';
|
||||||
import type { RouteRecordNormalized } from 'vue-router';
|
import type { RouteRecordNormalized } from 'vue-router';
|
||||||
|
|
||||||
import { appStore } from '/@/store/modules/app';
|
import { appStore } from '/@/store/modules/app';
|
||||||
import { permissionStore } from '/@/store/modules/permission';
|
import { permissionStore } from '/@/store/modules/permission';
|
||||||
import { transformMenuModule, flatMenus, getAllParentPath } from '/@/router/helper/menuHelper';
|
import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper';
|
||||||
import { filter } from '/@/utils/helper/treeHelper';
|
import { filter } from '/@/utils/helper/treeHelper';
|
||||||
import router from '/@/router';
|
import router from '/@/router';
|
||||||
import { PermissionModeEnum } from '/@/enums/appEnum';
|
import { PermissionModeEnum } from '/@/enums/appEnum';
|
||||||
@@ -10,6 +11,8 @@ import { pathToRegexp } from 'path-to-regexp';
|
|||||||
|
|
||||||
import modules from 'globby!/@/router/menus/modules/**/*.@(ts)';
|
import modules from 'globby!/@/router/menus/modules/**/*.@(ts)';
|
||||||
|
|
||||||
|
const reg = /(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
|
||||||
|
|
||||||
const menuModules: MenuModule[] = [];
|
const menuModules: MenuModule[] = [];
|
||||||
|
|
||||||
Object.keys(modules).forEach((key) => {
|
Object.keys(modules).forEach((key) => {
|
||||||
@@ -38,18 +41,9 @@ const staticMenus: Menu[] = [];
|
|||||||
|
|
||||||
async function getAsyncMenus() {
|
async function getAsyncMenus() {
|
||||||
// 前端角色控制菜单 直接取菜单文件
|
// 前端角色控制菜单 直接取菜单文件
|
||||||
if (!isBackMode()) {
|
return !isBackMode() ? staticMenus : permissionStore.getBackMenuListState;
|
||||||
return staticMenus;
|
|
||||||
}
|
|
||||||
return permissionStore.getBackMenuListState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取深层扁平化菜单
|
|
||||||
export const getFlatMenus = async (): Promise<Menu[]> => {
|
|
||||||
const menus = await getAsyncMenus();
|
|
||||||
return flatMenus(menus);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取菜单 树级
|
// 获取菜单 树级
|
||||||
export const getMenus = async (): Promise<Menu[]> => {
|
export const getMenus = async (): Promise<Menu[]> => {
|
||||||
const menus = await getAsyncMenus();
|
const menus = await getAsyncMenus();
|
||||||
@@ -61,7 +55,7 @@ export const getMenus = async (): Promise<Menu[]> => {
|
|||||||
export async function getCurrentParentPath(currentPath: string) {
|
export async function getCurrentParentPath(currentPath: string) {
|
||||||
const menus = await getAsyncMenus();
|
const menus = await getAsyncMenus();
|
||||||
const allParentPath = await getAllParentPath(menus, currentPath);
|
const allParentPath = await getAllParentPath(menus, currentPath);
|
||||||
return allParentPath[0];
|
return allParentPath?.[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取1级菜单,删除children
|
// 获取1级菜单,删除children
|
||||||
@@ -81,27 +75,24 @@ export async function getChildrenMenus(parentPath: string) {
|
|||||||
return parent.children;
|
return parent.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 扁平化children
|
|
||||||
export async function getFlatChildrenMenus(children: Menu[]) {
|
|
||||||
return flatMenus(children);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通用过滤方法
|
// 通用过滤方法
|
||||||
function basicFilter(routes: RouteRecordNormalized[]) {
|
function basicFilter(routes: RouteRecordNormalized[]) {
|
||||||
return (menu: Menu) => {
|
return (menu: Menu) => {
|
||||||
const matchRoute = routes.find((route) => {
|
const matchRoute = routes.find((route) => {
|
||||||
if (route.meta.externalLink) {
|
const match = route.path.match(reg)?.[0];
|
||||||
|
if (match && match === menu.path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.meta) {
|
if (route.meta?.carryParam) {
|
||||||
if (route.meta.carryParam) {
|
return pathToRegexp(route.path).test(menu.path);
|
||||||
return pathToRegexp(route.path).test(menu.path);
|
|
||||||
}
|
|
||||||
if (route.meta.ignoreAuth) return true;
|
|
||||||
}
|
}
|
||||||
|
const isSame = route.path === menu.path;
|
||||||
|
if (!isSame) return false;
|
||||||
|
|
||||||
return route.path === menu.path;
|
if (route.meta?.ignoreAuth) return true;
|
||||||
|
|
||||||
|
return isSame || pathToRegexp(route.path).test(menu.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!matchRoute) return false;
|
if (!matchRoute) return false;
|
||||||
|
@@ -38,7 +38,6 @@ const iframe: AppRouteModule = {
|
|||||||
name: 'DocExternal',
|
name: 'DocExternal',
|
||||||
component: IFrame,
|
component: IFrame,
|
||||||
meta: {
|
meta: {
|
||||||
externalLink: true,
|
|
||||||
title: t('routes.demo.iframe.docExternal'),
|
title: t('routes.demo.iframe.docExternal'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
3
src/router/types.d.ts
vendored
3
src/router/types.d.ts
vendored
@@ -15,9 +15,6 @@ export interface RouteMeta {
|
|||||||
// icon on tab
|
// icon on tab
|
||||||
icon?: string;
|
icon?: string;
|
||||||
// Jump address
|
// Jump address
|
||||||
frameSrc?: string;
|
|
||||||
// Outer link jump address
|
|
||||||
externalLink?: boolean;
|
|
||||||
|
|
||||||
// current page transition
|
// current page transition
|
||||||
transitionName?: string;
|
transitionName?: string;
|
||||||
|
@@ -89,7 +89,7 @@ const setting: ProjectConfig = {
|
|||||||
// Whether to show no dom
|
// Whether to show no dom
|
||||||
show: true,
|
show: true,
|
||||||
// Whether to show dom
|
// Whether to show dom
|
||||||
hidden: true,
|
hidden: false,
|
||||||
// Menu width
|
// Menu width
|
||||||
menuWidth: 210,
|
menuWidth: 210,
|
||||||
// Menu mode
|
// Menu mode
|
||||||
|
@@ -50,7 +50,7 @@ export function isRegExp(val: unknown): val is RegExp {
|
|||||||
return is(val, 'RegExp');
|
return is(val, 'RegExp');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isArray(val: unknown): val is Array<any> {
|
export function isArray(val: any): val is Array<any> {
|
||||||
return val && Array.isArray(val);
|
return val && Array.isArray(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -221,25 +221,35 @@
|
|||||||
font-size: 23em;
|
font-size: 23em;
|
||||||
}
|
}
|
||||||
@media (min-width: @screen-sm-max) and (max-width: @screen-md-max) {
|
@media (min-width: @screen-sm-max) and (max-width: @screen-md-max) {
|
||||||
font-size: 19em;
|
height: 50%;
|
||||||
|
font-size: 12em;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.meridiem {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media (min-width: @screen-xs-max) and (max-width: @screen-sm-max) {
|
@media (min-width: @screen-xs-max) and (max-width: @screen-sm-max) {
|
||||||
font-size: 13em;
|
font-size: 13em;
|
||||||
}
|
}
|
||||||
@media (max-width: @screen-xs) {
|
@media (max-width: @screen-xs) {
|
||||||
height: 50%;
|
height: 30%;
|
||||||
font-size: 6em;
|
font-size: 5em;
|
||||||
border-radius: 20px;
|
border-radius: 10px;
|
||||||
|
|
||||||
|
.meridiem {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__footer-date {
|
&__footer-date {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
left: 50%;
|
width: 100%;
|
||||||
font-family: helvetica;
|
font-family: helvetica;
|
||||||
color: #bababa;
|
color: #bababa;
|
||||||
transform: translate(-50%, 0);
|
text-align: center;
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
|
73
yarn.lock
73
yarn.lock
@@ -1051,43 +1051,43 @@
|
|||||||
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.272.tgz#27c7caee9764e0304161261ec08ffc2794944b66"
|
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.272.tgz#27c7caee9764e0304161261ec08ffc2794944b66"
|
||||||
integrity sha512-FyiTc7UiXJ5cDfk09lv70sYOSi5uLyK+a0LnF1KgWmofkikL06p98ksNRN7stmHryOYarSy75xgi6MbgAwtltQ==
|
integrity sha512-FyiTc7UiXJ5cDfk09lv70sYOSi5uLyK+a0LnF1KgWmofkikL06p98ksNRN7stmHryOYarSy75xgi6MbgAwtltQ==
|
||||||
|
|
||||||
"@intlify/core@9.0.0-beta.12":
|
"@intlify/core-base@9.0.0-beta.13":
|
||||||
version "9.0.0-beta.12"
|
version "9.0.0-beta.13"
|
||||||
resolved "https://registry.npmjs.org/@intlify/core/-/core-9.0.0-beta.12.tgz#f7d2d09060b8e00ae37157e00a0daa1c86290802"
|
resolved "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.0.0-beta.13.tgz#fb6bc278209cb7bef44853a42160fedb0560c3f8"
|
||||||
integrity sha512-0wdOS9d0ZEvGkbNIdaxEHQQOfAIuhv1Q8CSpNImThh8ZDD+5Sa38wTerHBO0/Rk0HfHUP/hjPqbxxRqITmSo1g==
|
integrity sha512-ukImWV+QvRmNZtCTLrSW391z46eMuBheCMPZh801nM3v0Dosfu2PtWO5/z8Q9Bsom4Q+PNQ5eBtOQj2yCAhVEA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@intlify/message-compiler" "9.0.0-beta.12"
|
"@intlify/message-compiler" "9.0.0-beta.13"
|
||||||
"@intlify/message-resolver" "9.0.0-beta.12"
|
"@intlify/message-resolver" "9.0.0-beta.13"
|
||||||
"@intlify/runtime" "9.0.0-beta.12"
|
"@intlify/runtime" "9.0.0-beta.13"
|
||||||
"@intlify/shared" "9.0.0-beta.12"
|
"@intlify/shared" "9.0.0-beta.13"
|
||||||
|
|
||||||
"@intlify/message-compiler@9.0.0-beta.12":
|
"@intlify/message-compiler@9.0.0-beta.13":
|
||||||
version "9.0.0-beta.12"
|
version "9.0.0-beta.13"
|
||||||
resolved "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.0.0-beta.12.tgz#836a49cfd057ecb2c536680cc01aa16693211891"
|
resolved "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.0.0-beta.13.tgz#3b8ddcb2be3f80b28c6e4f6028c0b3ec4e709849"
|
||||||
integrity sha512-EMzBDBIsFvWV9w0tRAHzn2BD1C7nkJkXYwDWinROmoL6C4jgKUgon+9Uxp7lV0H1E+7hUfhGj6zHdtJrwFhH+g==
|
integrity sha512-1z7716InFM8FdTAz64wqZvFuT4wL7WKF63v+vUEW4s9FLoL0U+xIccor9P5XHAvvG1gPMH/Zxd0deg/ULZ1Mcg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@intlify/message-resolver" "9.0.0-beta.12"
|
"@intlify/message-resolver" "9.0.0-beta.13"
|
||||||
"@intlify/shared" "9.0.0-beta.12"
|
"@intlify/shared" "9.0.0-beta.13"
|
||||||
source-map "0.6.1"
|
source-map "0.6.1"
|
||||||
|
|
||||||
"@intlify/message-resolver@9.0.0-beta.12":
|
"@intlify/message-resolver@9.0.0-beta.13":
|
||||||
version "9.0.0-beta.12"
|
version "9.0.0-beta.13"
|
||||||
resolved "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.0.0-beta.12.tgz#98cf346f5da0fdf3408ba132c24841295a4e02db"
|
resolved "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.0.0-beta.13.tgz#ae6de0bf0e54093160442d465e719bf03fd0f146"
|
||||||
integrity sha512-i8bmWzhiBH59YED3SXqvdUfwecl7OUPOU/8yvfdhg2rXuZ4e2chCPnLpPafXz6bi88HcRsWF4aRGlpwDVDYadg==
|
integrity sha512-mR1eSpRtB4jh11TpQTUyzjEwqZ6D30mJYREEfSrl5YKfUKwDQrulrOaIO8T5gVQG2m09vfxJHVrgfJ2hR8z/0Q==
|
||||||
|
|
||||||
"@intlify/runtime@9.0.0-beta.12":
|
"@intlify/runtime@9.0.0-beta.13":
|
||||||
version "9.0.0-beta.12"
|
version "9.0.0-beta.13"
|
||||||
resolved "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.0.0-beta.12.tgz#647a62a326d92690569798ef046d29e8daa25c96"
|
resolved "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.0.0-beta.13.tgz#8deff103ee6982c6d531314e9f965b90768d8a27"
|
||||||
integrity sha512-4ucZHqk/VGhrQEgu9xU5tE/sJTNfqKBhQtaXyEgYHchL9PvLoS1HFwPjABHvWjo3aVcv4d2cGtUPBwH4oLROKA==
|
integrity sha512-hcb3sg75SokuzNDG8IC6PJmwjsS/xdgevd99UNG1zKb7s5qFFb90ApvPDpiH0+R9TMQe11fZqg5dyrVBKqAV4A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@intlify/message-compiler" "9.0.0-beta.12"
|
"@intlify/message-compiler" "9.0.0-beta.13"
|
||||||
"@intlify/message-resolver" "9.0.0-beta.12"
|
"@intlify/message-resolver" "9.0.0-beta.13"
|
||||||
"@intlify/shared" "9.0.0-beta.12"
|
"@intlify/shared" "9.0.0-beta.13"
|
||||||
|
|
||||||
"@intlify/shared@9.0.0-beta.12":
|
"@intlify/shared@9.0.0-beta.13":
|
||||||
version "9.0.0-beta.12"
|
version "9.0.0-beta.13"
|
||||||
resolved "https://registry.npmjs.org/@intlify/shared/-/shared-9.0.0-beta.12.tgz#e939575bc4047411b9fc65347779f5b3173c1130"
|
resolved "https://registry.npmjs.org/@intlify/shared/-/shared-9.0.0-beta.13.tgz#2d93d695f19fd699ea8b336066f9d6dfc185f094"
|
||||||
integrity sha512-XtHAzQ2KBcdN0Khc7ZDCo5GnKQK4Vv0GKD1BplCWntpA2d5XqjdDpFuKumvbiOjPvYtuCFnksJU0OgJiCWG+KQ==
|
integrity sha512-/rqC3YEGHs3uu3XSsF1zdBKJb+on34Yn8Z58K3YxJsFxKPHa8mH73EUtN79hTZWh6Js4zEa/WsCgZCM62b8eJA==
|
||||||
|
|
||||||
"@koa/cors@^3.1.0":
|
"@koa/cors@^3.1.0":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
@@ -8256,16 +8256,13 @@ vue-eslint-parser@^7.3.0:
|
|||||||
esquery "^1.0.1"
|
esquery "^1.0.1"
|
||||||
lodash "^4.17.15"
|
lodash "^4.17.15"
|
||||||
|
|
||||||
vue-i18n@^9.0.0-beta.12:
|
vue-i18n@^9.0.0-beta.13:
|
||||||
version "9.0.0-beta.12"
|
version "9.0.0-beta.13"
|
||||||
resolved "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.0.0-beta.12.tgz#f6e2fc1cc366b8f16aa4754642931e937ebde303"
|
resolved "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.0.0-beta.13.tgz#89cf5dd1566025f441132231d15ed621ef70ba96"
|
||||||
integrity sha512-hDnr+GsIGCIKRtZsdDczkhqyzbpLuPgEkH5bQyMzrKTLelXipLvIVmUCAsSjyR7xMHDCwP6AwVTIZwk6ENXkwg==
|
integrity sha512-ZN6r5ITODu9NYAAbe1IGVUkNeamuleaXTLn5NMn/YZQ+5NSjDjysyVZVLkVOEOIw6bT2tLveyjsWlAZBVtfcPw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@intlify/core" "9.0.0-beta.12"
|
"@intlify/core-base" "9.0.0-beta.13"
|
||||||
"@intlify/message-compiler" "9.0.0-beta.12"
|
"@intlify/shared" "9.0.0-beta.13"
|
||||||
"@intlify/message-resolver" "9.0.0-beta.12"
|
|
||||||
"@intlify/runtime" "9.0.0-beta.12"
|
|
||||||
"@intlify/shared" "9.0.0-beta.12"
|
|
||||||
"@vue/devtools-api" "^6.0.0-beta.2"
|
"@vue/devtools-api" "^6.0.0-beta.2"
|
||||||
|
|
||||||
vue-router@^4.0.1:
|
vue-router@^4.0.1:
|
||||||
|
Reference in New Issue
Block a user