mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-18 19:46:47 +08:00
JEECG-BOOT 2.0.2版本发布
This commit is contained in:
51
ant-design-vue-jeecg/src/components/page/GlobalFooter.vue
Normal file
51
ant-design-vue-jeecg/src/components/page/GlobalFooter.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="footer">
|
||||
<div class="links">
|
||||
<a href="http://www.jeecg.org" target="_blank">JEECG 首页</a>
|
||||
<a href="https://github.com/zhangdaiscott/jeecg-boot" target="_blank">
|
||||
<a-icon type="github"/>
|
||||
</a>
|
||||
<a href="https://ant.design/">Ant Design</a>
|
||||
<a href="https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/">Vue Antd</a>
|
||||
</div>
|
||||
<div class="copyright">
|
||||
Copyright
|
||||
<a-icon type="copyright"/>
|
||||
2019 <span>JEECG开源社区 出品</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "LayoutFooter"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer {
|
||||
padding: 0 16px;
|
||||
margin: 48px 0 24px;
|
||||
text-align: center;
|
||||
|
||||
.links {
|
||||
margin-bottom: 8px;
|
||||
|
||||
a {
|
||||
color: rgba(0, 0, 0, .45);
|
||||
|
||||
&:hover {
|
||||
color: rgba(0, 0, 0, .65);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.copyright {
|
||||
color: rgba(0, 0, 0, .45);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
218
ant-design-vue-jeecg/src/components/page/GlobalHeader.vue
Normal file
218
ant-design-vue-jeecg/src/components/page/GlobalHeader.vue
Normal file
@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<!-- , width: fixedHeader ? `calc(100% - ${sidebarOpened ? 256 : 80}px)` : '100%' -->
|
||||
<a-layout-header
|
||||
v-if="!headerBarFixed"
|
||||
:class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', ]"
|
||||
:style="{ padding: '0' }">
|
||||
|
||||
<div v-if="mode === 'sidemenu'" class="header" :class="theme">
|
||||
<a-icon
|
||||
v-if="device==='mobile'"
|
||||
class="trigger"
|
||||
:type="collapsed ? 'menu-fold' : 'menu-unfold'"
|
||||
@click.native="toggle"></a-icon>
|
||||
<a-icon
|
||||
v-else
|
||||
class="trigger"
|
||||
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
|
||||
@click.native="toggle"/>
|
||||
|
||||
<span v-if="device === 'desktop'">欢迎进入 Jeecg-Boot 企业级快速开发平台</span>
|
||||
<span v-else>Jeecg-Boot</span>
|
||||
|
||||
<user-menu :theme="theme"/>
|
||||
</div>
|
||||
<!-- 顶部导航栏模式 -->
|
||||
<div v-else :class="['top-nav-header-index', theme]">
|
||||
<div class="header-index-wide">
|
||||
<div class="header-index-left" :style="topMenuStyle.headerIndexLeft">
|
||||
<logo class="top-nav-header" :show-title="device !== 'mobile'" :style="topMenuStyle.topNavHeader"/>
|
||||
<div v-if="device !== 'mobile'" :style="topMenuStyle.topSmenuStyle">
|
||||
<s-menu
|
||||
mode="horizontal"
|
||||
:menu="menus"
|
||||
:theme="theme"></s-menu>
|
||||
</div>
|
||||
<a-icon
|
||||
v-else
|
||||
class="trigger"
|
||||
:type="collapsed ? 'menu-fold' : 'menu-unfold'"
|
||||
@click.native="toggle"></a-icon>
|
||||
</div>
|
||||
<user-menu class="header-index-right" :theme="theme" :style="topMenuStyle.headerIndexRight"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</a-layout-header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserMenu from '../tools/UserMenu'
|
||||
import SMenu from '../menu/'
|
||||
import Logo from '../tools/Logo'
|
||||
|
||||
import { mixin } from '@/utils/mixin.js'
|
||||
|
||||
export default {
|
||||
name: 'GlobalHeader',
|
||||
components: {
|
||||
UserMenu,
|
||||
SMenu,
|
||||
Logo
|
||||
},
|
||||
mixins: [mixin],
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
// sidemenu, topmenu
|
||||
default: 'sidemenu'
|
||||
},
|
||||
menus: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'dark'
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
device: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'desktop'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
headerBarFixed: false,
|
||||
//update-begin--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮-----
|
||||
topMenuStyle: {
|
||||
headerIndexLeft: {},
|
||||
topNavHeader: {},
|
||||
headerIndexRight: {},
|
||||
topSmenuStyle: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/** 监听设备变化 */
|
||||
device() {
|
||||
if (this.mode === 'topmenu') {
|
||||
this.buildTopMenuStyle()
|
||||
}
|
||||
},
|
||||
/** 监听导航栏模式变化 */
|
||||
mode(newVal) {
|
||||
if (newVal === 'topmenu') {
|
||||
this.buildTopMenuStyle()
|
||||
}
|
||||
}
|
||||
},
|
||||
//update-end--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮-----
|
||||
mounted() {
|
||||
window.addEventListener('scroll', this.handleScroll)
|
||||
//update-begin--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮-----
|
||||
if (this.mode === 'topmenu') {
|
||||
this.buildTopMenuStyle()
|
||||
}
|
||||
//update-end--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮-----
|
||||
},
|
||||
methods: {
|
||||
handleScroll() {
|
||||
if (this.autoHideHeader) {
|
||||
let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
|
||||
if (scrollTop > 100) {
|
||||
this.headerBarFixed = true
|
||||
} else {
|
||||
this.headerBarFixed = false
|
||||
}
|
||||
} else {
|
||||
this.headerBarFixed = false
|
||||
}
|
||||
},
|
||||
toggle() {
|
||||
this.$emit('toggle')
|
||||
},
|
||||
//update-begin--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮-----
|
||||
buildTopMenuStyle() {
|
||||
if (this.mode === 'topmenu') {
|
||||
if (this.device === 'mobile') {
|
||||
// 手机端需要清空样式,否则显示会错乱
|
||||
this.topMenuStyle.topNavHeader = {}
|
||||
this.topMenuStyle.topSmenuStyle = {}
|
||||
this.topMenuStyle.headerIndexRight = {}
|
||||
this.topMenuStyle.headerIndexLeft = {}
|
||||
} else {
|
||||
let rightWidth = '360px'
|
||||
this.topMenuStyle.topNavHeader = { 'min-width': '165px' }
|
||||
this.topMenuStyle.topSmenuStyle = { 'width': 'calc(100% - 165px)' }
|
||||
this.topMenuStyle.headerIndexRight = { 'min-width': rightWidth }
|
||||
this.topMenuStyle.headerIndexLeft = { 'width': `calc(100% - ${rightWidth})` }
|
||||
}
|
||||
}
|
||||
}
|
||||
//update-begin--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮-----
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* update_begin author:scott date:20190220 for: 缩小首页布局顶部的高度*/
|
||||
|
||||
$height: 59px;
|
||||
|
||||
.layout {
|
||||
|
||||
.top-nav-header-index {
|
||||
|
||||
.header-index-wide {
|
||||
margin-left: 10px;
|
||||
|
||||
.ant-menu.ant-menu-horizontal {
|
||||
height: $height;
|
||||
line-height: $height;
|
||||
}
|
||||
}
|
||||
.trigger {
|
||||
line-height: 64px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
z-index: 2;
|
||||
color: white;
|
||||
height: $height;
|
||||
background-color: #1890ff;
|
||||
transition: background 300ms;
|
||||
|
||||
/* dark 样式 */
|
||||
&.dark {
|
||||
color: #000000;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
|
||||
background-color: white !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header, .top-nav-header-index {
|
||||
&.dark .trigger:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-layout-header {
|
||||
height: $height;
|
||||
line-height: $height;
|
||||
}
|
||||
|
||||
/* update_end author:scott date:20190220 for: 缩小首页布局顶部的高度*/
|
||||
|
||||
</style>
|
||||
660
ant-design-vue-jeecg/src/components/page/GlobalLayout.vue
Normal file
660
ant-design-vue-jeecg/src/components/page/GlobalLayout.vue
Normal file
@ -0,0 +1,660 @@
|
||||
<template>
|
||||
<a-layout class="layout" :class="[device]">
|
||||
|
||||
<template v-if="layoutMode === 'sidemenu'">
|
||||
<a-drawer
|
||||
v-if="device === 'mobile'"
|
||||
:wrapClassName="'drawer-sider ' + navTheme"
|
||||
placement="left"
|
||||
@close="() => this.collapsed = false"
|
||||
:closable="false"
|
||||
:visible="collapsed"
|
||||
width="200px"
|
||||
>
|
||||
<side-menu
|
||||
mode="inline"
|
||||
:menus="menus"
|
||||
@menuSelect="menuSelect"
|
||||
:theme="navTheme"
|
||||
:collapsed="false"
|
||||
:collapsible="true"></side-menu>
|
||||
</a-drawer>
|
||||
|
||||
<side-menu
|
||||
v-else
|
||||
mode="inline"
|
||||
:menus="menus"
|
||||
@menuSelect="myMenuSelect"
|
||||
:theme="navTheme"
|
||||
:collapsed="collapsed"
|
||||
:collapsible="true"></side-menu>
|
||||
</template>
|
||||
<!-- 下次优化这些代码 -->
|
||||
<template v-else>
|
||||
<a-drawer
|
||||
v-if="device === 'mobile'"
|
||||
:wrapClassName="'drawer-sider ' + navTheme"
|
||||
placement="left"
|
||||
@close="() => this.collapsed = false"
|
||||
:closable="false"
|
||||
:visible="collapsed"
|
||||
width="200px"
|
||||
>
|
||||
<side-menu
|
||||
mode="inline"
|
||||
:menus="menus"
|
||||
@menuSelect="menuSelect"
|
||||
:theme="navTheme"
|
||||
:collapsed="false"
|
||||
:collapsible="true"></side-menu>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<a-layout
|
||||
:class="[layoutMode, `content-width-${contentWidth}`]"
|
||||
:style="{ paddingLeft: fixSiderbar && isDesktop() ? `${sidebarOpened ? 200 : 80}px` : '0' }">
|
||||
<!-- layout header -->
|
||||
<global-header
|
||||
:mode="layoutMode"
|
||||
:menus="menus"
|
||||
:theme="navTheme"
|
||||
:collapsed="collapsed"
|
||||
:device="device"
|
||||
@toggle="toggle"
|
||||
/>
|
||||
|
||||
<!-- layout content -->
|
||||
<a-layout-content :style="{ height: '100%', paddingTop: fixedHeader ? '59px' : '0' }">
|
||||
<slot></slot>
|
||||
</a-layout-content>
|
||||
|
||||
<!-- layout footer -->
|
||||
<a-layout-footer style="padding: 0px">
|
||||
<global-footer/>
|
||||
</a-layout-footer>
|
||||
</a-layout>
|
||||
|
||||
<setting-drawer></setting-drawer>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SideMenu from '@/components/menu/SideMenu'
|
||||
import GlobalHeader from '@/components/page/GlobalHeader'
|
||||
import GlobalFooter from '@/components/page/GlobalFooter'
|
||||
import SettingDrawer from '@/components/setting/SettingDrawer'
|
||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
|
||||
export default {
|
||||
name: 'GlobalLayout',
|
||||
components: {
|
||||
SideMenu,
|
||||
GlobalHeader,
|
||||
GlobalFooter,
|
||||
SettingDrawer
|
||||
},
|
||||
mixins: [mixin, mixinDevice],
|
||||
data() {
|
||||
return {
|
||||
collapsed: false,
|
||||
activeMenu:{},
|
||||
menus: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
// 主路由
|
||||
mainRouters: state => state.permission.addRouters,
|
||||
// 后台菜单
|
||||
permissionMenuList: state => state.user.permissionList
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
sidebarOpened(val) {
|
||||
this.collapsed = !val
|
||||
}
|
||||
},
|
||||
created() {
|
||||
//--update-begin----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
|
||||
//this.menus = this.mainRouters.find((item) => item.path === '/').children;
|
||||
this.menus = this.permissionMenuList
|
||||
// 根据后台配置菜单,重新排序加载路由信息
|
||||
console.log('----加载菜单逻辑----')
|
||||
console.log(this.mainRouters)
|
||||
console.log(this.permissionMenuList)
|
||||
console.log('----navTheme------'+this.navTheme)
|
||||
//--update-end----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['setSidebar']),
|
||||
toggle() {
|
||||
this.collapsed = !this.collapsed
|
||||
this.setSidebar(!this.collapsed)
|
||||
triggerWindowResizeEvent()
|
||||
},
|
||||
menuSelect() {
|
||||
if (!this.isDesktop()) {
|
||||
this.collapsed = false
|
||||
}
|
||||
},
|
||||
//update-begin-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title
|
||||
myMenuSelect(value){
|
||||
//此处触发动态路由被点击事件
|
||||
this.findMenuBykey(this.menus,value.key)
|
||||
this.$emit("dynamicRouterShow",value.key,this.activeMenu.meta.title)
|
||||
},
|
||||
findMenuBykey(menus,key){
|
||||
for(let i of menus){
|
||||
if(i.path==key){
|
||||
this.activeMenu = {...i}
|
||||
}else if(i.children && i.children.length>0){
|
||||
this.findMenuBykey(i.children,key)
|
||||
}
|
||||
}
|
||||
}
|
||||
//update-end-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
body {
|
||||
// 打开滚动条固定显示
|
||||
overflow-y: scroll;
|
||||
|
||||
&.colorWeak {
|
||||
filter: invert(80%);
|
||||
}
|
||||
}
|
||||
|
||||
.layout {
|
||||
min-height: 100vh !important;
|
||||
overflow-x: hidden;
|
||||
|
||||
&.mobile {
|
||||
|
||||
.ant-layout-content {
|
||||
|
||||
.content {
|
||||
margin: 24px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ant-table-wrapper
|
||||
* 覆盖的表格手机模式样式,如果想修改在手机上表格最低宽度,可以在这里改动
|
||||
*/
|
||||
.ant-table-wrapper {
|
||||
.ant-table-content {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.ant-table-body {
|
||||
min-width: 800px;
|
||||
}
|
||||
}
|
||||
.sidemenu {
|
||||
.ant-header-fixedHeader {
|
||||
|
||||
&.ant-header-side-opened, &.ant-header-side-closed {
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.topmenu {
|
||||
/* 必须为 topmenu 才能启用流式布局 */
|
||||
&.content-width-Fluid {
|
||||
.header-index-wide {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.header, .top-nav-header-index {
|
||||
.user-wrapper .action {
|
||||
padding: 0 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-layout-has-sider {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.trigger {
|
||||
font-size: 22px;
|
||||
line-height: 42px;
|
||||
padding: 0 18px;
|
||||
cursor: pointer;
|
||||
transition: color 300ms, background 300ms;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.topmenu {
|
||||
.ant-header-fixedHeader {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
width: 100%;
|
||||
transition: width .2s;
|
||||
|
||||
&.ant-header-side-opened {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.ant-header-side-closed {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
/* 必须为 topmenu 才能启用流式布局 */
|
||||
&.content-width-Fluid {
|
||||
.header-index-wide {
|
||||
max-width: unset;
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
.page-header-index-wide {
|
||||
max-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.sidemenu {
|
||||
.ant-header-fixedHeader {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
width: 100%;
|
||||
transition: width .2s;
|
||||
|
||||
&.ant-header-side-opened {
|
||||
width: calc(100% - 200px)
|
||||
}
|
||||
|
||||
&.ant-header-side-closed {
|
||||
width: calc(100% - 80px)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 64px;
|
||||
padding: 0 12px 0 0;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header, .top-nav-header-index {
|
||||
|
||||
.user-wrapper {
|
||||
float: right;
|
||||
height: 100%;
|
||||
|
||||
.action {
|
||||
cursor: pointer;
|
||||
padding: 0 14px;
|
||||
display: inline-block;
|
||||
transition: all .3s;
|
||||
|
||||
height: 70%;
|
||||
line-height: 46px;
|
||||
|
||||
&.action-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin: 20px 10px 20px 0;
|
||||
color: #1890ff;
|
||||
background: hsla(0, 0%, 100%, .85);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 16px;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.dark {
|
||||
.user-wrapper {
|
||||
|
||||
.action {
|
||||
color: black;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.mobile {
|
||||
.top-nav-header-index {
|
||||
|
||||
.header-index-wide {
|
||||
|
||||
.header-index-left {
|
||||
|
||||
.trigger {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.logo.top-nav-header {
|
||||
text-align: center;
|
||||
width: 56px;
|
||||
line-height: 58px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-wrapper .action .avatar {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
&.light {
|
||||
|
||||
.header-index-wide {
|
||||
|
||||
.header-index-left {
|
||||
.trigger {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.tablet {
|
||||
// overflow: hidden; text-overflow:ellipsis; white-space: nowrap;
|
||||
.top-nav-header-index {
|
||||
|
||||
.header-index-wide {
|
||||
|
||||
.header-index-left {
|
||||
.logo > a {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.top-nav-header-index {
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
|
||||
position: relative;
|
||||
transition: background .3s, width .2s;
|
||||
|
||||
.header-index-wide {
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
padding: 0 20px 0 0;
|
||||
display: flex;
|
||||
height: 59px;
|
||||
|
||||
.ant-menu.ant-menu-horizontal {
|
||||
border: none;
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
}
|
||||
|
||||
.header-index-left {
|
||||
flex: 1 1;
|
||||
display: flex;
|
||||
|
||||
.logo.top-nav-header {
|
||||
width: 165px;
|
||||
height: 64px;
|
||||
position: relative;
|
||||
line-height: 64px;
|
||||
transition: all .3s;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
font-size: 16px;
|
||||
margin: 0 0 0 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-index-right {
|
||||
float: right;
|
||||
height: 59px;
|
||||
overflow: hidden;
|
||||
.action:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: #fff;
|
||||
|
||||
.header-index-wide {
|
||||
.header-index-left {
|
||||
.logo {
|
||||
h1 {
|
||||
color: #002140;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.dark {
|
||||
|
||||
.user-wrapper {
|
||||
|
||||
.action {
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
.header-index-wide .header-index-left .trigger:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 内容区
|
||||
.layout-content {
|
||||
margin: 24px 24px 0px;
|
||||
height: 64px;
|
||||
padding: 0 12px 0 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.topmenu {
|
||||
.page-header-index-wide {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// drawer-sider 自定义
|
||||
.ant-drawer.drawer-sider {
|
||||
.sider {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
.ant-drawer-content {
|
||||
background-color: rgb(0, 21, 41);
|
||||
}
|
||||
}
|
||||
&.light {
|
||||
box-shadow: none;
|
||||
.ant-drawer-content {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单样式
|
||||
.sider {
|
||||
box-shadow: 2px 116px 6px 0 rgba(0, 21, 41, .35);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
|
||||
&.ant-fixed-sidemenu {
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 64px;
|
||||
position: relative;
|
||||
line-height: 64px;
|
||||
padding-left: 24px;
|
||||
-webkit-transition: all .3s;
|
||||
transition: all .3s;
|
||||
background: #002140;
|
||||
overflow: hidden;
|
||||
|
||||
img, h1 {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
margin: 0 0 0 8px;
|
||||
font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 116px 8px 0 rgba(29, 35, 41, 0.05);
|
||||
|
||||
.logo {
|
||||
background: #fff;
|
||||
box-shadow: 1px 1px 0 0 #e8e8e8;
|
||||
|
||||
h1 {
|
||||
color: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-light {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 外置的样式控制
|
||||
.user-dropdown-menu-wrapper.ant-dropdown-menu {
|
||||
padding: 4px 0;
|
||||
|
||||
.ant-dropdown-menu-item {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item > .anticon:first-child,
|
||||
.ant-dropdown-menu-item > a > .anticon:first-child,
|
||||
.ant-dropdown-menu-submenu-title > .anticon:first-child
|
||||
.ant-dropdown-menu-submenu-title > a > .anticon:first-child {
|
||||
min-width: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 数据列表 样式
|
||||
.table-alert {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-page-search-wrapper {
|
||||
|
||||
.ant-form-inline {
|
||||
|
||||
.ant-form-item {
|
||||
display: flex;
|
||||
margin-bottom: 24px;
|
||||
margin-right: 0;
|
||||
|
||||
.ant-form-item-control-wrapper {
|
||||
flex: 1 1;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
> .ant-form-item-label {
|
||||
line-height: 32px;
|
||||
padding-right: 8px;
|
||||
width: auto;
|
||||
}
|
||||
.ant-form-item-control {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-page-search-submitButtons {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
.table-operator {
|
||||
margin-bottom: 18px;
|
||||
|
||||
button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
238
ant-design-vue-jeecg/src/components/page/PageHeader.vue
Normal file
238
ant-design-vue-jeecg/src/components/page/PageHeader.vue
Normal file
@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div class="page-header">
|
||||
<div class="page-header-index-wide">
|
||||
<a-breadcrumb class="breadcrumb">
|
||||
<a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
|
||||
<router-link v-if="item.name != name" :to="{ path: item.path }">
|
||||
{{ item.meta.title }}
|
||||
</router-link>
|
||||
<span v-else>{{ item.meta.title }}</span>
|
||||
</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
|
||||
<div class="detail">
|
||||
<div class="main" v-if="!$route.meta.hiddenHeaderContent">
|
||||
<div class="row">
|
||||
<img v-if="logo" :src="logo" class="logo"/>
|
||||
<h1 v-if="title" class="title">{{ title }}</h1>
|
||||
<div class="action">
|
||||
<slot name="action"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div v-if="avatar" class="avatar">
|
||||
<a-avatar :src="avatar"/>
|
||||
</div>
|
||||
<div v-if="this.$slots.content" class="headerContent">
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
<div v-if="this.$slots.extra" class="extra">
|
||||
<slot name="extra"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<slot name="pageMenu"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Breadcrumb from '@/components/tools/Breadcrumb'
|
||||
|
||||
export default {
|
||||
name: "PageHeader",
|
||||
components: {
|
||||
"s-breadcrumb": Breadcrumb
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
breadcrumb: {
|
||||
type: Array,
|
||||
default: null,
|
||||
required: false
|
||||
},
|
||||
logo: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
breadList: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
|
||||
this.breadList = []
|
||||
// this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: '首页'}})
|
||||
|
||||
this.name = this.$route.name
|
||||
this.$route.matched.forEach((item) => {
|
||||
// item.name !== 'index' && this.breadList.push(item)
|
||||
this.breadList.push(item)
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.page-header {
|
||||
background: #fff;
|
||||
padding: 16px 32px 0;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
|
||||
.breadcrumb {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.detail {
|
||||
display: flex;
|
||||
/*margin-bottom: 16px;*/
|
||||
|
||||
.avatar {
|
||||
flex: 0 1 72px;
|
||||
margin: 0 24px 8px 0;
|
||||
|
||||
& > span {
|
||||
border-radius: 72px;
|
||||
display: block;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
flex: 0 1 auto;
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.avatar {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
font-weight: 500;
|
||||
color: rgba(0,0,0,.85);
|
||||
margin-bottom: 16px;
|
||||
flex: auto;
|
||||
|
||||
}
|
||||
.logo {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 4px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
.content, .headerContent {
|
||||
flex: auto;
|
||||
color: rgba(0,0,0,.45);
|
||||
line-height: 22px;
|
||||
|
||||
.link {
|
||||
margin-top: 16px;
|
||||
line-height: 24px;
|
||||
|
||||
a {
|
||||
font-size: 14px;
|
||||
margin-right: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.extra {
|
||||
flex: 0 1 auto;
|
||||
margin-left: 88px;
|
||||
min-width: 242px;
|
||||
text-align: right;
|
||||
}
|
||||
.action {
|
||||
margin-left: 56px;
|
||||
min-width: 266px;
|
||||
flex: 0 1 auto;
|
||||
text-align: right;
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile .page-header {
|
||||
|
||||
.main {
|
||||
|
||||
.row {
|
||||
flex-wrap: wrap;
|
||||
|
||||
.avatar {
|
||||
flex: 0 1 25%;
|
||||
margin: 0 2% 8px 0;
|
||||
}
|
||||
.content, .headerContent {
|
||||
flex: 0 1 70%;
|
||||
|
||||
.link {
|
||||
margin-top: 16px;
|
||||
line-height: 24px;
|
||||
|
||||
a {
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.extra {
|
||||
flex: 1 1 auto;
|
||||
margin-left: 0;
|
||||
min-width: 0;
|
||||
text-align: right;
|
||||
}
|
||||
.action {
|
||||
margin-left: unset;
|
||||
min-width: 266px;
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
margin-bottom: 12px;
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
127
ant-design-vue-jeecg/src/components/page/PageLayout.vue
Normal file
127
ant-design-vue-jeecg/src/components/page/PageLayout.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<div :style="!$route.meta.pageHeader ? 'margin: -10px -24px 0;' : null">
|
||||
<!-- pageHeader , route meta hideHeader:true on hide -->
|
||||
<page-header v-if="!$route.meta.pageHeader" :title="title" :logo="logo" :avatar="avatar">
|
||||
<slot slot="action" name="action"></slot>
|
||||
<slot slot="content" name="headerContent"></slot>
|
||||
<div slot="content" v-if="!this.$slots.headerContent && desc">
|
||||
<p style="font-size: 14px;color: rgba(0,0,0,.65)">{{ desc }}</p>
|
||||
<div class="link">
|
||||
<template v-for="(link, index) in linkList">
|
||||
<a :key="index" :href="link.href">
|
||||
<a-icon :type="link.icon"/>
|
||||
<span>{{ link.title }}</span>
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<slot slot="extra" name="extra"></slot>
|
||||
<div slot="pageMenu">
|
||||
<div class="page-menu-search" v-if="search">
|
||||
<a-input-search style="width: 80%; max-width: 522px;" placeholder="请输入..." size="large" enterButton="搜索" />
|
||||
</div>
|
||||
<div class="page-menu-tabs" v-if="tabs && tabs.items">
|
||||
<!-- @change="callback" :activeKey="activeKey" -->
|
||||
<a-tabs :tabBarStyle="{margin: 0}" @change="tabs.callback" :activeKey="tabs.active()">
|
||||
<a-tab-pane v-for="item in tabs.items" :tab="item.title" :key="item.key"></a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</page-header>
|
||||
<div class="content">
|
||||
<div :class="['page-header-index-wide']">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PageHeader from './PageHeader'
|
||||
|
||||
export default {
|
||||
name: "LayoutContent",
|
||||
components: {
|
||||
PageHeader
|
||||
},
|
||||
// ['desc', 'logo', 'title', 'avatar', 'linkList', 'extraImage']
|
||||
props: {
|
||||
desc: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
logo: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
linkList: {
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
extraImage: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
search: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
tabs: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
margin: 24px 24px 0;
|
||||
|
||||
.link {
|
||||
margin-top: 16px;
|
||||
|
||||
&:not(:empty) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
a {
|
||||
margin-right: 32px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
display: inline-block;
|
||||
|
||||
i {
|
||||
font-size: 24px;
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
span {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.page-menu-search {
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.page-menu-tabs {
|
||||
margin-top: 48px;
|
||||
}
|
||||
.page-header[data-v-6740ec88] {
|
||||
margin: 0px 24px 0;
|
||||
}
|
||||
</style>
|
||||
58
ant-design-vue-jeecg/src/components/page/SHeaderNotice.vue
Normal file
58
ant-design-vue-jeecg/src/components/page/SHeaderNotice.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<a-popover trigger="click" placement="bottomRight" :overlayStyle="{ width: '300px' }">
|
||||
<template slot="content">
|
||||
<a-spin :spinning="loadding">
|
||||
<a-tabs>
|
||||
<a-tab-pane v-for="(tab, k) in tabs" :tab="tab.title" :key="k">
|
||||
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
</template>
|
||||
<span @click="fetchNotice" class="header-notice">
|
||||
<a-badge count="12">
|
||||
<a-icon style="font-size: 16px; padding: 4px" type="bell" />
|
||||
</a-badge>
|
||||
</span>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "HeaderNotice",
|
||||
props: {
|
||||
tabs: {
|
||||
type: Array,
|
||||
default: null,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loadding: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchNotice () {
|
||||
if (this.loadding) {
|
||||
this.loadding = false
|
||||
return
|
||||
}
|
||||
this.loadding = true
|
||||
setTimeout(() => {
|
||||
this.loadding = false
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-notice{
|
||||
display: inline-block;
|
||||
transition: all 0.3s;
|
||||
span {
|
||||
vertical-align: initial;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user