mirror of https://github.com/1Panel-dev/1Panel
Browse Source
#### What this PR does / why we need it? #### Summary of your change #### Please indicate you've done the following: - [ ] Made sure tests are passing and test coverage is added if needed. - [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/). - [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.pull/1112/head
wangdan-fit2cloud
2 years ago
committed by
GitHub
95 changed files with 326 additions and 204 deletions
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,11 @@
|
||||
import { type App } from 'vue'; |
||||
import LayoutContent from './layout-content/index.vue'; |
||||
import RouterButton from './router-button/index.vue'; |
||||
import ComplexTable from './complex-table/index.vue'; |
||||
export default { |
||||
install(app: App) { |
||||
app.component(LayoutContent.name, LayoutContent); |
||||
app.component(RouterButton.name, RouterButton); |
||||
app.component(ComplexTable.name, ComplexTable); |
||||
}, |
||||
}; |
@ -0,0 +1,4 @@
|
||||
export enum DeviceType { |
||||
Mobile, |
||||
Desktop, |
||||
} |
@ -0,0 +1,24 @@
|
||||
<script setup lang="ts"> |
||||
import { MenuStore } from '@/store/modules/menu'; |
||||
const menuStore = MenuStore(); |
||||
</script> |
||||
<template> |
||||
<div class="mobile-header"> |
||||
<svg-icon class="caidan" iconName="p-caidan" @click="menuStore.setCollapse()"></svg-icon> |
||||
</div> |
||||
</template> |
||||
|
||||
<style lang="scss" scoped> |
||||
.mobile-header { |
||||
background: rgba(255, 255, 255, 0.65); |
||||
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2); |
||||
padding: 10px; |
||||
text-align: left; |
||||
z-index: 999; |
||||
.caidan { |
||||
margin-left: 10px; |
||||
font-size: 10px; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,4 @@
|
||||
export { default as Sidebar } from './Sidebar/index.vue'; |
||||
export { default as Footer } from './AppFooter.vue'; |
||||
export { default as AppMain } from './AppMain.vue'; |
||||
export { default as MobileHeader } from './MobileHeader.vue'; |
@ -0,0 +1,53 @@
|
||||
import { watch, onBeforeMount, onMounted, onBeforeUnmount } from 'vue'; |
||||
import { useRoute } from 'vue-router'; |
||||
|
||||
import { MenuStore } from '@/store/modules/menu'; |
||||
import { GlobalStore } from '@/store'; |
||||
import { DeviceType } from '@/enums/app'; |
||||
/** 参考 Bootstrap 的响应式设计 WIDTH = 600 */ |
||||
const WIDTH = 600; |
||||
|
||||
/** 根据大小变化重新布局 */ |
||||
export default () => { |
||||
const route = useRoute(); |
||||
const globalStore = GlobalStore(); |
||||
const menuStore = MenuStore(); |
||||
const _isMobile = () => { |
||||
const rect = document.body.getBoundingClientRect(); |
||||
return rect.width - 1 < WIDTH; |
||||
}; |
||||
|
||||
const _resizeHandler = () => { |
||||
if (!document.hidden) { |
||||
const isMobile = _isMobile(); |
||||
globalStore.toggleDevice(isMobile ? DeviceType.Mobile : DeviceType.Desktop); |
||||
if (isMobile) { |
||||
menuStore.closeSidebar(true); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
watch( |
||||
() => route.name, |
||||
() => { |
||||
if (globalStore.device === DeviceType.Mobile && !menuStore.isCollapse) { |
||||
menuStore.closeSidebar(false); |
||||
} |
||||
}, |
||||
); |
||||
|
||||
onBeforeMount(() => { |
||||
window.addEventListener('resize', _resizeHandler); |
||||
}); |
||||
|
||||
onMounted(() => { |
||||
if (_isMobile()) { |
||||
globalStore.toggleDevice(DeviceType.Mobile); |
||||
menuStore.closeSidebar(true); |
||||
} |
||||
}); |
||||
|
||||
onBeforeUnmount(() => { |
||||
window.removeEventListener('resize', _resizeHandler); |
||||
}); |
||||
}; |
@ -1,37 +0,0 @@
|
||||
.el-container { |
||||
display: flex; |
||||
width: 100%; |
||||
min-width: 970px; |
||||
height: 100%; |
||||
.el-aside { |
||||
width: auto; |
||||
overflow: inherit; |
||||
} |
||||
.el-header, |
||||
.el-footer { |
||||
height: auto; |
||||
padding: 0; |
||||
} |
||||
.el-main { |
||||
box-sizing: border-box; |
||||
// padding: 20px 33px; |
||||
|
||||
overflow-x: hidden; |
||||
background-color: #f4f4f4; |
||||
// background: #f0f2f5; |
||||
.main-box { |
||||
box-sizing: border-box; |
||||
width: 100%; |
||||
height: 100%; |
||||
padding: 5px; |
||||
overflow: auto; |
||||
overflow-x: hidden !important; |
||||
// background-color: #f0f2f5; |
||||
border-radius: 4px; |
||||
// box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); |
||||
&::-webkit-scrollbar { |
||||
background-color: white; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,31 +1,134 @@
|
||||
<template> |
||||
<el-container> |
||||
<el-aside> |
||||
<Menu> |
||||
<slot name="menu"></slot> |
||||
</Menu> |
||||
</el-aside> |
||||
<el-container> |
||||
<el-main> |
||||
<div> |
||||
<View></View> |
||||
</div> |
||||
</el-main> |
||||
<el-footer> |
||||
<Footer> |
||||
<slot name="footer"></slot> |
||||
</Footer> |
||||
</el-footer> |
||||
</el-container> |
||||
</el-container> |
||||
<div :class="classObj" class="app-wrapper"> |
||||
<div v-if="classObj.mobile && classObj.openSidebar" class="drawer-bg" @click="handleClickOutside" /> |
||||
<div class="app-sidebar"> |
||||
<Sidebar /> |
||||
</div> |
||||
|
||||
<div class="main-container"> |
||||
<mobile-header v-if="classObj.mobile" /> |
||||
<app-main class="app-main" /> |
||||
|
||||
<Footer class="app-footer" /> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import Menu from './layout-menu.vue'; |
||||
import Footer from './layout-footer.vue'; |
||||
import View from './layout-view.vue'; |
||||
import { computed } from 'vue'; |
||||
import { Sidebar, Footer, AppMain, MobileHeader } from './components'; |
||||
import useResize from './hooks/useResize'; |
||||
import { GlobalStore } from '@/store'; |
||||
import { MenuStore } from '@/store/modules/menu'; |
||||
import { DeviceType } from '@/enums/app'; |
||||
useResize(); |
||||
|
||||
const menuStore = MenuStore(); |
||||
const globalStore = GlobalStore(); |
||||
|
||||
const classObj = computed(() => { |
||||
return { |
||||
hideSidebar: menuStore.isCollapse, |
||||
openSidebar: !menuStore.isCollapse, |
||||
mobile: globalStore.device === DeviceType.Mobile, |
||||
withoutAnimation: menuStore.withoutAnimation, |
||||
}; |
||||
}); |
||||
const handleClickOutside = () => { |
||||
menuStore.closeSidebar(false); |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
@import './index.scss'; |
||||
.app-wrapper { |
||||
position: relative; |
||||
width: 100%; |
||||
} |
||||
|
||||
.drawer-bg { |
||||
background-color: #000; |
||||
opacity: 0.3; |
||||
width: 100%; |
||||
top: 0; |
||||
height: 100%; |
||||
position: absolute; |
||||
z-index: 999; |
||||
} |
||||
|
||||
.main-container { |
||||
display: flex; |
||||
flex-direction: column; |
||||
flex: 1; |
||||
flex-basis: auto; |
||||
position: relative; |
||||
min-height: 100%; |
||||
height: calc(100vh); |
||||
transition: margin-left 0.28s; |
||||
margin-left: var(--panel-menu-width); |
||||
background-color: #f4f4f4; |
||||
overflow-x: hidden; |
||||
} |
||||
.app-main { |
||||
padding: 20px; |
||||
flex: 1; |
||||
flex-basis: auto; |
||||
overflow: auto; |
||||
} |
||||
.app-sidebar { |
||||
transition: width 0.28s; |
||||
width: var(--panel-menu-width) !important; |
||||
height: 100%; |
||||
position: fixed; |
||||
font-size: 0px; |
||||
top: 0; |
||||
bottom: 0; |
||||
left: 0; |
||||
z-index: 1001; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.hideSidebar { |
||||
.main-container { |
||||
margin-left: var(--panel-menu-hide-width); |
||||
} |
||||
.app-sidebar { |
||||
width: var(--panel-menu-hide-width) !important; |
||||
} |
||||
.fixed-header { |
||||
width: calc(100% - var(--panel-menu-hide-width)); |
||||
} |
||||
} |
||||
// for mobile response 适配移动端 |
||||
.mobile { |
||||
.main-container { |
||||
margin-left: 0px; |
||||
} |
||||
.app-sidebar { |
||||
transition: transform 0.28s; |
||||
width: var(--panel-menu-width) !important; |
||||
background: #ffffff; |
||||
} |
||||
.app-footer { |
||||
display: block; |
||||
text-align: center; |
||||
} |
||||
&.openSidebar { |
||||
position: fixed; |
||||
top: 0; |
||||
} |
||||
&.hideSidebar { |
||||
.app-sidebar { |
||||
pointer-events: none; |
||||
transition-duration: 0.3s; |
||||
transform: translate3d(calc(0px - var(--panel-menu-width)), 0, 0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
.withoutAnimation { |
||||
.main-container, |
||||
.sidebar-container { |
||||
transition: none; |
||||
} |
||||
} |
||||
</style> |
||||
|
@ -1,3 +0,0 @@
|
||||
<template> |
||||
<slot></slot> |
||||
</template> |
@ -1,3 +0,0 @@
|
||||
<template> |
||||
<slot></slot> |
||||
</template> |
@ -1,5 +1,4 @@
|
||||
/** |
||||
* @description: default layout |
||||
*/ |
||||
// export const Layout = () => import('@/layout/index.vue');
|
||||
export const Layout = () => import('@/components/app-layout/index.vue'); |
||||
export const Layout = () => import('@/layout/index.vue'); |
||||
|
@ -1,6 +1,7 @@
|
||||
@use 'fit2cloud-ui-plus/src/styles/index.scss' as *; |
||||
@use './element.scss'; |
||||
@use './element-dark.scss'; |
||||
@use './moblie.scss'; |
||||
@use './reset.scss'; |
||||
@use './var.scss'; |
||||
@use 'md-editor-v3/lib/style.css'; |
||||
|
@ -0,0 +1,9 @@
|
||||
.mobile { |
||||
.monitor-tags { |
||||
position: inherit; |
||||
top: 13px; |
||||
} |
||||
.mobile-monitor-chart { |
||||
margin-top: 20px !important; |
||||
} |
||||
} |
Loading…
Reference in new issue