Commit c4fec018 by sendya

feat: add fixedHeader

parent 57c1a9cb
<template> <template>
<a-layout-header style="padding: 0px;"> <a-layout-header v-if="!headerBarFixed" :class="[fixedHeader && 'ant-header-fixedHeader']" :style="{ padding: '0', width: fixedHeader ? `calc(100% - ${sidebarOpened ? 256 : 80}px)` : '100%' }">
<div v-if="mode === 'sidemenu'" class="header"> <div v-if="mode === 'sidemenu'" class="header">
<a-icon <a-icon
v-if="device==='mobile'" v-if="device==='mobile'"
...@@ -76,18 +76,36 @@ ...@@ -76,18 +76,36 @@
data() { data() {
return { return {
menus: [], menus: [],
headerBarFixed: false,
} }
}, },
mounted () {
window.addEventListener('scroll', this.handleScroll)
},
created() { created() {
this.menus = this.mainMenu.find((item) => item.path === '/').children this.menus = this.mainMenu.find((item) => item.path === '/').children
}, },
computed: { computed: {
...mapState({ ...mapState({
mainMenu: state => state.permission.addRouters, mainMenu: state => state.permission.addRouters,
sidebarOpened: state => state.app.sidebar.opened,
fixedHeader: state => state.app.fixedHeader,
swipeDownHiddenHeader: state => state.app.swipeDownHiddenHeader,
}), }),
}, },
methods: { methods: {
handleScroll () {
if (this.swipeDownHiddenHeader) {
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() { toggle() {
this.$emit('toggle') this.$emit('toggle')
} }
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<global-header :mode="layoutMode" :theme="theme" :collapsed="collapsed" :device="device" @toggle="toggle"/> <global-header :mode="layoutMode" :theme="theme" :collapsed="collapsed" :device="device" @toggle="toggle"/>
<!-- layout content --> <!-- layout content -->
<a-layout-content :style="{ margin: '24px 24px 0', height: '100%' }"> <a-layout-content :style="{ margin: '24px 24px 0', height: '100%', paddingTop: fixedHeader ? '64px' : '0' }">
<slot></slot> <slot></slot>
</a-layout-content> </a-layout-content>
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
mainMenu: state => state.permission.addRouters, mainMenu: state => state.permission.addRouters,
layoutMode: state => state.app.layout, layoutMode: state => state.app.layout,
sidebarOpened: state => state.app.sidebar.opened, sidebarOpened: state => state.app.sidebar.opened,
fixedHeader: state => state.app.fixedHeader,
theme: state => state.app.theme, theme: state => state.app.theme,
device: state => state.app.device, device: state => state.app.device,
}) })
...@@ -108,7 +109,7 @@ ...@@ -108,7 +109,7 @@
toggle() { toggle() {
this.collapsed = !this.collapsed this.collapsed = !this.collapsed
triggerResize() triggerResize()
this.setSidebar(this.collapsed) this.setSidebar(!this.collapsed)
}, },
menuSelect() { menuSelect() {
if (this.device !== 'desktop') { if (this.device !== 'desktop') {
...@@ -166,6 +167,14 @@ ...@@ -166,6 +167,14 @@
background: rgba(0, 0, 0, 0.025); background: rgba(0, 0, 0, 0.025);
} }
} }
.ant-header-fixedHeader {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: 100%;
transition: width .2s;
}
.header { .header {
height: 64px; height: 64px;
......
...@@ -85,6 +85,31 @@ ...@@ -85,6 +85,31 @@
</div> </div>
</a-tooltip> </a-tooltip>
</div> </div>
<div :style="{ marginTop: '24px' }">
<a-list :split="false">
<a-list-item>
<a-select slot="actions" defaultValue="auto" size="small">
<a-select-option value="fixed">固定</a-select-option>
<a-select-option value="auto">流式</a-select-option>
</a-select>
<a-list-item-meta>
<div slot="title">内容区域宽度</div>
</a-list-item-meta>
</a-list-item>
<a-list-item>
<a-switch slot="actions" size="small" :defaultChecked="fixedHeader" @change="handleFixedHeader" />
<a-list-item-meta>
<div slot="title">固定 Header</div>
</a-list-item-meta>
</a-list-item>
<a-list-item>
<a-switch slot="actions" size="small" :defaultChecked="swipeDownHiddenHeader" @change="handleFixedHeaderHidden" />
<a-list-item-meta>
<div slot="title">下滑时隐藏 Header</div>
</a-list-item-meta>
</a-list-item>
</a-list>
</div>
</div> </div>
<a-divider /> <a-divider />
...@@ -143,6 +168,8 @@ ...@@ -143,6 +168,8 @@
layoutMode: state => state.app.layout, layoutMode: state => state.app.layout,
primaryColor: state => state.app.color, primaryColor: state => state.app.color,
colorWeak: state => state.app.weak, colorWeak: state => state.app.weak,
fixedHeader: state => state.app.fixedHeader,
swipeDownHiddenHeader: state => state.app.swipeDownHiddenHeader,
}) })
}, },
mounted () { mounted () {
...@@ -186,6 +213,12 @@ ...@@ -186,6 +213,12 @@
this.$store.dispatch('ToggleColor', color) this.$store.dispatch('ToggleColor', color)
updateTheme(color) updateTheme(color)
} }
},
handleFixedHeader (fixed) {
this.$store.dispatch('ToggleFixedHeader', fixed)
},
handleFixedHeaderHidden (autoHidden) {
this.$store.dispatch('ToggleFixedHeaderHidden', autoHidden)
} }
}, },
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* navTheme - sidebar theme ['dark', 'light'] 两种主题 * navTheme - sidebar theme ['dark', 'light'] 两种主题
* colorWeak - 色盲模式 * colorWeak - 色盲模式
* layout - 整体布局方式 ['sidemenu', 'topmenu'] 两种布局 * layout - 整体布局方式 ['sidemenu', 'topmenu'] 两种布局
* fixedHeader - 固定 Header : boolean
* *
* storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage) * storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage)
* *
...@@ -13,6 +14,8 @@ export default { ...@@ -13,6 +14,8 @@ export default {
primaryColor: '#1890FF', // primary color of ant design primaryColor: '#1890FF', // primary color of ant design
navTheme: 'dark', // theme for nav menu navTheme: 'dark', // theme for nav menu
layout: 'sidemenu', layout: 'sidemenu',
fixedHeader: false, // fixed header
swipeDownHiddenHeader: false,
colorWeak: false, colorWeak: false,
// vue-ls options // vue-ls options
storageOptions: { storageOptions: {
......
...@@ -13,7 +13,7 @@ import 'ant-design-vue/dist/antd.less'; // or 'ant-design-vue/dist/antd.less' ...@@ -13,7 +13,7 @@ import 'ant-design-vue/dist/antd.less'; // or 'ant-design-vue/dist/antd.less'
import '@/permission' // permission control import '@/permission' // permission control
import '@/utils/filter' // base filter import '@/utils/filter' // base filter
import { ACCESS_TOKEN, DEFAULT_COLOR, DEFAULT_THEME, DEFAULT_LAYOUT_MODE, DEFAULT_COLOR_WEAK, SIDEBAR_TYPE } from "@/store/mutation-types" import { ACCESS_TOKEN, DEFAULT_COLOR, DEFAULT_THEME, DEFAULT_LAYOUT_MODE, DEFAULT_COLOR_WEAK, SIDEBAR_TYPE, DEFAULT_FIXED_HEADER, DEFAULT_FIXED_HEADER_HIDDEN } from "@/store/mutation-types"
import config from '@/defaultConfig' import config from '@/defaultConfig'
Vue.config.productionTip = false Vue.config.productionTip = false
...@@ -30,6 +30,8 @@ new Vue({ ...@@ -30,6 +30,8 @@ new Vue({
store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, false)) store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, false))
store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme)) store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme))
store.commit('TOGGLE_LAYOUT_MODE', Vue.ls.get(DEFAULT_LAYOUT_MODE, config.layout)) store.commit('TOGGLE_LAYOUT_MODE', Vue.ls.get(DEFAULT_LAYOUT_MODE, config.layout))
store.commit('TOGGLE_FIXED_HEADER', Vue.ls.get(DEFAULT_FIXED_HEADER, config.fixedHeader))
store.commit('TOGGLE_FIXED_HEADER_HIDDEN', Vue.ls.get(DEFAULT_FIXED_HEADER_HIDDEN, config.swipeDownHiddenHeader))
store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak)) store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak))
store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor)) store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor))
store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN)) store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))
......
import Vue from 'vue' import Vue from 'vue'
import { SIDEBAR_TYPE, DEFAULT_THEME, DEFAULT_LAYOUT_MODE, DEFAULT_COLOR, DEFAULT_COLOR_WEAK } from "@/store/mutation-types" import { SIDEBAR_TYPE, DEFAULT_THEME, DEFAULT_LAYOUT_MODE, DEFAULT_COLOR, DEFAULT_COLOR_WEAK, DEFAULT_FIXED_HEADER, DEFAULT_FIXED_HEADER_HIDDEN } from "@/store/mutation-types"
const app = { const app = {
state: { state: {
...@@ -10,6 +10,8 @@ const app = { ...@@ -10,6 +10,8 @@ const app = {
device: 'desktop', device: 'desktop',
theme: '', theme: '',
layout: '', layout: '',
fixedHeader: false,
swipeDownHiddenHeader: false,
color: null, color: null,
weak: false weak: false
}, },
...@@ -35,6 +37,15 @@ const app = { ...@@ -35,6 +37,15 @@ const app = {
Vue.ls.set(DEFAULT_LAYOUT_MODE, layout) Vue.ls.set(DEFAULT_LAYOUT_MODE, layout)
state.layout = layout state.layout = layout
}, },
TOGGLE_FIXED_HEADER: (state, fixed) => {
Vue.ls.set(DEFAULT_FIXED_HEADER, fixed)
state.fixedHeader = fixed
},
TOGGLE_FIXED_HEADER_HIDDEN: (state, show) => {
Vue.ls.set(DEFAULT_FIXED_HEADER_HIDDEN, show)
state.swipeDownHiddenHeader = show
},
TOGGLE_COLOR: (state, color) => { TOGGLE_COLOR: (state, color) => {
Vue.ls.set(DEFAULT_COLOR, color) Vue.ls.set(DEFAULT_COLOR, color)
state.color = color state.color = color
...@@ -60,6 +71,12 @@ const app = { ...@@ -60,6 +71,12 @@ const app = {
ToggleLayoutMode({ commit }, mode) { ToggleLayoutMode({ commit }, mode) {
commit('TOGGLE_LAYOUT_MODE', mode) commit('TOGGLE_LAYOUT_MODE', mode)
}, },
ToggleFixedHeader({ commit }, fixedHeader) {
commit('TOGGLE_FIXED_HEADER', fixedHeader)
},
ToggleFixedHeaderHidden({ commit }, show) {
commit('TOGGLE_FIXED_HEADER_HIDDEN', show)
},
ToggleColor({ commit }, color) { ToggleColor({ commit }, color) {
commit('TOGGLE_COLOR', color) commit('TOGGLE_COLOR', color)
}, },
......
...@@ -4,3 +4,5 @@ export const DEFAULT_THEME = 'DEFAULT_THEME' ...@@ -4,3 +4,5 @@ export const DEFAULT_THEME = 'DEFAULT_THEME'
export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE' export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE'
export const DEFAULT_COLOR = 'DEFAULT_COLOR' export const DEFAULT_COLOR = 'DEFAULT_COLOR'
export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK' export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK'
export const DEFAULT_FIXED_HEADER = 'DEFAULT_FIXED_HEADER'
export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'
\ No newline at end of file
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<a-form-item <a-form-item
fieldDecoratorId="password" fieldDecoratorId="password"
:fieldDecoratorOptions="{rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur'}"> :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur'}">
<a-input size="large" type="password" placeholder="密码 / admin"> <a-input size="large" type="password" autocomplete="false" placeholder="密码 / admin">
<a-icon slot="prefix" type='lock' :style="{ color: 'rgba(0,0,0,.25)' }"/> <a-icon slot="prefix" type='lock' :style="{ color: 'rgba(0,0,0,.25)' }"/>
</a-input> </a-input>
</a-form-item> </a-form-item>
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<a-popover placement="right" trigger="click" :visible="state.passwordLevelChecked"> <a-popover placement="right" trigger="click" :visible="state.passwordLevelChecked">
<template slot="content"> <template slot="content">
<div :style="{ width: '240px' }"> <div :style="{ width: '240px' }" >
<div :class="['user-register', passwordLevelClass]">强度:<span>{{ passwordLevelName }}</span></div> <div :class="['user-register', passwordLevelClass]">强度:<span>{{ passwordLevelName }}</span></div>
<a-progress :percent="state.percent" :showInfo="false" :strokeColor=" passwordLevelColor " /> <a-progress :percent="state.percent" :showInfo="false" :strokeColor=" passwordLevelColor " />
<div style="margin-top: 10px;"> <div style="margin-top: 10px;">
...@@ -21,16 +21,12 @@ ...@@ -21,16 +21,12 @@
</template> </template>
<a-form-item <a-form-item
fieldDecoratorId="password" fieldDecoratorId="password"
:fieldDecoratorOptions="{rules: [ :fieldDecoratorOptions="{rules: [{ required: true, message: '至少6位密码,区分大小写'}, { validator: this.handlePasswordLevel }
{ required: true, message: '至少6位密码,区分大小写'}, ]}">
{ validator: this.handlePasswordLevel } <a-input size="large" type="password" @click="handlePasswordInputClick" autocomplete="false" placeholder="至少6位密码,区分大小写"></a-input>
]}"
>
<a-input size="large" type="password" @click="state.passwordLevelChecked = true" autocomplete="false" placeholder="至少6位密码,区分大小写"></a-input>
</a-form-item> </a-form-item>
</a-popover> </a-popover>
<a-form-item <a-form-item
fieldDecoratorId="password2" fieldDecoratorId="password2"
:fieldDecoratorOptions="{rules: [{ required: true, message: '至少6位密码,区分大小写' }, { validator: this.handlePasswordCheck }]}"> :fieldDecoratorOptions="{rules: [{ required: true, message: '至少6位密码,区分大小写' }, { validator: this.handlePasswordCheck }]}">
...@@ -89,6 +85,7 @@ ...@@ -89,6 +85,7 @@
</template> </template>
<script> <script>
import { mapState } from 'vuex'
import { getSmsCaptcha } from '@/api/login' import { getSmsCaptcha } from '@/api/login'
const levelNames = { const levelNames = {
...@@ -129,6 +126,9 @@ ...@@ -129,6 +126,9 @@
} }
}, },
computed: { computed: {
...mapState({
isMobile: state => state.app.device === 'mobile',
}),
passwordLevelClass () { passwordLevelClass () {
return levelClass[this.state.passwordLevel] return levelClass[this.state.passwordLevel]
}, },
...@@ -159,14 +159,13 @@ ...@@ -159,14 +159,13 @@
} }
this.state.passwordLevel = level this.state.passwordLevel = level
this.state.percent = level * 30 this.state.percent = level * 30
console.log('passwordLevel', this.state.passwordLevel, 'level', level)
if (level >= 2) { if (level >= 2) {
if (level >= 3) { if (level >= 3) {
this.state.percent = 100 this.state.percent = 100
} }
callback() callback()
} else { } else {
if (level == 0) { if (level === 0) {
this.state.percent = 10 this.state.percent = 10
} }
callback(new Error('密码强度不够')) callback(new Error('密码强度不够'))
...@@ -181,6 +180,14 @@ ...@@ -181,6 +180,14 @@
callback() callback()
}, },
handlePasswordInputClick () {
if (!this.isMobile) {
this.state.passwordLevelChecked = true
return;
}
this.state.passwordLevelChecked = false
},
handleSubmit() { handleSubmit() {
this.form.validateFields((err, values) => { this.form.validateFields((err, values) => {
if (!err) { if (!err) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment