This commit is contained in:
zhigang.li 2018-07-02 20:48:01 +08:00
parent e881bc0df1
commit b7f68ab2c7
20 changed files with 281 additions and 77 deletions

18
package-lock.json generated
View File

@ -8190,9 +8190,9 @@
"dev": true
},
"iview": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/iview/-/iview-2.14.1.tgz",
"integrity": "sha512-0ykE0nN+uFSpIBqJAwUPotfamajxkYIk5U/Z/SzzQdzl1++byDF/+HDL0w/ShEvHV4h1zJJP6D9jyyK+Qu08Xg==",
"version": "2.14.3",
"resolved": "https://registry.npmjs.org/iview/-/iview-2.14.3.tgz",
"integrity": "sha512-jK5CBNuNBKUZWooCVlipBIUkNnGeZHRtypeuMo9VhQmJ9cCXmuI6BalrtxBFkBCnuUXRdFD34/kSevF9Cc2kpg==",
"requires": {
"async-validator": "1.8.2",
"deepmerge": "2.1.1",
@ -8201,18 +8201,13 @@
"lodash.throttle": "4.1.1",
"popper.js": "1.14.3",
"tinycolor2": "1.4.1",
"v-click-outside-x": "3.0.0"
"v-click-outside-x": "3.0.1"
},
"dependencies": {
"deepmerge": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz",
"integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w=="
},
"v-click-outside-x": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/v-click-outside-x/-/v-click-outside-x-3.0.0.tgz",
"integrity": "sha512-VKm35tQ1tlZFXZc527v05sRXbyoQ8KKT1aeefZrcRCW+mPU4KuTiPy4pe1AH8Pibjzx80iU3pNJ4gNUFSXekUQ=="
}
}
},
@ -14833,6 +14828,11 @@
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==",
"dev": true
},
"v-click-outside-x": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v-click-outside-x/-/v-click-outside-x-3.0.1.tgz",
"integrity": "sha512-Dqy4XEoAPHP/qRzkB5EF+4/luo2G4feAKDrTpjdlsTB9PVHd6D7ryxVkmNsnhDdjOsJDBDcKRsZq8lD8YqbCjQ=="
},
"validate-npm-package-license": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",

View File

@ -18,7 +18,7 @@
"cropperjs": "^1.2.2",
"echarts": "^4.0.4",
"html2canvas": "^1.0.0-alpha.12",
"iview": "^2.14.1",
"iview": "^2.14.3",
"iview-area": "^1.5.17",
"js-cookie": "^2.2.0",
"simplemde": "^1.11.2",

View File

@ -1,6 +1,6 @@
<template>
<div class="cropper-wrapper">
<img ref="cropperImg" :src="src" alt="">
<img id="aaa" ref="cropperImg" alt="">
</div>
</template>
@ -28,10 +28,18 @@ export default {
cropper: null
}
},
watch: {
src (src) {
console.log(src)
console.log(this.cropper)
this.cropper.replace(src)
}
},
mounted () {
this.cropper = new Cropper(this.$refs.cropperImg, {
aspectRatio: 16 / 9,
dragMode: this.dragMode,
console.log(this.$refs.cropperImg)
const aaa = document.getElementById('aaa')
this.cropper = new Cropper(aaa, {
dragMode: 'move',
preview: this.previewId,
restore: false,
center: false,

View File

@ -8,5 +8,5 @@ export default {
* 如果不使用则需要在路由中给需要在菜单中展示的路由设置meta: {title: 'xxx'}
* 用来在菜单中显示文字
*/
useI18n: false
useI18n: true
}

View File

@ -120,17 +120,6 @@ export const getNewTagList = (list, newRoute) => {
return newList
}
/**
* @param {Boolean} status 状态 1 => locked 0 => unlocked
* @description 这里只是为了演示实际应该将锁定状态的设置和获取用接口来实现
*/
export const setLockStatus = (status) => {
localStorage.isLocked = status
}
export const getLockStatus = () => {
return parseInt(localStorage.isLocked)
}
/**
* @param {*} access 用户权限数组 ['super_admin', 'admin']
* @param {*} route 路由列表
@ -261,3 +250,30 @@ export const getTableDataFromArray = (array) => {
tableData
}
}
export const findNodeUpper = (ele, tag) => {
if (ele.parentNode) {
if (ele.parentNode.tagName === tag.toUpperCase()) {
return ele.parentNode
} else {
return findNodeUpper(ele.parentNode, tag)
}
}
}
export const findNodeDownward = (ele, tag) => {
const tagName = tag.toUpperCase()
if (ele.childNodes.length) {
let i = -1
let len = ele.childNodes.length
while (++i < len) {
let child = ele.childNodes[i]
if (child.tagName === tagName) return child
else return findNodeDownward(child, tag)
}
}
}
export const showByAccess = (access, canViewAccess) => {
return hasOneOf(canViewAccess, access)
}

View File

@ -10,10 +10,9 @@ import zhTwLocale from 'iview/src/locale/lang/zh-TW'
Vue.use(VueI18n)
// 自动根据浏览器系统语言设置语言
// const navLang = navigator.language
// const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false
// let lang = window.localStorage.lang || localLang || 'zh-CN'
let lang = 'zh-CN'
const navLang = navigator.language
const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false
let lang = window.localStorage.lang || localLang || 'zh-CN'
Vue.config.lang = lang

View File

@ -1,7 +1,17 @@
export default {
components: 'components',
count_to: 'count-to',
components: 'Components',
count_to_page: 'Count-to',
tables_page: 'Table',
split_pane_page: 'Split-pane',
markdown_page: 'Markdown-editor',
editor_page: 'Rich-Text-Editor',
icons_page: 'Custom-icon',
img_cropper_page: 'Image-editor',
update: 'Update',
update_table_page: 'Update .CSV',
update_paste_page: 'Paste Table Data',
multilevel: 'multilevel',
directive_page: 'Directive',
level_1: 'level-1',
level_2: 'level-2',
level_2_1: 'level-2-1'

View File

@ -1,7 +1,17 @@
export default {
components: '组件',
count_to: '数字渐变',
count_to_page: '数字渐变',
tables_page: '多功能表格',
split_pane_page: '分割窗口',
markdown_page: 'Markdown编辑器',
editor_page: '富文本编辑器',
icons_page: '自定义图标',
img_cropper_page: '图片编辑器',
update: '上传数据',
update_table_page: '上传CSV文件',
update_paste_page: '粘贴表格数据',
multilevel: '多级菜单',
directive_page: '指令',
level_1: 'level-1',
level_2: 'level-2',
level_2_1: 'level-2-1'

View File

@ -1,7 +1,17 @@
export default {
components: '组件',
count_to: '数字渐变',
count_to_page: '数字渐变',
tables_page: '多功能表格',
split_pane_page: '分割窗口',
markdown_page: 'Markdown編輯器',
editor_page: '富文本編輯器',
icons_page: '自定義圖標',
img_cropper_page: '圖片編輯器',
update: '上傳數據',
update_table_page: '上傳CSV文件',
update_paste_page: '粘貼表格數據',
multilevel: '多级菜单',
directive_page: '指令',
level_1: 'level-1',
level_2: 'level-2',
level_2_1: 'level-2-1'

View File

@ -30,6 +30,7 @@ importDirective(Vue)
new Vue({
el: '#app',
router,
i18n,
store,
render: h => h(App)
})

View File

@ -3,49 +3,36 @@ import Router from 'vue-router'
import routes from './routers'
import store from '@/store'
import iView from 'iview'
import { getToken, getLockStatus, canTurnTo } from '@/libs/util'
import { getToken, canTurnTo } from '@/libs/util'
Vue.use(Router)
const router = new Router({
routes
})
const LOCK_PAGE_NAME = 'lock_page'
const LOGIN_PAGE_NAME = 'login'
const IS_LOCKED = getLockStatus()
router.beforeEach((to, from, next) => {
iView.LoadingBar.start()
if (IS_LOCKED && to.name !== LOCK_PAGE_NAME) {
// 当前是锁定状态并且用户要跳转到的页面不是解锁页面
const token = getToken()
if (!token && to.name !== LOGIN_PAGE_NAME) {
// 未登录且要跳转的页面不是登录页
next({
replace: true, // 重定向到解锁页面
name: LOCK_PAGE_NAME
name: LOGIN_PAGE_NAME // 跳转到登录页
})
} else if (!token && to.name === LOGIN_PAGE_NAME) {
// 未登陆且要跳转的页面是登录页
next() // 跳转
} else if (token && to.name === LOGIN_PAGE_NAME) {
// 已登录且要跳转的页面是登录页
next({
name: 'home' // 跳转到home页
})
} else if (IS_LOCKED && to.name === LOCK_PAGE_NAME) {
// 当前未锁定且用户要跳转到的页面是解锁页面
next(false) // 不做跳转
} else {
const token = getToken()
if (!token && to.name !== LOGIN_PAGE_NAME) {
// 未登录且要跳转的页面不是登录页
next({
name: LOGIN_PAGE_NAME // 跳转到登录页
})
} else if (!token && to.name === LOGIN_PAGE_NAME) {
// 未登陆且要跳转的页面是登录页
next() // 跳转
} else if (token && to.name === LOGIN_PAGE_NAME) {
// 已登录且要跳转的页面是登录页
next({
name: 'home' // 跳转到home页
})
} else {
store.dispatch('getUserInfo').then(user => {
// 拉取用户信息通过用户权限和跳转的页面的name来判断是否有权限访问;access必须是一个数组['super_admin'] ['super_admin', 'admin']
if (canTurnTo(to.name, user.access, routes)) next() // 有权限,可访问
else next({ replace: true, name: 'error_401' }) // 无权限重定向到401页面
})
}
store.dispatch('getUserInfo').then(user => {
// 拉取用户信息通过用户权限和跳转的页面的name来判断是否有权限访问;access必须是一个数组['super_admin'] ['super_admin', 'admin']
if (canTurnTo(to.name, user.access, routes)) next() // 有权限,可访问
else next({ replace: true, name: 'error_401' }) // 无权限重定向到401页面
})
}
})

View File

@ -4,7 +4,8 @@ export default {
state: {
breadCrumbList: [],
tagNavList: [],
homeRoute: getHomeRoute(routers)
homeRoute: getHomeRoute(routers),
local: ''
},
getters: {
menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access)
@ -25,6 +26,9 @@ export default {
else state.tagNavList.unshift(item)
setTagNavListInLocalstorage([...state.tagNavList])
}
},
setLocal (state, lang) {
state.local = lang
}
}
}

View File

@ -4,11 +4,12 @@
<i-col>
<Card>
<Row>
<i-col span="4">
<i-col span="5">
<Button type="primary" @click="showModal">显示可拖动弹窗</Button>
<br/>
<Button v-draggable="buttonOptions" class="draggable-btn">这个按钮也是可以拖动的</Button>
</i-col>
<i-col span="20">
<i-col span="19">
<div class="intro-con">
&lt;Modal v-draggable="options" v-model="visible"&gt;标题&lt;/Modal&gt;
<pre class="code-con">
@ -22,10 +23,10 @@
</Row>
</Card>
</i-col>
<Modal v-draggable="options" v-model="modalVisible">
拖动这里即可拖动整个弹窗
</Modal>
</Row>
<Modal v-draggable="options" v-model="modalVisible">
拖动这里即可拖动整个弹窗
</Modal>
</div>
</template>
@ -43,7 +44,8 @@ export default {
buttonOptions: {
trigger: '.draggable-btn',
body: '.draggable-btn'
}
},
statu: 1
}
},
methods: {
@ -56,7 +58,7 @@ export default {
<style>
.intro-con{
height: 140px;
min-height: 140px;
}
.draggable-btn{
margin-top: 20px;

View File

@ -0,0 +1,84 @@
<template>
<div v-if="showFullScreenBtn" class="full-screen-btn-con">
<Tooltip :content="value ? '退出全屏' : '全屏'" placement="bottom">
<Icon @click.native="handleChange" :type="value ? 'arrow-shrink' : 'arrow-expand'" :size="23"></Icon>
</Tooltip>
</div>
</template>
<script>
export default {
name: 'Fullscreen',
computed: {
showFullScreenBtn () {
return window.navigator.userAgent.indexOf('MSIE') < 0
}
},
props: {
value: {
type: Boolean,
default: false
}
},
methods: {
handleFullscreen () {
let main = document.body
if (this.value) {
if (document.exitFullscreen) {
document.exitFullscreen()
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen()
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen()
} else if (document.msExitFullscreen) {
document.msExitFullscreen()
}
} else {
if (main.requestFullscreen) {
main.requestFullscreen()
} else if (main.mozRequestFullScreen) {
main.mozRequestFullScreen()
} else if (main.webkitRequestFullScreen) {
main.webkitRequestFullScreen()
} else if (main.msRequestFullscreen) {
main.msRequestFullscreen()
}
}
},
handleChange () {
this.handleFullscreen()
}
},
mounted () {
let isFullscreen = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen
isFullscreen = !!isFullscreen
document.addEventListener('fullscreenchange', () => {
this.$emit('input', !this.value)
this.$emit('on-change', !this.value)
})
document.addEventListener('mozfullscreenchange', () => {
this.$emit('input', !this.value)
this.$emit('on-change', !this.value)
})
document.addEventListener('webkitfullscreenchange', () => {
this.$emit('input', !this.value)
this.$emit('on-change', !this.value)
})
document.addEventListener('msfullscreenchange', () => {
this.$emit('input', !this.value)
this.$emit('on-change', !this.value)
})
this.$emit('input', isFullscreen)
}
}
</script>
<style lang="less">
.full-screen-btn-con .ivu-tooltip-rel{
height: 64px;
line-height: 73px;
i{
cursor: pointer;
}
}
</style>

View File

@ -0,0 +1,2 @@
import Fullscreen from './fullscreen.vue'
export default Fullscreen

View File

@ -6,5 +6,9 @@
float: right;
height: auto;
padding-right: 20px;
line-height: 64px;
& > *{
float: right;
}
}
}

View File

@ -0,0 +1,2 @@
import Language from './language.vue'
export default Language

View File

@ -0,0 +1,51 @@
<template>
<div>
<Dropdown trigger="click" @on-click="selectLang">
<a href="javascript:void(0)">
{{ title }}
<Icon type="arrow-down-b"></Icon>
</a>
<DropdownMenu slot="list">
<DropdownItem v-for="(value, key) in localList" :name="key" :key="`lang-${key}`">{{ value }}</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
</template>
<script>
export default {
name: 'Language',
props: {
lang: String
},
data () {
return {
langList: {
'zh-CN': '语言',
'zh-TW': '語言',
'en-US': 'Lang'
},
localList: {
'zh-CN': '中文简体',
'zh-TW': '中文繁体',
'en-US': 'English'
}
}
},
watch: {
lang (lang) {
this.$i18n.locale = lang
}
},
computed: {
title () {
return this.langList[this.lang]
}
},
methods: {
selectLang (name) {
this.$emit('on-lang-change', name)
}
}
}
</script>

View File

@ -1,8 +1,9 @@
.user{
&-avator-dropdown{
cursor: pointer;
display: inline-block;
height: 32px;
// height: 64px;
vertical-align: middle;
line-height: 10px;
// line-height: 64px;
}
}

View File

@ -13,6 +13,8 @@
<Header class="header-con">
<header-bar :collapsed="collapsed" @on-coll-change="handleCollapsedChange">
<user :user-avator="userAvator"/>
<language @on-lang-change="setLocal" style="margin-right: 10px;" :lang="local"/>
<fullscreen v-model="isFullscreen" style="margin-right: 10px;"/>
</header-bar>
</Header>
<Content>
@ -35,6 +37,8 @@ import SideMenu from './components/side-menu'
import HeaderBar from './components/header-bar'
import TagsNav from './components/tags-nav'
import User from './components/user'
import Fullscreen from './components/fullscreen'
import Language from './components/language'
import { mapMutations, mapActions } from 'vuex'
import { getNewTagList, getNextName } from '@/libs/util'
import minLogo from '@/assets/images/logo-min.jpg'
@ -45,14 +49,17 @@ export default {
components: {
SideMenu,
HeaderBar,
Language,
TagsNav,
Fullscreen,
User
},
data () {
return {
collapsed: false,
minLogo,
maxLogo
maxLogo,
isFullscreen: false
}
},
computed: {
@ -70,13 +77,17 @@ export default {
},
menuList () {
return this.$store.getters.menuList
},
local () {
return this.$store.state.app.local
}
},
methods: {
...mapMutations([
'setBreadCrumb',
'setTagNavList',
'addTag'
'addTag',
'setLocal'
]),
...mapActions([
'handleLogin'
@ -112,6 +123,8 @@ export default {
this.setTagNavList()
this.addTag(this.$store.state.app.homeRoute)
this.setBreadCrumb(this.$route.matched)
//
this.setLocal(this.$i18n.locale)
}
}
</script>