Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
jxf111348
vue-vben-admin
提交
27e50b47
V
vue-vben-admin
项目概览
jxf111348
/
vue-vben-admin
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vue-vben-admin
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
27e50b47
编写于
12月 13, 2020
作者:
V
vben
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
perf(tabs): perf multiple-tabs
上级
ed41e508
变更
35
隐藏空白更改
内联
并排
Showing
35 changed file
with
593 addition
and
401 deletion
+593
-401
src/components/Dropdown/index.ts
src/components/Dropdown/index.ts
+2
-2
src/components/Menu/src/BasicMenu.tsx
src/components/Menu/src/BasicMenu.tsx
+1
-0
src/hooks/setting/useMenuSetting.ts
src/hooks/setting/useMenuSetting.ts
+11
-0
src/layouts/default/LayoutTrigger.tsx
src/layouts/default/LayoutTrigger.tsx
+0
-42
src/layouts/default/content/index.vue
src/layouts/default/content/index.vue
+2
-2
src/layouts/default/feature/index.vue
src/layouts/default/feature/index.vue
+29
-0
src/layouts/default/footer/index.less
src/layouts/default/footer/index.less
+0
-28
src/layouts/default/footer/index.tsx
src/layouts/default/footer/index.tsx
+0
-34
src/layouts/default/footer/index.vue
src/layouts/default/footer/index.vue
+74
-0
src/layouts/default/header/LayoutHeader.tsx
src/layouts/default/header/LayoutHeader.tsx
+1
-1
src/layouts/default/header/LayoutMultipleHeader.tsx
src/layouts/default/header/LayoutMultipleHeader.tsx
+1
-1
src/layouts/default/header/index.less
src/layouts/default/header/index.less
+2
-1
src/layouts/default/index.tsx
src/layouts/default/index.tsx
+12
-45
src/layouts/default/index.vue
src/layouts/default/index.vue
+95
-0
src/layouts/default/multitabs/TabContent.tsx
src/layouts/default/multitabs/TabContent.tsx
+0
-78
src/layouts/default/multitabs/index.tsx
src/layouts/default/multitabs/index.tsx
+0
-114
src/layouts/default/setting/index.vue
src/layouts/default/setting/index.vue
+1
-1
src/layouts/default/sider/useLayoutSider.tsx
src/layouts/default/sider/useLayoutSider.tsx
+1
-1
src/layouts/default/tabs/components/QuickButton.vue
src/layouts/default/tabs/components/QuickButton.vue
+21
-0
src/layouts/default/tabs/components/TabContent.vue
src/layouts/default/tabs/components/TabContent.vue
+72
-0
src/layouts/default/tabs/index.less
src/layouts/default/tabs/index.less
+58
-32
src/layouts/default/tabs/index.vue
src/layouts/default/tabs/index.vue
+123
-0
src/layouts/default/tabs/types.ts
src/layouts/default/tabs/types.ts
+0
-0
src/layouts/default/tabs/useMultipleTabs.ts
src/layouts/default/tabs/useMultipleTabs.ts
+4
-3
src/layouts/default/tabs/useTabDropdown.ts
src/layouts/default/tabs/useTabDropdown.ts
+0
-0
src/layouts/default/trigger/HeaderTrigger.vue
src/layouts/default/trigger/HeaderTrigger.vue
+25
-0
src/layouts/default/trigger/SiderTrigger.vue
src/layouts/default/trigger/SiderTrigger.vue
+18
-0
src/layouts/default/trigger/index.vue
src/layouts/default/trigger/index.vue
+21
-0
src/layouts/iframe/index.vue
src/layouts/iframe/index.vue
+9
-7
src/layouts/iframe/useFrameKeepAlive.ts
src/layouts/iframe/useFrameKeepAlive.ts
+3
-3
src/layouts/page/index.tsx
src/layouts/page/index.tsx
+2
-0
src/layouts/page/useCache.ts
src/layouts/page/useCache.ts
+0
-1
src/locales/lang/en/layout/multipleTab.ts
src/locales/lang/en/layout/multipleTab.ts
+2
-2
src/locales/lang/zh_CN/layout/multipleTab.ts
src/locales/lang/zh_CN/layout/multipleTab.ts
+2
-2
src/router/constant.ts
src/router/constant.ts
+1
-1
未找到文件。
src/components/Dropdown/index.ts
浏览文件 @
27e50b47
import
{
withInstall
}
from
'
../util
'
;
import
{
createAsyncComponent
}
from
'
/@/utils/factory/createAsyncComponent
'
;
export
const
Dropdown
=
createAsyncComponent
(()
=>
import
(
'
./src/Dropdown
'
));
import
Dropdown
from
'
./src/Dropdown
'
;
withInstall
(
Dropdown
);
export
*
from
'
./src/types
'
;
export
{
Dropdown
};
src/components/Menu/src/BasicMenu.tsx
浏览文件 @
27e50b47
...
...
@@ -243,6 +243,7 @@ export default defineComponent({
onOpenChange
=
{
handleOpenChange
}
class
=
{
unref
(
getMenuClass
)
}
onClick
=
{
handleMenuClick
}
subMenuOpenDelay
=
{
0.2
}
{
...
unref
(
getInlineCollapseOptions
)
}
>
{
{
...
...
src/hooks/setting/useMenuSetting.ts
浏览文件 @
27e50b47
...
...
@@ -6,6 +6,7 @@ import { appStore } from '/@/store/modules/app';
import
{
SIDE_BAR_MINI_WIDTH
,
SIDE_BAR_SHOW_TIT_MINI_WIDTH
}
from
'
/@/enums/appEnum
'
;
import
{
MenuModeEnum
,
MenuTypeEnum
,
TriggerEnum
}
from
'
/@/enums/menuEnum
'
;
import
{
useFullContent
}
from
'
/@/hooks/web/useFullContent
'
;
// Get menu configuration
const
getMenuSetting
=
computed
(()
=>
appStore
.
getProjectConfig
.
menuSetting
);
...
...
@@ -78,6 +79,15 @@ const getCalcContentWidth = computed(() => {
return
`calc(100% -
${
unref
(
width
)}
px)`
;
});
const
{
getFullContent
:
fullContent
}
=
useFullContent
();
const
getShowSidebar
=
computed
(()
=>
{
return
(
unref
(
getSplit
)
||
(
unref
(
getShowMenu
)
&&
unref
(
getMenuMode
)
!==
MenuModeEnum
.
HORIZONTAL
&&
!
unref
(
fullContent
))
);
});
// Set menu configuration
function
setMenuSetting
(
menuSetting
:
Partial
<
MenuSetting
>
):
void
{
appStore
.
commitProjectConfigState
({
menuSetting
});
...
...
@@ -119,5 +129,6 @@ export function useMenuSetting() {
getMenuHidden
,
getIsTopMenu
,
getMenuBgColor
,
getShowSidebar
,
};
}
src/layouts/default/LayoutTrigger.tsx
已删除
100644 → 0
浏览文件 @
ed41e508
import
type
{
FunctionalComponent
}
from
'
vue
'
;
import
{
defineComponent
,
unref
}
from
'
vue
'
;
import
{
DoubleRightOutlined
,
DoubleLeftOutlined
,
MenuUnfoldOutlined
,
MenuFoldOutlined
,
}
from
'
@ant-design/icons-vue
'
;
import
{
useMenuSetting
}
from
'
/@/hooks/setting/useMenuSetting
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
const
SiderTrigger
:
FunctionalComponent
=
()
=>
{
const
{
getCollapsed
}
=
useMenuSetting
();
return
unref
(
getCollapsed
)
?
<
DoubleRightOutlined
/>
:
<
DoubleLeftOutlined
/>;
};
const
HeaderTrigger
:
FunctionalComponent
<
{
theme
?:
string
;
}
>
=
(
props
)
=>
{
const
{
toggleCollapsed
,
getCollapsed
}
=
useMenuSetting
();
return
(
<
span
class
=
{
[
'
layout-trigger
'
,
props
.
theme
]
}
onClick
=
{
toggleCollapsed
}
>
{
unref
(
getCollapsed
)
?
<
MenuUnfoldOutlined
/>
:
<
MenuFoldOutlined
/>
}
</
span
>
);
};
export
default
defineComponent
({
name
:
'
LayoutTrigger
'
,
props
:
{
sider
:
propTypes
.
bool
.
def
(
true
),
theme
:
propTypes
.
oneOf
([
'
light
'
,
'
dark
'
]),
},
setup
(
props
)
{
return
()
=>
{
return
props
.
sider
?
<
SiderTrigger
/>
:
<
HeaderTrigger
theme
=
{
props
.
theme
}
/>;
};
},
});
src/layouts/default/content/index.vue
浏览文件 @
27e50b47
...
...
@@ -6,7 +6,7 @@
:loading=
"getPageLoading"
background=
"rgba(240, 242, 245, 0.6)"
absolute
:class=
"`$
{prefixCls}
__
loading`"
:class=
"`$
{prefixCls}
-
loading`"
/>
</transition>
<PageLayout
/>
...
...
@@ -53,7 +53,7 @@
margin: 0 auto;
}
&
__
loading {
&
-
loading {
position: absolute;
top: 200px;
z-index: @page-loading-z-index;
...
...
src/layouts/default/feature/index.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<LayoutLockPage
/>
<BackTop
v-if=
"getUseOpenBackTop"
:target=
"getTarget"
/>
<SettingDrawer
v-if=
"getShowSettingButton"
/>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
createAsyncComponent
}
from
'
/@/utils/factory/createAsyncComponent
'
;
import
{
BackTop
}
from
'
ant-design-vue
'
;
import
{
useRootSetting
}
from
'
/@/hooks/setting/useRootSetting
'
;
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
,
getShowSettingButton
}
=
useRootSetting
();
return
{
getTarget
:
()
=>
document
.
body
,
getUseOpenBackTop
,
getShowSettingButton
,
};
},
});
</
script
>
src/layouts/default/footer/index.less
已删除
100644 → 0
浏览文件 @
ed41e508
@normal-color: rgba(0, 0, 0, 0.45);
@hover-color: rgba(0, 0, 0, 0.85);
.layout-footer {
color: @normal-color;
text-align: center;
&__links {
margin-bottom: 8px;
a {
color: @normal-color;
&:hover {
color: @hover-color;
}
}
.github {
margin: 0 30px;
&:hover {
color: @hover-color;
}
}
}
}
src/layouts/default/footer/index.tsx
已删除
100644 → 0
浏览文件 @
ed41e508
import
'
./index.less
'
;
import
{
defineComponent
}
from
'
vue
'
;
import
{
Layout
}
from
'
ant-design-vue
'
;
import
{
GithubFilled
}
from
'
@ant-design/icons-vue
'
;
import
{
DOC_URL
,
GITHUB_URL
,
SITE_URL
}
from
'
/@/settings/siteSetting
'
;
import
{
openWindow
}
from
'
/@/utils
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
export
default
defineComponent
({
name
:
'
LayoutContent
'
,
setup
()
{
const
{
t
}
=
useI18n
();
return
()
=>
{
return
(
<
Layout
.
Footer
class
=
"layout-footer"
>
{
()
=>
(
<>
<
div
class
=
"layout-footer__links"
>
<
a
onClick
=
{
()
=>
openWindow
(
SITE_URL
)
}
>
{
t
(
'
layout.footer.onlinePreview
'
)
}
</
a
>
<
GithubFilled
onClick
=
{
()
=>
openWindow
(
GITHUB_URL
)
}
class
=
"github"
/>
<
a
onClick
=
{
()
=>
openWindow
(
DOC_URL
)
}
>
{
t
(
'
layout.footer.onlineDocument
'
)
}
</
a
>
</
div
>
<
div
>
Copyright
©
2020 Vben Admin
</
div
>
</>
)
}
</
Layout
.
Footer
>
);
};
},
});
src/layouts/default/footer/index.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<Footer
:class=
"prefixCls"
v-if=
"getShowLayoutFooter"
>
<div
:class=
"`$
{prefixCls}__links`">
<a
@
click=
"openWindow(SITE_URL)"
>
{{
t
(
'
layout.footer.onlinePreview
'
)
}}
</a>
<GithubFilled
@
click=
"openWindow(GITHUB_URL)"
:class=
"`$
{prefixCls}__github`" />
<a
@
click=
"openWindow(DOC_URL)"
>
{{
t
(
'
layout.footer.onlineDocument
'
)
}}
</a>
</div>
<div>
Copyright
©
2020 Vben Admin
</div>
</Footer>
</
template
>
<
script
lang=
"ts"
>
import
{
computed
,
defineComponent
,
unref
}
from
'
vue
'
;
import
{
Layout
}
from
'
ant-design-vue
'
;
import
{
GithubFilled
}
from
'
@ant-design/icons-vue
'
;
import
{
DOC_URL
,
GITHUB_URL
,
SITE_URL
}
from
'
/@/settings/siteSetting
'
;
import
{
openWindow
}
from
'
/@/utils
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
useRootSetting
}
from
'
/@/hooks/setting/useRootSetting
'
;
import
{
useRouter
}
from
'
vue-router
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
export
default
defineComponent
({
name
:
'
LayoutFooter
'
,
components
:
{
Footer
:
Layout
.
Footer
,
GithubFilled
},
setup
()
{
const
{
t
}
=
useI18n
();
const
{
getShowFooter
}
=
useRootSetting
();
const
{
currentRoute
}
=
useRouter
();
const
{
prefixCls
}
=
useDesign
(
'
layout-footer
'
);
const
getShowLayoutFooter
=
computed
(()
=>
{
return
unref
(
getShowFooter
)
&&
!
unref
(
currentRoute
).
meta
?.
hiddenFooter
;
});
return
{
getShowLayoutFooter
,
prefixCls
,
t
,
DOC_URL
,
GITHUB_URL
,
SITE_URL
,
openWindow
};
},
});
</
script
>
<
style
lang=
"less"
scoped
>
@import (reference) '../../../design/index.less';
@prefix-cls: ~'@{namespace}-layout-footer';
@normal-color: rgba(0, 0, 0, 0.45);
@hover-color: rgba(0, 0, 0, 0.85);
.@{prefix-cls} {
color: @normal-color;
text-align: center;
&__links {
margin-bottom: 8px;
a {
color: @normal-color;
&:hover {
color: @hover-color;
}
}
}
&__github {
margin: 0 30px;
&:hover {
color: @hover-color;
}
}
}
</
style
>
src/layouts/default/header/LayoutHeader.tsx
浏览文件 @
27e50b47
...
...
@@ -19,7 +19,7 @@ import UserDropdown from './UserDropdown';
import
LayoutMenu
from
'
../menu
'
;
import
LayoutBreadcrumb
from
'
./LayoutBreadcrumb.vue
'
;
import
LockAction
from
'
./actions/LockAction
'
;
import
LayoutTrigger
from
'
../
LayoutTrigger
'
;
import
LayoutTrigger
from
'
../
trigger/index.vue
'
;
import
NoticeAction
from
'
./notice/NoticeActionItem.vue
'
;
import
{
RedoOutlined
,
...
...
src/layouts/default/header/LayoutMultipleHeader.tsx
浏览文件 @
27e50b47
...
...
@@ -3,7 +3,7 @@ import './LayoutMultipleHeader.less';
import
{
defineComponent
,
unref
,
computed
,
ref
,
watch
,
nextTick
,
CSSProperties
}
from
'
vue
'
;
import
LayoutHeader
from
'
./LayoutHeader
'
;
import
MultipleTabs
from
'
../
multitabs/index
'
;
import
MultipleTabs
from
'
../
tabs/index.vue
'
;
import
{
useHeaderSetting
}
from
'
/@/hooks/setting/useHeaderSetting
'
;
import
{
useMenuSetting
}
from
'
/@/hooks/setting/useMenuSetting
'
;
...
...
src/layouts/default/header/index.less
浏览文件 @
27e50b47
@import (reference) '../../../design/index.less';
@header-trigger-prefix-cls: ~'@{namespace}-layout-header-trigger';
.layout-header {
display: flex;
...
...
@@ -24,7 +25,7 @@
height: 100%;
align-items: center;
.
layout-trigger
{
.
@{header-trigger-prefix-cls}
{
display: flex;
height: 100%;
padding: 1px 10px 0 16px;
...
...
src/layouts/default/index.tsx
浏览文件 @
27e50b47
import
'
./index.less
'
;
import
{
defineComponent
,
unref
,
computed
,
ref
}
from
'
vue
'
;
import
{
Layout
,
BackTop
}
from
'
ant-design-vue
'
;
import
LayoutHeader
from
'
./header/LayoutHeader
'
;
import
{
defineComponent
,
unref
,
ref
}
from
'
vue
'
;
import
{
Layout
}
from
'
ant-design-vue
'
;
import
{
createAsyncComponent
}
from
'
/@/utils/factory/createAsyncComponent
'
;
import
LayoutHeader
from
'
./header/LayoutHeader
'
;
import
LayoutContent
from
'
./content/index.vue
'
;
import
LayoutFooter
from
'
./footer
'
;
import
LayoutLockPage
from
'
/@/views/sys/lock/index.vue
'
;
import
LayoutSideBar
from
'
./sider
'
;
import
SettingBtn
from
'
./setting/index.vue
'
;
import
LayoutMultipleHeader
from
'
./header/LayoutMultipleHeader
'
;
import
{
MenuModeEnum
}
from
'
/@/enums/menuEnum
'
;
import
{
useRouter
}
from
'
vue-router
'
;
import
{
useFullContent
}
from
'
/@/hooks/web/useFullContent
'
;
import
{
useHeaderSetting
}
from
'
/@/hooks/setting/useHeaderSetting
'
;
import
{
useMenuSetting
}
from
'
/@/hooks/setting/useMenuSetting
'
;
import
{
useRootSetting
}
from
'
/@/hooks/setting/useRootSetting
'
;
import
{
createLayoutContext
}
from
'
./useLayoutContext
'
;
import
{
registerGlobComp
}
from
'
/@/components/registerGlobComp
'
;
import
{
createBreakpointListen
}
from
'
/@/hooks/event/useBreakpoint
'
;
import
{
isMobile
}
from
'
/@/utils/is
'
;
const
LayoutFeatures
=
createAsyncComponent
(()
=>
import
(
'
/@/layouts/default/feature/index.vue
'
));
const
LayoutFooter
=
createAsyncComponent
(()
=>
import
(
'
/@/layouts/default/footer/index.vue
'
));
export
default
defineComponent
({
name
:
'
DefaultLayout
'
,
setup
()
{
const
{
currentRoute
}
=
useRouter
();
const
headerRef
=
ref
<
ComponentRef
>
(
null
);
const
isMobileRef
=
ref
(
false
);
...
...
@@ -43,56 +39,27 @@ export default defineComponent({
const
{
getShowFullHeaderRef
}
=
useHeaderSetting
();
const
{
getUseOpenBackTop
,
getShowSettingButton
,
getShowFooter
}
=
useRootSetting
();
const
{
getShowMenu
,
getMenuMode
,
getSplit
}
=
useMenuSetting
();
const
{
getFullContent
}
=
useFullContent
();
const
getShowLayoutFooter
=
computed
(()
=>
{
return
unref
(
getShowFooter
)
&&
!
unref
(
currentRoute
).
meta
?.
hiddenFooter
;
});
const
showSideBarRef
=
computed
(()
=>
{
return
(
unref
(
getSplit
)
||
(
unref
(
getShowMenu
)
&&
unref
(
getMenuMode
)
!==
MenuModeEnum
.
HORIZONTAL
&&
!
unref
(
getFullContent
))
);
});
function
renderFeatures
()
{
return
(
<>
<
LayoutLockPage
/>
{
/* back top */
}
{
unref
(
getUseOpenBackTop
)
&&
<
BackTop
target
=
{
()
=>
document
.
body
}
/>
}
{
/* open setting drawer */
}
{
unref
(
getShowSettingButton
)
&&
<
SettingBtn
/>
}
</>
);
}
const
{
getShowSidebar
}
=
useMenuSetting
();
return
()
=>
{
return
(
<
Layout
class
=
"default-layout"
>
{
()
=>
(
<>
{
renderFeatures
()
}
<
LayoutFeatures
/>
{
unref
(
getShowFullHeaderRef
)
&&
<
LayoutHeader
fixed
=
{
true
}
ref
=
{
headerRef
}
/>
}
<
Layout
>
{
()
=>
(
<>
{
unref
(
showSideBarRef
)
&&
<
LayoutSideBar
/>
}
{
unref
(
getShowSidebar
)
&&
<
LayoutSideBar
/>
}
<
Layout
class
=
"default-layout__main"
>
{
()
=>
(
<>
<
LayoutMultipleHeader
/>
<
LayoutContent
/>
{
unref
(
getShowLayoutFooter
)
&&
<
LayoutFooter
/>
}
<
LayoutFooter
/>
</>
)
}
</
Layout
>
...
...
src/layouts/default/index.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<Layout
:class=
"prefixCls"
>
<LayoutFeatures
/>
<LayoutHeader
fixed
ref=
"headerRef"
v-if=
"getShowFullHeaderRef"
/>
<Layout>
<LayoutSideBar
v-if=
"getShowSidebar"
/>
<Layout
:class=
"`$
{prefixCls}__main`">
<LayoutMultipleHeader
/>
<LayoutContent
/>
<LayoutFooter
/>
</Layout>
</Layout>
</Layout>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
ref
}
from
'
vue
'
;
import
{
Layout
}
from
'
ant-design-vue
'
;
import
{
createAsyncComponent
}
from
'
/@/utils/factory/createAsyncComponent
'
;
import
LayoutHeader
from
'
./header/LayoutHeader
'
;
import
LayoutContent
from
'
./content/index.vue
'
;
import
LayoutSideBar
from
'
./sider
'
;
import
LayoutMultipleHeader
from
'
./header/LayoutMultipleHeader
'
;
import
{
useHeaderSetting
}
from
'
/@/hooks/setting/useHeaderSetting
'
;
import
{
useMenuSetting
}
from
'
/@/hooks/setting/useMenuSetting
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
createLayoutContext
}
from
'
./useLayoutContext
'
;
import
{
registerGlobComp
}
from
'
/@/components/registerGlobComp
'
;
import
{
createBreakpointListen
}
from
'
/@/hooks/event/useBreakpoint
'
;
import
{
isMobile
}
from
'
/@/utils/is
'
;
export
default
defineComponent
({
name
:
'
DefaultLayout
'
,
components
:
{
LayoutFeatures
:
createAsyncComponent
(()
=>
import
(
'
/@/layouts/default/feature/index.vue
'
)),
LayoutFooter
:
createAsyncComponent
(()
=>
import
(
'
/@/layouts/default/footer/index.vue
'
)),
LayoutHeader
,
LayoutContent
,
LayoutSideBar
,
LayoutMultipleHeader
,
Layout
,
},
setup
()
{
const
headerRef
=
ref
<
ComponentRef
>
(
null
);
const
isMobileRef
=
ref
(
false
);
const
{
prefixCls
}
=
useDesign
(
'
default-layout
'
);
createLayoutContext
({
fullHeader
:
headerRef
,
isMobile
:
isMobileRef
});
createBreakpointListen
(()
=>
{
isMobileRef
.
value
=
isMobile
();
});
// ! Only register global components here
// ! Can reduce the size of the first screen code
// default layout It is loaded after login. So it won’t be packaged to the first screen
registerGlobComp
();
const
{
getShowFullHeaderRef
}
=
useHeaderSetting
();
const
{
getShowSidebar
}
=
useMenuSetting
();
return
{
getShowFullHeaderRef
,
getShowSidebar
,
headerRef
,
prefixCls
,
};
},
});
</
script
>
<
style
lang=
"less"
>
@import (reference) '../../design/index.less';
@prefix-cls: ~'@{namespace}-default-layout';
.@{prefix-cls} {
display: flex;
width: 100%;
min-height: 100%;
background: @content-bg;
flex-direction: column;
> .ant-layout {
min-height: 100%;
}
&__main {
margin-left: 1px;
}
}
</
style
>
src/layouts/default/multitabs/TabContent.tsx
已删除
100644 → 0
浏览文件 @
ed41e508
import
type
{
PropType
}
from
'
vue
'
;
import
{
Dropdown
}
from
'
/@/components/Dropdown/index
'
;
import
{
defineComponent
,
unref
,
FunctionalComponent
}
from
'
vue
'
;
import
{
TabContentProps
}
from
'
./types
'
;
import
{
RightOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
TabContentEnum
}
from
'
./types
'
;
import
{
useTabDropdown
}
from
'
./useTabDropdown
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
RouteLocationNormalized
}
from
'
vue-router
'
;
const
{
t
:
titleT
}
=
useI18n
();
const
ExtraContent
:
FunctionalComponent
=
()
=>
{
return
(
<
span
class
=
{
`multiple-tabs-content__extra `
}
>
<
RightOutlined
/>
</
span
>
);
};
const
TabContent
:
FunctionalComponent
<
{
tabItem
:
RouteLocationNormalized
;
handler
:
Fn
}
>
=
(
props
)
=>
{
const
{
tabItem
:
{
meta
}
=
{}
}
=
props
;
return
(
<
div
class
=
{
`multiple-tabs-content__content `
}
onContextmenu
=
{
props
.
handler
(
props
.
tabItem
)
}
>
<
span
class
=
"ml-1"
>
{
meta
&&
titleT
(
meta
.
title
)
}
</
span
>
</
div
>
);
};
export
default
defineComponent
({
name
:
'
TabContent
'
,
props
:
{
tabItem
:
{
type
:
Object
as
PropType
<
RouteLocationNormalized
>
,
default
:
null
,
},
type
:
{
type
:
Number
as
PropType
<
TabContentEnum
>
,
default
:
TabContentEnum
.
TAB_TYPE
,
},
},
setup
(
props
)
{
const
{
getDropMenuList
,
handleMenuEvent
,
handleContextMenu
,
getTrigger
,
isTabs
,
}
=
useTabDropdown
(
props
as
TabContentProps
);
return
()
=>
{
return
(
<
Dropdown
dropMenuList
=
{
unref
(
getDropMenuList
)
}
trigger
=
{
unref
(
getTrigger
)
}
onMenuEvent
=
{
handleMenuEvent
}
>
{
()
=>
{
if
(
!
unref
(
isTabs
))
{
return
<
ExtraContent
/>;
}
return
<
TabContent
handler
=
{
handleContextMenu
}
tabItem
=
{
props
.
tabItem
}
/>;
}
}
</
Dropdown
>
);
};
},
});
src/layouts/default/multitabs/index.tsx
已删除
100644 → 0
浏览文件 @
ed41e508
import
'
./index.less
'
;
import
type
{
TabContentProps
}
from
'
./types
'
;
import
{
defineComponent
,
watch
,
computed
,
unref
,
ref
}
from
'
vue
'
;
import
{
useRouter
}
from
'
vue-router
'
;
import
{
Tabs
}
from
'
ant-design-vue
'
;
import
TabContent
from
'
./TabContent
'
;
import
{
useGo
}
from
'
/@/hooks/web/usePage
'
;
import
{
TabContentEnum
}
from
'
./types
'
;
import
{
tabStore
}
from
'
/@/store/modules/tab
'
;
import
{
userStore
}
from
'
/@/store/modules/user
'
;
import
{
initAffixTabs
,
useTabsDrag
}
from
'
./useMultipleTabs
'
;
import
{
REDIRECT_NAME
}
from
'
/@/router/constant
'
;
export
default
defineComponent
({
name
:
'
MultipleTabs
'
,
setup
()
{
const
activeKeyRef
=
ref
(
''
);
const
affixTextList
=
initAffixTabs
();
useTabsDrag
(
affixTextList
);
const
go
=
useGo
();
const
{
currentRoute
}
=
useRouter
();
const
getTabsState
=
computed
(()
=>
tabStore
.
getTabsState
);
watch
(
()
=>
tabStore
.
getLastChangeRouteState
?.
path
,
()
=>
{
if
(
tabStore
.
getLastChangeRouteState
?.
name
===
REDIRECT_NAME
)
{
return
;
}
const
lastChangeRoute
=
unref
(
tabStore
.
getLastChangeRouteState
);
if
(
!
lastChangeRoute
||
!
userStore
.
getTokenState
)
return
;
const
{
path
,
fullPath
}
=
lastChangeRoute
;
const
p
=
fullPath
||
path
;
if
(
activeKeyRef
.
value
!==
p
)
{
activeKeyRef
.
value
=
p
;
}
tabStore
.
addTabAction
(
lastChangeRoute
);
},
{
immediate
:
true
,
}
);
function
handleChange
(
activeKey
:
any
)
{
activeKeyRef
.
value
=
activeKey
;
go
(
activeKey
,
false
);
}
// Close the current tab
function
handleEdit
(
targetKey
:
string
)
{
// Added operation to hide, currently only use delete operation
tabStore
.
closeTabByKeyAction
(
targetKey
);
}
function
renderQuick
()
{
const
tabContentProps
:
TabContentProps
=
{
tabItem
:
currentRoute
.
value
,
type
:
TabContentEnum
.
EXTRA_TYPE
,
};
return
<
TabContent
{
...
tabContentProps
}
/>;
}
function
renderTabs
()
{
return
unref
(
getTabsState
).
map
((
item
)
=>
{
const
key
=
item
.
query
?
item
.
fullPath
:
item
.
path
;
const
closable
=
!
(
item
&&
item
.
meta
&&
item
.
meta
.
affix
);
const
slots
=
{
tab
:
()
=>
<
TabContent
tabItem
=
{
item
}
/>,
};
return
(
<
Tabs
.
TabPane
key
=
{
key
}
closable
=
{
closable
}
>
{
slots
}
</
Tabs
.
TabPane
>
);
});
}
return
()
=>
{
const
slots
=
{
default
:
()
=>
renderTabs
(),
tabBarExtraContent
:
()
=>
renderQuick
(),
};
return
(
<
div
class
=
"multiple-tabs"
>
<
Tabs
type
=
"editable-card"
size
=
"small"
animated
=
{
false
}
hideAdd
=
{
true
}
tabBarGutter
=
{
3
}
activeKey
=
{
unref
(
activeKeyRef
)
}
onChange
=
{
handleChange
}
onEdit
=
{
handleEdit
}
>
{
slots
}
</
Tabs
>
</
div
>
);
};
},
});
src/layouts/default/setting/index.vue
浏览文件 @
27e50b47
...
...
@@ -13,7 +13,7 @@
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
export
default
defineComponent
({
name
:
'
SettingB
t
n
'
,
name
:
'
SettingB
utto
n
'
,
components
:
{
SettingOutlined
,
SettingDrawer
},
setup
()
{
const
[
register
,
{
openDrawer
}]
=
useDrawer
();
...
...
src/layouts/default/sider/useLayoutSider.tsx
浏览文件 @
27e50b47
import
type
{
Ref
}
from
'
vue
'
;
import
{
computed
,
unref
,
onMounted
,
nextTick
,
ref
}
from
'
vue
'
;
import
LayoutTrigger
from
'
/@/layouts/default/
LayoutTrigger
'
;
import
LayoutTrigger
from
'
/@/layouts/default/
trigger/index.vue
'
;
import
{
TriggerEnum
}
from
'
/@/enums/menuEnum
'
;
...
...
src/layouts/default/tabs/components/QuickButton.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<TabContent
:type=
"TabContentEnum.EXTRA_TYPE"
:tabItem=
"$route"
/>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
TabContentEnum
}
from
'
../types
'
;
import
TabContent
from
'
./TabContent.vue
'
;
export
default
defineComponent
({
name
:
'
QuickButton
'
,
components
:
{
TabContent
,
},
setup
()
{
return
{
TabContentEnum
,
};
},
});
</
script
>
src/layouts/default/tabs/components/TabContent.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<Dropdown
:dropMenuList=
"getDropMenuList"
:trigger=
"getTrigger"
@
menuEvent=
"handleMenuEvent"
>
<div
:class=
"`$
{prefixCls}__info`" @contextmenu="handleContext" v-if="isTabs">
<span
class=
"ml-1"
>
{{
getTitle
}}
</span>
</div>
<span
:class=
"`$
{prefixCls}__extra`" v-else>
<RightOutlined
/>
</span>
</Dropdown>
</
template
>
<
script
lang=
"ts"
>
import
type
{
PropType
}
from
'
vue
'
;
import
{
defineComponent
,
computed
}
from
'
vue
'
;
import
{
Dropdown
}
from
'
/@/components/Dropdown/index
'
;
import
{
TabContentProps
,
TabContentEnum
}
from
'
../types
'
;
import
{
RightOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
useTabDropdown
}
from
'
../useTabDropdown
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
RouteLocationNormalized
}
from
'
vue-router
'
;
export
default
defineComponent
({
name
:
'
TabContent
'
,
components
:
{
Dropdown
,
RightOutlined
},
props
:
{
tabItem
:
{
type
:
Object
as
PropType
<
RouteLocationNormalized
>
,
default
:
null
,
},
type
:
{
type
:
Number
as
PropType
<
TabContentEnum
>
,
default
:
TabContentEnum
.
TAB_TYPE
,
},
},
setup
(
props
)
{
const
{
prefixCls
}
=
useDesign
(
'
multiple-tabs-content
'
);
const
{
t
}
=
useI18n
();
const
getTitle
=
computed
(()
=>
{
const
{
tabItem
:
{
meta
}
=
{}
}
=
props
;
return
meta
&&
t
(
meta
.
title
);
});
const
{
getDropMenuList
,
handleMenuEvent
,
handleContextMenu
,
getTrigger
,
isTabs
,
}
=
useTabDropdown
(
props
as
TabContentProps
);
function
handleContext
(
e
:
ChangeEvent
)
{
props
.
tabItem
&&
handleContextMenu
(
props
.
tabItem
)(
e
);
}
return
{
prefixCls
,
getDropMenuList
,
handleMenuEvent
,
handleContext
,
getTrigger
,
isTabs
,
getTitle
,
};
},
});
</
script
>
src/layouts/default/
multi
tabs/index.less
→
src/layouts/default/tabs/index.less
浏览文件 @
27e50b47
@import (reference) '../../../design/index.less';
@prefix-cls: ~'@{namespace}-multiple-tabs';
.
multiple-tabs
{
.
@{prefix-cls}
{
z-index: 10;
height: @multiple-height + 2;
padding: 0 0 2px 0;
margin-left: -1px;
line-height: @multiple-height + 2;
background: @white;
box-shadow: 0 1px 2px 0 rgba(29, 35, 41, 0.05);
...
...
@@ -32,13 +31,33 @@
line-height: calc(@multiple-height - 2px);
color: @text-color-call-out;
background: @white;
border: 1px solid darken(@border-color-light,
8
%);
border: 1px solid darken(@border-color-light,
6
%);
transition: none;
&:not(.ant-tabs-tab-active)::before {
position: absolute;
top: -1px;
left: 50%;
width: 100%;
height: 2px;
background-color: @primary-color;
content: '';
opacity: 0;
transform: translate(-50%, 0) scaleX(0);
transform-origin: center;
transition: none;
}
&:hover {
.ant-tabs-close-x {
opacity: 1;
}
&:not(.ant-tabs-tab-active)::before {
opacity: 1;
transform: translate(-50%, 0) scaleX(1);
transition: all 0.3s ease-in-out;
}
}
.ant-tabs-close-x {
...
...
@@ -51,7 +70,7 @@
&:hover {
svg {
width: 0.
75
em;
width: 0.
8
em;
}
}
}
...
...
@@ -73,6 +92,7 @@
color: @white;
background: fade(@primary-color, 100%);
border: 0;
transition: none;
&::before {
position: absolute;
...
...
@@ -98,7 +118,7 @@
}
.ant-tabs-nav > div:nth-child(1) {
padding: 0
10
px;
padding: 0
6
px;
.ant-tabs-tab {
margin-right: 3px !important;
...
...
@@ -124,36 +144,42 @@
.ant-dropdown-trigger {
display: inline-flex;
}
}
.multiple-tabs-content {
&__extra {
display: inline-block;
width: @multiple-height;
height: @multiple-height;
line-height: @multiple-height;
color: #999;
text-align: center;
cursor: pointer;
border-left: 1px solid #eee;
&:hover {
color: @text-color-base;
&--hide-close {
.ant-tabs-close-x {
opacity: 0 !important;
}
}
&-content {
&__extra {
display: inline-block;
width: @multiple-height;
height: @multiple-height;
line-height: @multiple-height;
color: #999;
text-align: center;
cursor: pointer;
border-left: 1px solid #eee;
&:hover {
color: @text-color-base;
}
span[role='img'] {
transform: rotate(90deg);
span[role='img'] {
transform: rotate(90deg);
}
}
}
&__content {
display: inline-block;
width: 100%;
height: @multiple-height - 2;
padding-left: 0;
margin-left: -10px;
font-size: 12px;
cursor: pointer;
user-select: none;
&__info {
display: inline-block;
width: 100%;
height: @multiple-height - 2;
padding-left: 0;
margin-left: -10px;
font-size: 12px;
cursor: pointer;
user-select: none;
}
}
}
src/layouts/default/tabs/index.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<div
:class=
"getWrapClass"
>
<Tabs
type=
"editable-card"
size=
"small"
:animated=
"false"
:hideAdd=
"true"
:tabBarGutter=
"3"
:activeKey=
"activeKeyRef"
@
change=
"handleChange"
@
edit=
"handleEdit"
>
<template
v-for=
"item in getTabsState"
:key=
"item.query ? item.fullPath : item.path"
>
<TabPane
:closable=
"!(item && item.meta && item.meta.affix)"
>
<template
#tab
>
<TabContent
:tabItem=
"item"
/>
</
template
>
</TabPane>
</template>
<
template
#tabBarExtraContent
>
<QuickButton
/>
</
template
>
</Tabs>
</div>
</template>
<
script
lang=
"ts"
>
import
{
defineComponent
,
watch
,
computed
,
unref
,
ref
}
from
'
vue
'
;
import
{
Tabs
}
from
'
ant-design-vue
'
;
import
TabContent
from
'
./components/TabContent.vue
'
;
import
{
useGo
}
from
'
/@/hooks/web/usePage
'
;
import
{
tabStore
}
from
'
/@/store/modules/tab
'
;
import
{
userStore
}
from
'
/@/store/modules/user
'
;
import
{
initAffixTabs
,
useTabsDrag
}
from
'
./useMultipleTabs
'
;
import
{
REDIRECT_NAME
}
from
'
/@/router/constant
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
createAsyncComponent
}
from
'
/@/utils/factory/createAsyncComponent
'
;
export
default
defineComponent
({
name
:
'
MultipleTabs
'
,
components
:
{
QuickButton
:
createAsyncComponent
(()
=>
import
(
'
./components/QuickButton.vue
'
)),
Tabs
,
TabPane
:
Tabs
.
TabPane
,
TabContent
,
},
setup
()
{
const
affixTextList
=
initAffixTabs
();
const
activeKeyRef
=
ref
(
''
);
useTabsDrag
(
affixTextList
);
const
{
prefixCls
}
=
useDesign
(
'
multiple-tabs
'
);
const
go
=
useGo
();
const
getTabsState
=
computed
(()
=>
tabStore
.
getTabsState
);
const
unClose
=
computed
(()
=>
{
return
getTabsState
.
value
.
length
===
1
;
});
const
getWrapClass
=
computed
(()
=>
{
return
[
prefixCls
,
{
[
`
${
prefixCls
}
--hide-close`
]:
unClose
,
},
];
});
watch
(
()
=>
tabStore
.
getLastChangeRouteState
?.
path
,
()
=>
{
if
(
tabStore
.
getLastChangeRouteState
?.
name
===
REDIRECT_NAME
)
{
return
;
}
const
lastChangeRoute
=
unref
(
tabStore
.
getLastChangeRouteState
);
if
(
!
lastChangeRoute
||
!
userStore
.
getTokenState
)
return
;
const
{
path
,
fullPath
}
=
lastChangeRoute
;
const
p
=
fullPath
||
path
;
if
(
activeKeyRef
.
value
!==
p
)
{
activeKeyRef
.
value
=
p
;
}
tabStore
.
addTabAction
(
lastChangeRoute
);
},
{
immediate
:
true
,
}
);
function
handleChange
(
activeKey
:
any
)
{
activeKeyRef
.
value
=
activeKey
;
go
(
activeKey
,
false
);
}
// Close the current tab
function
handleEdit
(
targetKey
:
string
)
{
// Added operation to hide, currently only use delete operation
if
(
unref
(
unClose
))
return
;
tabStore
.
closeTabByKeyAction
(
targetKey
);
}
return
{
prefixCls
,
unClose
,
getWrapClass
,
handleEdit
,
handleChange
,
activeKeyRef
,
getTabsState
,
};
},
});
</
script
>
<
style
lang=
"less"
>
@import './index.less';
</
style
>
src/layouts/default/
multi
tabs/types.ts
→
src/layouts/default/tabs/types.ts
浏览文件 @
27e50b47
文件已移动
src/layouts/default/
multi
tabs/useMultipleTabs.ts
→
src/layouts/default/tabs/useMultipleTabs.ts
浏览文件 @
27e50b47
...
...
@@ -2,6 +2,7 @@ import Sortable from 'sortablejs';
import
{
toRaw
,
ref
,
nextTick
,
onMounted
}
from
'
vue
'
;
import
{
RouteLocationNormalized
}
from
'
vue-router
'
;
import
{
useProjectSetting
}
from
'
/@/hooks/setting
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
router
from
'
/@/router
'
;
import
{
tabStore
}
from
'
/@/store/modules/tab
'
;
import
{
isNullAndUnDef
}
from
'
/@/utils/is
'
;
...
...
@@ -48,12 +49,12 @@ export function initAffixTabs(): string[] {
export
function
useTabsDrag
(
affixTextList
:
string
[])
{
const
{
multiTabsSetting
}
=
useProjectSetting
();
const
{
prefixCls
}
=
useDesign
(
'
multiple-tabs
'
);
function
initSortableTabs
()
{
if
(
!
multiTabsSetting
.
canDrag
)
return
;
nextTick
(()
=>
{
const
el
=
document
.
querySelectorAll
(
'
.multiple-tabs .ant-tabs-nav > div
'
)?.[
0
]
as
HTMLElement
;
const
el
=
document
.
querySelectorAll
(
`.
${
prefixCls
}
.ant-tabs-nav > div`
)?.[
0
]
as
HTMLElement
;
if
(
!
el
)
return
;
Sortable
.
create
(
el
,
{
...
...
src/layouts/default/
multi
tabs/useTabDropdown.ts
→
src/layouts/default/tabs/useTabDropdown.ts
浏览文件 @
27e50b47
文件已移动
src/layouts/default/trigger/HeaderTrigger.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<span
:class=
"[prefixCls, theme]"
@
click=
"toggleCollapsed"
>
<MenuUnfoldOutlined
v-if=
"getCollapsed"
/>
<MenuFoldOutlined
v-else
/>
</span>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
MenuUnfoldOutlined
,
MenuFoldOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
useMenuSetting
}
from
'
/@/hooks/setting/useMenuSetting
'
;
import
{
useDesign
}
from
'
/@/hooks/web/useDesign
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
export
default
defineComponent
({
name
:
'
SiderTrigger
'
,
components
:
{
MenuUnfoldOutlined
,
MenuFoldOutlined
},
props
:
{
theme
:
propTypes
.
oneOf
([
'
light
'
,
'
dark
'
]),
},
setup
()
{
const
{
getCollapsed
,
toggleCollapsed
}
=
useMenuSetting
();
const
{
prefixCls
}
=
useDesign
(
'
layout-header-trigger
'
);
return
{
getCollapsed
,
toggleCollapsed
,
prefixCls
};
},
});
</
script
>
src/layouts/default/trigger/SiderTrigger.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<DoubleRightOutlined
v-if=
"getCollapsed"
/>
<DoubleLeftOutlined
v-else
/>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
DoubleRightOutlined
,
DoubleLeftOutlined
}
from
'
@ant-design/icons-vue
'
;
import
{
useMenuSetting
}
from
'
/@/hooks/setting/useMenuSetting
'
;
export
default
defineComponent
({
name
:
'
SiderTrigger
'
,
components
:
{
DoubleRightOutlined
,
DoubleLeftOutlined
},
setup
()
{
const
{
getCollapsed
}
=
useMenuSetting
();
return
{
getCollapsed
};
},
});
</
script
>
src/layouts/default/trigger/index.vue
0 → 100644
浏览文件 @
27e50b47
<
template
>
<SiderTrigger
v-if=
"sider"
/>
<HeaderTrigger
v-else
:theme=
"theme"
/>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
import
{
createAsyncComponent
}
from
'
/@/utils/factory/createAsyncComponent
'
;
import
{
propTypes
}
from
'
/@/utils/propTypes
'
;
export
default
defineComponent
({
name
:
'
LayoutTrigger
'
,
components
:
{
SiderTrigger
:
createAsyncComponent
(()
=>
import
(
'
./SiderTrigger.vue
'
)),
HeaderTrigger
:
createAsyncComponent
(()
=>
import
(
'
./HeaderTrigger.vue
'
),
{
loading
:
true
}),
},
props
:
{
sider
:
propTypes
.
bool
.
def
(
true
),
theme
:
propTypes
.
oneOf
([
'
light
'
,
'
dark
'
]),
},
});
</
script
>
src/layouts/iframe/index.vue
浏览文件 @
27e50b47
<
template
>
<template
v-for=
"frame in getFramePages"
:key=
"frame.path"
>
<FramePage
v-if=
"frame.meta.frameSrc && hasRenderFrame(frame.name)"
v-show=
"showIframe(frame)"
:frameSrc=
"frame.meta.frameSrc"
/>
</
template
>
<div>
<template
v-for=
"frame in getFramePages"
:key=
"frame.path"
>
<FramePage
v-if=
"frame.meta.frameSrc && hasRenderFrame(frame.name)"
v-show=
"showIframe(frame)"
:frameSrc=
"frame.meta.frameSrc"
/>
</
template
>
</div>
</template>
<
script
lang=
"ts"
>
import
{
defineComponent
}
from
'
vue
'
;
...
...
src/layouts/iframe/useFrameKeepAlive.ts
浏览文件 @
27e50b47
import
type
{
AppRouteRecordRaw
}
from
'
/@/router/types
'
;
import
{
computed
,
toRaw
,
unref
}
from
'
vue
'
;
import
{
useRouter
}
from
'
vue-router
'
;
import
router
from
'
/@/router
'
;
import
{
tabStore
}
from
'
/@/store/modules/tab
'
;
...
...
@@ -10,8 +8,10 @@ import { unique } from '/@/utils';
import
{
useMultipleTabSetting
}
from
'
/@/hooks/setting/useMultipleTabSetting
'
;
import
router
from
'
/@/router
'
;
export
function
useFrameKeepAlive
()
{
const
{
currentRoute
}
=
useRouter
()
;
const
{
currentRoute
}
=
router
;
const
{
getShowMultipleTab
}
=
useMultipleTabSetting
();
const
getFramePages
=
computed
(()
=>
{
...
...
src/layouts/page/index.tsx
浏览文件 @
27e50b47
...
...
@@ -10,12 +10,14 @@ import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import
{
useTransitionSetting
}
from
'
/@/hooks/setting/useTransitionSetting
'
;
import
{
useCache
}
from
'
./useCache
'
;
import
{
useMultipleTabSetting
}
from
'
/@/hooks/setting/useMultipleTabSetting
'
;
// import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
interface
DefaultContext
{
Component
:
FunctionalComponent
&
{
type
:
{
[
key
:
string
]:
any
}
};
route
:
RouteLocation
;
}
// const FrameLayout=createAsyncComponent(()=>'/@/layouts/iframe/index.vue')
export
default
defineComponent
({
name
:
'
PageLayout
'
,
setup
()
{
...
...
src/layouts/page/useCache.ts
浏览文件 @
27e50b47
...
...
@@ -32,7 +32,6 @@ export function useCache(isPage: boolean) {
if
(
isPage
)
{
// page Layout
// not parent layout
return
cached
.
get
(
PAGE_LAYOUT_KEY
)
||
[];
}
const
cacheSet
=
new
Set
<
string
>
();
...
...
src/locales/lang/en/layout/multipleTab.ts
浏览文件 @
27e50b47
export
default
{
redo
:
'
Refresh
'
,
close
:
'
Close
'
,
redo
:
'
Refresh
current
'
,
close
:
'
Close
current
'
,
closeLeft
:
'
Close Left
'
,
closeRight
:
'
Close Right
'
,
closeOther
:
'
Close Other
'
,
...
...
src/locales/lang/zh_CN/layout/multipleTab.ts
浏览文件 @
27e50b47
export
default
{
redo
:
'
刷新
'
,
close
:
'
关闭
'
,
redo
:
'
刷新
当前
'
,
close
:
'
关闭
当前
'
,
closeLeft
:
'
关闭左侧
'
,
closeRight
:
'
关闭右侧
'
,
closeOther
:
'
关闭其他
'
,
...
...
src/router/constant.ts
浏览文件 @
27e50b47
...
...
@@ -6,7 +6,7 @@ const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exception');
/**
* @description: default layout
*/
export
const
LAYOUT
=
()
=>
import
(
'
/@/layouts/default/index
'
);
export
const
LAYOUT
=
()
=>
import
(
'
/@/layouts/default/index
.vue
'
);
/**
* @description: page-layout
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录