提交
This commit is contained in:
65
src/layout/components/AppMain.vue
Normal file
65
src/layout/components/AppMain.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'app-main',
|
||||
computed: {
|
||||
cachedViews() {
|
||||
// console.log(this.$store.state.tagsView.cachedViews)
|
||||
return this.$store.state.tagsView.cachedViews
|
||||
},
|
||||
key() {
|
||||
return this.$route.path
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler(to) {
|
||||
if (this.$store.state.settings.tagsView || !to.name) return
|
||||
this.$store.dispatch('tagsView/noTagsAddView', to)
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
render(h) {
|
||||
const { cachedViews, key } = this
|
||||
const keepAlive = (
|
||||
<keep-alive include={cachedViews}>
|
||||
<router-view key={key} />
|
||||
</keep-alive>
|
||||
)
|
||||
window.__KEEP_ALIVE__ = keepAlive
|
||||
return (
|
||||
<section
|
||||
class='app-main-container'
|
||||
id='app-main'
|
||||
>
|
||||
<transition
|
||||
name='fade-transform'
|
||||
mode='out-in'
|
||||
onBeforeLeave={() => this.$el.parentNode.style.overflow = 'hidden'}
|
||||
onAfterEnter={() => this.$el.parentNode.style.overflow = ''}
|
||||
>
|
||||
{keepAlive}
|
||||
</transition>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-main-container {
|
||||
/* BFC */
|
||||
float: left;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// fix css style bug in open el-dialog
|
||||
.el-popup-parent--hidden {
|
||||
.fixed-header {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
65
src/layout/components/Breadcrumb/index.vue
Normal file
65
src/layout/components/Breadcrumb/index.vue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<el-breadcrumb id="breadcrumb-container" class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
levelList: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
// only show routes with meta.title
|
||||
const matched = this.$route.matched.filter(item => item.meta && item.meta.title)
|
||||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||
},
|
||||
pathCompile(path) {
|
||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||
const { params } = this.$route
|
||||
var toPath = pathToRegexp.compile(path)
|
||||
return toPath(params)
|
||||
},
|
||||
handleLink(item) {
|
||||
const { redirect, path } = item
|
||||
if (redirect) {
|
||||
this.$router.push(redirect)
|
||||
return
|
||||
}
|
||||
this.$router.push(this.pathCompile(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
34
src/layout/components/Hamburger/index.vue
Normal file
34
src/layout/components/Hamburger/index.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div id="hamburger-container" style="padding: 0 18px;" @click="toggleClick">
|
||||
<svg-icon icon-class="hamburger" class="hamburger" :class="{'is-active':isActive}" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'hamburger',
|
||||
props: {
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleClick() {
|
||||
this.$emit('toggleClick')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less' scoped>
|
||||
.hamburger {
|
||||
display: inline-block;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
.hamburger.is-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
||||
91
src/layout/components/Logo.vue
Normal file
91
src/layout/components/Logo.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="sidebar-logo-container" :class="{'collapse':collapse}">
|
||||
<div key="collapse" class="sidebar-logo-link" to="/dashboard">
|
||||
<!-- <img v-if="logo" :src="settings.title=='电能质量监测系统'?logo:logo1" class="sidebar-logo" :style="{ width: settings.layout === 'layout1' ? '35px' : '50px',height: settings.layout === 'layout1' ? '35px' : '50px'}"> -->
|
||||
<img :src="logourl" class="sidebar-logo" :style="{ width: settings.layout === 'layout1' ? '35px' : '180px',height: settings.layout === 'layout1' ? '35px' : '50px'}">
|
||||
<!-- <svg-icon icon-class="logo" class="sidebar-logo" /> -->
|
||||
<transition name="sidebarLogoFade">
|
||||
<h1
|
||||
v-show="!collapse"
|
||||
class="sidebar-title"
|
||||
:style="{ fontSize: settings.layout === 'layout1' && settings.title.length >= 8 ? '14px' : '24px'}"
|
||||
>{{ settings.title }} </h1>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'sidebar-logo',
|
||||
props: {
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['settings'])
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// logo: require('../../assets/login/'+window.logo),
|
||||
logourl:window.sessionStorage.logo
|
||||
}
|
||||
},
|
||||
created(){
|
||||
// console.log(this.logourl)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "~@/styles/variables.scss";
|
||||
.sidebarLogoFade-enter-active {
|
||||
transition: opacity 1.5s;
|
||||
}
|
||||
|
||||
.sidebarLogoFade-enter,
|
||||
.sidebarLogoFade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.sidebar-logo-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
padding-left: 20px;
|
||||
overflow: hidden;
|
||||
line-height: 60px;
|
||||
|
||||
& .sidebar-logo-link {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
& .sidebar-logo {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
margin-right: 8px;
|
||||
color: #fff;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
& .sidebar-title {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 50px;
|
||||
color: #fff;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapse {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
29
src/layout/components/Navbar/Item.vue
Normal file
29
src/layout/components/Navbar/Item.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'menu-item',
|
||||
functional: true,
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
render(h, context) {
|
||||
const { icon, title } = context.props
|
||||
const vnodes = []
|
||||
|
||||
if (icon) {
|
||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
||||
}
|
||||
|
||||
if (title) {
|
||||
vnodes.push(<span>{(title)}</span>)
|
||||
}
|
||||
return vnodes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
61
src/layout/components/Navbar/NavbarItem.vue
Normal file
61
src/layout/components/Navbar/NavbarItem.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<el-menu-item v-if="!item.children || item.children.every(it=>it.hidden)" :index="item.routePath || item.url">
|
||||
<app-link :to="to(item)">
|
||||
<item :icon="item.icon" :title="item.title" />
|
||||
</app-link>
|
||||
</el-menu-item>
|
||||
<el-submenu v-else :class="{'no-arrow': item.title === '...'}" :index="item.routePath">
|
||||
<span slot="title">
|
||||
<item :icon="item.icon" :title="item.title" />
|
||||
</span>
|
||||
<navbar-item
|
||||
v-for="(child,idx) in item.children"
|
||||
:key="idx"
|
||||
:index="idx"
|
||||
:item="child"
|
||||
/>
|
||||
</el-submenu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Item from './Item.vue'
|
||||
import AppLink from '../Sidebar/Link.vue'
|
||||
|
||||
export default {
|
||||
name: 'navbar-item',
|
||||
components: { Item, AppLink },
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
to(menuItem) {
|
||||
const visitedTags = this.$store.state.tagsView.visitedTags
|
||||
const tag = visitedTags.find(t => t.routeName === menuItem.routeName)
|
||||
return tag ? tag.routePath : menuItem.routePath
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.el-menu--horizontal .svg-icon {
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.no-arrow ::v-deep .el-submenu__title {
|
||||
width: 60px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
123
src/layout/components/Navbar/index.vue
Normal file
123
src/layout/components/Navbar/index.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="navbar-menu">
|
||||
<el-menu
|
||||
:default-active="customActiveMenu || activeMenu"
|
||||
unique-opened
|
||||
mode="horizontal"
|
||||
>
|
||||
<navbar-item v-for="(item,index) in renderMenu" :key="index" :item="item" :index="index" />
|
||||
</el-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import NavbarItem from './NavbarItem'
|
||||
import variables from '@/styles/variables.scss'
|
||||
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
|
||||
|
||||
export default {
|
||||
components: { NavbarItem },
|
||||
props: {
|
||||
menus: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
customActiveMenu: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
renderMenu: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sidebar'
|
||||
]),
|
||||
activeMenu() {
|
||||
if (this.$route.meta.activeMenu) {
|
||||
return this.$route.meta.activeMenu
|
||||
}
|
||||
return this.$route.path
|
||||
},
|
||||
variables() {
|
||||
return variables
|
||||
},
|
||||
isCollapse() {
|
||||
return !this.sidebar.opened
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
menus() {
|
||||
this.setMenus()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.setMenus()
|
||||
}, 200)
|
||||
addResizeListener(this.$el, this.setMenus)
|
||||
},
|
||||
beforeDestroy() {
|
||||
removeResizeListener(this.$el, this.setMenus)
|
||||
},
|
||||
methods: {
|
||||
setMenus() {
|
||||
const wrapperW = this.$el.offsetWidth
|
||||
const topMenu = []
|
||||
const otherMenu = []
|
||||
let nowW = 0
|
||||
this.menus.forEach(item => {
|
||||
nowW += this.getItemW(item)
|
||||
if (nowW + 100 > wrapperW) {
|
||||
otherMenu.push(item)
|
||||
} else {
|
||||
topMenu.push(item)
|
||||
}
|
||||
})
|
||||
if (otherMenu.length > 0) {
|
||||
topMenu.push({
|
||||
title: '...',
|
||||
routePath: '/',
|
||||
children: otherMenu
|
||||
})
|
||||
}
|
||||
this.renderMenu = topMenu
|
||||
},
|
||||
getItemW(item) {
|
||||
// 20 14 8 20
|
||||
let w = 0
|
||||
if (item.icon) w += 22 // 图标长度
|
||||
if (item.children) w += 20 // 右边下箭头
|
||||
w += item.title.length * 14 // 文字长度
|
||||
w += 40 // padding
|
||||
return w
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.navbar-menu {
|
||||
flex: 1;
|
||||
& ::v-deep .el-menu.el-menu--horizontal {
|
||||
display: flex;
|
||||
border-bottom: none;
|
||||
.el-submenu__title {
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
}
|
||||
& ::v-deep .el-menu-item {
|
||||
padding: 0;
|
||||
& > a {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
574
src/layout/components/RightMenu.vue
Normal file
574
src/layout/components/RightMenu.vue
Normal file
@@ -0,0 +1,574 @@
|
||||
<template>
|
||||
<div class="right-menu">
|
||||
<div class="menu-item">
|
||||
<span style="width: 210px;font-size: 14px;font-weight: 500;color:#05fd3c">当前时间:{{nowtime}}</span>
|
||||
<!-- <el-button type="primary" round @click="ddd" size="mini" >关闭告警</el-button>
|
||||
<el-badge :value="200" :max="99" class="item" >
|
||||
<i class="el-icon-message-solid" style="font-size: 20px;" @click="message"/>
|
||||
</el-badge> -->
|
||||
</div>
|
||||
<el-dropdown trigger="click" size="medium">
|
||||
<div id="right-menu-set" class="menu-item">
|
||||
<i class="el-icon-s-custom" /><span style="margin-left: 5px" v-if="flag"
|
||||
>{{ userInfo.name
|
||||
}}<i style="margin-left: 5px" class="el-icon-caret-bottom"
|
||||
/></span>
|
||||
</div>
|
||||
<!-- <el-dropdown-menu slot="dropdown" id="dropdown" class="user-dropdown" :style="device==1?'zoom:1':'zoom:1.06'"> -->
|
||||
<el-dropdown-menu slot="dropdown" id="dropdown" class="user-dropdown">
|
||||
<!-- <el-dropdown-menu slot="dropdown" id="dropdown" class="user-dropdown"> -->
|
||||
<el-dropdown-item>
|
||||
<span style="display: block" @click="userclickd()">用户信息</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="handleResetPassword()">
|
||||
<span style="display: block">修改密码</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<span style="dispblock" @click="goto">帮助文档</span>
|
||||
</el-dropdown-item>
|
||||
<!-- divided closelostar-->
|
||||
<el-dropdown-item @click.native="logout(1)">
|
||||
<span style="display: block">清理缓存</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="logout(0)">
|
||||
<span style="display: block">退出登录</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
title="修改密码"
|
||||
:visible.sync="dialogVisible1"
|
||||
append-to-body
|
||||
width="30%"
|
||||
:before-close="closepw"
|
||||
>
|
||||
<el-form ref="passwordform" :model="passwordform" :rules="rules" label-width="100px">
|
||||
<el-form-item label="旧密码:" prop="password">
|
||||
<el-input v-model="passwordform.password" type="password" placeholder="请输入旧密码"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码:" prop="newPwd" class="top" >
|
||||
<el-input v-model="passwordform.newPwd" type="password" placeholder="请输入新密码"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码:" prop="confirmPwd" class="top">
|
||||
<el-input v-model="passwordform.confirmPwd" type="password" placeholder="请输入确认密码"/>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button
|
||||
text-align="center"
|
||||
|
||||
@click="resetForm('passwordform')"
|
||||
>取 消</el-button
|
||||
>
|
||||
<el-button text-align="center" type="primary" @click="submint"
|
||||
>确认</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
title="用户信息"
|
||||
append-to-body
|
||||
:visible.sync="dialogVisible2"
|
||||
width="30%"
|
||||
>
|
||||
<el-form ref="form" :model="form" label-width="100px">
|
||||
<el-form-item label="用户名称:">
|
||||
<el-input v-model="form.name" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录名称:" class="top" >
|
||||
<el-input v-model="form.loginName" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="归属部门名称:" class="top" >
|
||||
<el-input v-model="form.deptName" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="拥有的角色:" class="top" >
|
||||
<el-input v-model="form.roles" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话号码:" class="top" >
|
||||
<el-input v-model="form.iphone" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="电子邮箱:" class="top" >
|
||||
<el-input v-model="form.emirl" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<!-- <el-form-item label="系统类型:">
|
||||
<el-input v-model="form.systype" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态:">
|
||||
<el-input v-model="form.status" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录时间:">
|
||||
<el-input v-model="form.lofintime" :disabled="true"></el-input>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from "vuex";
|
||||
import {
|
||||
add,
|
||||
list,
|
||||
getById,
|
||||
deleteById,
|
||||
dept,
|
||||
edit,
|
||||
detptree,
|
||||
rolelist,
|
||||
selecRoleDetail,
|
||||
passwordConfirm,
|
||||
deluser,
|
||||
updatePassword,
|
||||
activateUser,
|
||||
exportUser,
|
||||
exportUserExcel,
|
||||
} from "@/api/admin/user";
|
||||
import { gongkey, userfunction } from "@/api/user";
|
||||
import axios from "axios";
|
||||
import { sm3Digest } from "@/assets/commjs/sm3";
|
||||
import { sm2, encrypt } from "@/assets/commjs/sm2.js";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
var validatePass = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入密码"));
|
||||
} else {
|
||||
if (this.passwordform.confirmPwd !== "") {
|
||||
this.$refs.passwordform.validateField("confirmPwd");
|
||||
}
|
||||
callback();
|
||||
}
|
||||
};
|
||||
var validatePass2 = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请再次输入密码"));
|
||||
} else if (value !== this.passwordform.newPwd) {
|
||||
callback(new Error("两次输入密码不一致!"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
flag: true,
|
||||
dialogVisible2: false,
|
||||
dialogVisible1: false,
|
||||
passwordform: {
|
||||
password: "",
|
||||
newPwd:'',
|
||||
confirmPwd:''
|
||||
},
|
||||
nowtime:'',
|
||||
LocationProvince:"正在定位所在省", //给渲染层定义一个初始值
|
||||
LocationCity:"正在定位所在市" , //给渲染层定义一个初始值
|
||||
form: {
|
||||
name: "",
|
||||
deptName: "",
|
||||
iphone: "",
|
||||
emirl: "",
|
||||
roles: '',
|
||||
loginName: "",
|
||||
systype: "",
|
||||
status: "",
|
||||
lofintime: "",
|
||||
},
|
||||
password3: "",
|
||||
id: "",
|
||||
device: 1,
|
||||
pd: "",
|
||||
|
||||
rules: {
|
||||
password: [
|
||||
{ required: true, message: "请输入旧密码", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 16,
|
||||
message: "长度在 6 到 16 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
{ validator: validatePass, trigger: "blur" },
|
||||
],
|
||||
newPwd: [
|
||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 16,
|
||||
message: "长度在 6 到 16 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
{ validator: validatePass, trigger: "blur" },
|
||||
],
|
||||
confirmPwd: [
|
||||
{ required: true, message: "请确认密码", trigger: "blur" },
|
||||
{
|
||||
min: 6,
|
||||
max: 16,
|
||||
message: "长度在 6 到 16 个字符",
|
||||
trigger: "blur",
|
||||
},
|
||||
{ validator: validatePass2, trigger: "blur", required: true },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["userInfo"]),
|
||||
},
|
||||
created() {
|
||||
this.device = window.devicePixelRatio;
|
||||
|
||||
|
||||
},
|
||||
mounted() {
|
||||
// this.city() //触发获取城市方法
|
||||
setInterval(()=>{
|
||||
this.getnowtime()
|
||||
},500)
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
changeSetting: "settings/changeSetting",
|
||||
}),
|
||||
|
||||
async logout(t) {
|
||||
this.flag = false;
|
||||
await this.$store.dispatch("user/logout");
|
||||
if(t==1){
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "缓存清理成功!",
|
||||
});
|
||||
}else{
|
||||
return
|
||||
}
|
||||
},
|
||||
toggleSettings() {
|
||||
const showSettings = this.$store.state.app.showSettings;
|
||||
this.$store.state.app.showSettings = !showSettings;
|
||||
},
|
||||
|
||||
goto(t) {
|
||||
//this.$router.push({path:'/algorithm/algorithm1',query:{name:'wtzhpg',path:'/algorithm/algorithm1'}})
|
||||
this.$router.push({ path: "/algorithm/algorithm1" });
|
||||
|
||||
|
||||
},
|
||||
message() {
|
||||
// alert(9)
|
||||
this.$router.push("/BusinessAdministrator/alarManagement/AlarmInformation");
|
||||
},
|
||||
ddd() {
|
||||
this.$notify.closeAll();
|
||||
},
|
||||
closelostar() {
|
||||
this.$confirm("此操作将清理所有信息缓存, 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
window.localStorage.removeItem("loglevel:webpack-dev-server");
|
||||
window.localStorage.removeItem("CUSTOM_SETTINGS");
|
||||
//window.localStorage.clear()
|
||||
//window.sessionStorage.clear()
|
||||
this.$store.dispatch("user/logout");
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "缓存清理成功!",
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message({
|
||||
type: "info",
|
||||
message: "已取消缓存清理",
|
||||
});
|
||||
});
|
||||
},
|
||||
userclickd() {
|
||||
this.dialogVisible2 = true;
|
||||
var info = window.sessionStorage.getItem("Info");
|
||||
info = eval("(" + info + ")");
|
||||
// var gNamelist=[]
|
||||
// for (var i = 0; i < info.role.length; i++) {
|
||||
// gNamelist.push(row.role[i]);
|
||||
// }
|
||||
// gNamelist.join();
|
||||
this.form.name = info.name;
|
||||
this.form.deptName = info.deptName;
|
||||
if (info.type == 1) {
|
||||
this.form.systype = "省级系统";
|
||||
} else {
|
||||
this.form.systype = "数据中心";
|
||||
}
|
||||
this.form.emirl = info.emirl;
|
||||
let str = info.loginTime
|
||||
let str1=str.split('T')
|
||||
//console.log(str1)
|
||||
this.form.lofintime = str1[0]+" "+str1[1];
|
||||
// let r = ''
|
||||
// info.role.forEach((m,index) => {
|
||||
// r+=m+', '
|
||||
// });
|
||||
this.form.roles = info.role.join()
|
||||
//this.form.roles =JSON.stringify(info.role);
|
||||
|
||||
|
||||
if (info.state == 1) {
|
||||
this.form.status = "正常";
|
||||
}
|
||||
this.form.loginName = info.loginName;
|
||||
},
|
||||
resetForm(formName){
|
||||
this.$refs[formName].resetFields();
|
||||
},
|
||||
closepw(){
|
||||
this.$refs.passwordform.resetFields();
|
||||
this.dialogVisible1 = false;
|
||||
},
|
||||
handleResetPassword() {
|
||||
this.passwordform.password = "";
|
||||
this.passwordform.newPwd = "";
|
||||
this.passwordform.confirmPwd = "";
|
||||
|
||||
this.pd = "pw";
|
||||
this.dialogVisible1 = true;
|
||||
var info = window.sessionStorage.getItem("Info");
|
||||
info = eval("(" + info + ")");
|
||||
this.id = info.id;
|
||||
|
||||
this.gongKey();
|
||||
},
|
||||
submint() {
|
||||
this.gonxxKey();
|
||||
},
|
||||
gonxxKey() {
|
||||
gongkey({ loginName: window.sessionStorage.cnloginname }).then((response) => {
|
||||
if (response.code === "A0000") {
|
||||
var publicKey = response.data;
|
||||
// console.log("获取公钥后赋值" + publicKey);
|
||||
var sm3Pwd = sm3Digest(this.passwordform.password); //SM3加密
|
||||
var jiamipassword = "";
|
||||
jiamipassword = sm2(
|
||||
sm3Pwd + "|" + this.passwordform.password,
|
||||
publicKey,
|
||||
0
|
||||
); //SM2公钥加密
|
||||
this.password3 = jiamipassword;
|
||||
// console.log("密码加密后hhhhh:" + jiamipassword);
|
||||
// console.log("测试" + this.password3);
|
||||
if (this.pd == "del") {
|
||||
var password = this.password3;
|
||||
this.dialogVisible1 = false;
|
||||
passwordConfirm(password).then((response) => {
|
||||
if (response.code === "A0000") {
|
||||
this.$confirm("此操作将永久删除该用户, 是否继续?", "提示", {
|
||||
confirmButtonText: "删除",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
let data = {
|
||||
id: this.id,
|
||||
};
|
||||
deluser(data).then((response) => {
|
||||
this.$message({ type: "success", message: "删除成功" });
|
||||
});
|
||||
this.handleQuery();
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message({
|
||||
type: "info",
|
||||
message: "已取消删除",
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.pd === "pw") {
|
||||
var password = this.password3;
|
||||
this.dialogVisible1 = false;
|
||||
passwordConfirm(password).then((response) => {
|
||||
if (response.code === "A0000") {
|
||||
// this.$prompt("请输入新密码", "提示", {
|
||||
// confirmButtonText: "确定",
|
||||
// cancelButtonText: "取消",
|
||||
// })
|
||||
// .then(({ value }) => {
|
||||
gongkey({loginName: window.sessionStorage.cnloginname}).then((response) => {
|
||||
if (response.code === "A0000") {
|
||||
var publicKey = response.data;
|
||||
// console.log("获取公钥后赋值" + publicKey);
|
||||
var sm3Pwd = sm3Digest(this.passwordform.newPwd); //SM3加密
|
||||
var jiamipassword = "";
|
||||
jiamipassword = sm2( sm3Pwd + "|" + this.passwordform.newPwd, publicKey, 0); //SM2公钥加密
|
||||
let id = window.sessionStorage.getItem("Info").id;
|
||||
let data = {
|
||||
id: this.id,
|
||||
newPassword: jiamipassword,
|
||||
};
|
||||
updatePassword(data).then((response) => {
|
||||
if (response.code === "A0000") {
|
||||
this.$message({
|
||||
type: "success",
|
||||
message: "修改成功",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// })
|
||||
// .catch(() => {
|
||||
// this.$message({
|
||||
// type: "info",
|
||||
// message: "取消输入",
|
||||
// });
|
||||
// });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
getnowtime(){
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = ('0' + (now.getMonth() + 1)).slice(-2);
|
||||
const day = ('0' + now.getDate()).slice(-2);
|
||||
const hours = ('0' + now.getHours()).slice(-2);
|
||||
const minutes = ('0' + now.getMinutes()).slice(-2);
|
||||
const seconds = ('0' + now.getSeconds()).slice(-2);
|
||||
|
||||
this.nowtime = year +"-"+ month +"-"+ day +":"+ hours +":"+ minutes +":"+ seconds;
|
||||
},
|
||||
city(){ //定义获取城市方法
|
||||
|
||||
const geolocation = new BMap.Geolocation();
|
||||
|
||||
var _this = this
|
||||
|
||||
geolocation.getCurrentPosition(function getinfo(position){
|
||||
|
||||
let city = position.address.city; //获取城市信息
|
||||
|
||||
let province = position.address.province; //获取省份信息
|
||||
|
||||
_this.LocationProvince = province
|
||||
|
||||
_this.LocationCity = city
|
||||
|
||||
}, function(e) {
|
||||
|
||||
_this.LocationCity = "定位失败"
|
||||
|
||||
}, {provider: 'baidu'});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// delAllCookie() {
|
||||
// //清空全部cookie
|
||||
// var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
|
||||
// if (keys) {
|
||||
// for (var i = keys.length; i--; ) {
|
||||
// document.cookie =
|
||||
// keys[i] + "=0;path=/;expires=" + new Date(0).toUTCString(); //清除当前域名下
|
||||
// document.cookie =
|
||||
// keys[i] +"=0;path=/;domain=" +document.domain +";expires=" +
|
||||
// new Date(0).toUTCString();
|
||||
// document.cookie =
|
||||
// keys[i] +"=0;path=示例:/index.vue(不同域的path,也就是你清除不了的cookie);domain=示例:10.10.10.208(不同域的domain,也就是你清除不了的cookie);expires=" +
|
||||
// new Date(0).toUTCString();
|
||||
// // **document.cookie可加多条!!!!**
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import url("../../styles/comStyle.less");
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.item {
|
||||
margin-top: 0px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.right-menu {
|
||||
display: flex;
|
||||
border-left: 1px solid #d4d4d400 !important;
|
||||
//background: red;
|
||||
height: 100%;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.right-menu-item {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
padding: 0 8px;
|
||||
font-size: 18px;
|
||||
color: #5a5e66;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
padding: 0 10px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.el-icon-caret-bottom {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.user-dropdown {
|
||||
min-width: 100px;
|
||||
// display: flex;
|
||||
position: absolute;
|
||||
z-index: 9999999999999 !important;
|
||||
left: 99%;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
||||
display: none;
|
||||
}
|
||||
.v-modal {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.5;
|
||||
/* background: #7a6464; */
|
||||
}
|
||||
</style>
|
||||
189
src/layout/components/Settings/index.vue
Normal file
189
src/layout/components/Settings/index.vue
Normal file
@@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
title="页面设置"
|
||||
:visible.sync="$store.state.app.showSettings"
|
||||
direction="rtl"
|
||||
append-to-body
|
||||
custom-class="settings-drawer"
|
||||
>
|
||||
<div class="drawer-container">
|
||||
<div class="drawer-item">
|
||||
<span>布局类型</span>
|
||||
<ul class="layout">
|
||||
<li @click="changeSetting({layout:'layout1'})">
|
||||
<img src="../../../assets/layout/layout1.svg" alt="layout1">
|
||||
<i v-show="settings.layout === 'layout1'" class="el-icon-check" />
|
||||
</li>
|
||||
<li @click="changeSetting({layout:'layout2'})">
|
||||
<img src="../../../assets/layout/layout2.svg" alt="layout2">
|
||||
<i v-show="settings.layout === 'layout2'" class="el-icon-check" />
|
||||
</li>
|
||||
<li @click="changeSetting({layout:'layout3'})">
|
||||
<img src="../../../assets/layout/layout3.svg" alt="layout3">
|
||||
<i v-show="settings.layout === 'layout3'" class="el-icon-check" />
|
||||
</li>
|
||||
<li @click="changeSetting({layout:'layout4'})">
|
||||
<img src="../../../assets/layout/layout4.svg" alt="layout4">
|
||||
<i v-show="settings.layout === 'layout4'" class="el-icon-check" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="drawer-item">
|
||||
<span>主题色</span>
|
||||
<el-color-picker
|
||||
:value="settings.themeColor || '#4451B2'"
|
||||
:predefine="['#4451B2', '#12B1B1', '#409EFF', '#E84B16', '#fa541c','#EBA313', '#4CB418', '#2f54eb', '#722ed1']"
|
||||
popper-class="theme-picker-dropdown"
|
||||
style="float: right; height: 26px; margin: -3px 8px 0 0;"
|
||||
class="theme-picker"
|
||||
@change="themeColor=>changeSetting({themeColor})"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>布局大小</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
class="drawer-select"
|
||||
:value="settings.size"
|
||||
@change="sizeChange"
|
||||
>
|
||||
<el-option label="小" value="mini" />
|
||||
<el-option label="中" value="small" />
|
||||
<el-option label="大" value="medium" />
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>开启页签</span>
|
||||
<el-switch
|
||||
:value="settings.tagsView"
|
||||
class="drawer-switch"
|
||||
@input="tagsView=>changeSetting({tagsView})"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>固定头部</span>
|
||||
<el-switch
|
||||
:value="settings.layout !== 'layout2' && settings.layout !== 'layout1' ? true : settings.fixedHeader"
|
||||
class="drawer-switch"
|
||||
:disabled="settings.layout !== 'layout2' && settings.layout !== 'layout1' "
|
||||
@input="fixedHeader=>changeSetting({fixedHeader})"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
import { addClass } from '@/utils/className.js'
|
||||
import { removeClass } from '@/utils/className'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
settings() {
|
||||
return this.$store.state.settings
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
changeSetting: 'settings/changeSetting'
|
||||
}),
|
||||
sizeChange(size) {
|
||||
this.$ELEMENT.size = size
|
||||
//console.log(`PAGE_SIZE-${this.settings.size}`)
|
||||
removeClass(document.body, `PAGE-SIZE-${this.settings.size}`)
|
||||
addClass(document.body, `PAGE-SIZE-${size}`)
|
||||
this.changeSetting({ size })
|
||||
this.refreshView()
|
||||
this.$message({
|
||||
message: '切换布局大小成功',
|
||||
type: 'success'
|
||||
})
|
||||
},
|
||||
refreshView() {
|
||||
// In order to make the cached page re-rendered
|
||||
this.$store.dispatch('tagsView/delAllTags')
|
||||
|
||||
const { fullPath } = this.$route
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$router.replace({
|
||||
path: '/redirect' + fullPath
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.drawer-container {
|
||||
padding: 0 24px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
|
||||
.drawer-item {
|
||||
padding: 12px 0;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
|
||||
.layout {
|
||||
margin-top: 16px;
|
||||
|
||||
& > li {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 52px;
|
||||
height: 45px;
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: #409EFF;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-switch {
|
||||
float: right;
|
||||
}
|
||||
.drawer-select {
|
||||
float: right;
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-picker ::v-deep .el-color-picker__trigger {
|
||||
width: 26px !important;
|
||||
height: 26px !important;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.theme-picker-dropdown {
|
||||
z-index: 99999 !important;
|
||||
}
|
||||
|
||||
.settings-drawer {
|
||||
width: 250px !important;
|
||||
}
|
||||
</style>
|
||||
26
src/layout/components/Sidebar/FixiOSBug.js
Normal file
26
src/layout/components/Sidebar/FixiOSBug.js
Normal file
@@ -0,0 +1,26 @@
|
||||
export default {
|
||||
computed: {
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
||||
this.fixBugIniOS()
|
||||
},
|
||||
methods: {
|
||||
fixBugIniOS() {
|
||||
const $subMenu = this.$refs.subMenu
|
||||
if ($subMenu) {
|
||||
const handleMouseleave = $subMenu.handleMouseleave
|
||||
$subMenu.handleMouseleave = (e) => {
|
||||
if (this.device === 'mobile') {
|
||||
return
|
||||
}
|
||||
handleMouseleave(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/layout/components/Sidebar/Item.vue
Normal file
29
src/layout/components/Sidebar/Item.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'menu-item',
|
||||
functional: true,
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
render(h, context) {
|
||||
const { icon, title } = context.props
|
||||
const vnodes = []
|
||||
|
||||
if (icon) {
|
||||
vnodes.push(<svg-icon icon-class={icon}/>)
|
||||
}
|
||||
|
||||
if (title) {
|
||||
vnodes.push(<span slot='title'>{(title)}</span>)
|
||||
}
|
||||
return vnodes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
36
src/layout/components/Sidebar/Link.vue
Normal file
36
src/layout/components/Sidebar/Link.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
<template>
|
||||
<!-- eslint-disable vue/require-component-is -->
|
||||
<component v-bind="linkProps(to)">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkProps(url) {
|
||||
if (isExternal(url)) {
|
||||
return {
|
||||
is: 'a',
|
||||
href: url,
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
}
|
||||
}
|
||||
return {
|
||||
is: 'router-link',
|
||||
to: url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
57
src/layout/components/Sidebar/SidebarItem.vue
Normal file
57
src/layout/components/Sidebar/SidebarItem.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div>
|
||||
<template v-if='!item.children || item.children.every(it=>it.hidden)'>
|
||||
<app-link :to='to(item)'>
|
||||
<el-menu-item :index='item.routePath' :class="{'submenu-title-noDropdown':!isNest}">
|
||||
<item :icon='item.icon' :title='item.title' />
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</template>
|
||||
<el-submenu v-else ref='subMenu' :index='item.routePath' popper-append-to-body>
|
||||
<template slot='title'>
|
||||
<item :icon='item.icon' :title='item.title' />
|
||||
</template>
|
||||
<sidebar-item
|
||||
v-for='(child,idx) in item.children'
|
||||
:key='idx'
|
||||
:index='idx'
|
||||
:is-nest='true'
|
||||
:item='child'
|
||||
class='nest-menu'
|
||||
/>
|
||||
</el-submenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Item from './Item'
|
||||
import AppLink from './Link'
|
||||
import FixiOSBug from './FixiOSBug'
|
||||
|
||||
export default {
|
||||
name: 'sidebar-item',
|
||||
components: { Item, AppLink },
|
||||
mixins: [FixiOSBug],
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
isNest: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
to(menuItem) {
|
||||
const visitedTags = this.$store.state.tagsView.visitedTags
|
||||
const tag = visitedTags.find(t => t.routeName === menuItem.routeName)
|
||||
return tag ? tag.routePath : menuItem.routePath
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
50
src/layout/components/Sidebar/index.vue
Normal file
50
src/layout/components/Sidebar/index.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="sidebar-container">
|
||||
<el-menu :default-active="activeMenu" :collapse="collapse" :collapse-transition="false" unique-opened>
|
||||
<sidebar-item v-for="(item, index) in menus" :key="index" :item="item" :index="index" />
|
||||
</el-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SidebarItem from './SidebarItem'
|
||||
|
||||
export default {
|
||||
components: { SidebarItem },
|
||||
props: {
|
||||
menus: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
collapse() {
|
||||
setTimeout(() => {
|
||||
window.echartsArr &&
|
||||
window.echartsArr.forEach(item => {
|
||||
item.resize()
|
||||
})
|
||||
}, 200)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
activeMenu() {
|
||||
if (this.$route.meta.activeMenu) {
|
||||
return this.$route.meta.activeMenu
|
||||
}
|
||||
if(this.$route.fullPath.indexOf('iframe') > -1){
|
||||
return this.$route.fullPath
|
||||
}else{
|
||||
return this.$route.path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './sidebar.scss';
|
||||
</style>
|
||||
50
src/layout/components/Sidebar/sidebar.scss
Normal file
50
src/layout/components/Sidebar/sidebar.scss
Normal file
@@ -0,0 +1,50 @@
|
||||
.sidebar-container ::v-deep {
|
||||
.svg-icon {
|
||||
// margin-right: 16px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.el-menu {
|
||||
width: 100% !important;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
& .nest-menu {
|
||||
font-size: 0;
|
||||
}
|
||||
.el-menu>div {
|
||||
padding: 5px 0;
|
||||
}
|
||||
.el-menu-item,
|
||||
.el-submenu__title {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
.el-submenu__title {
|
||||
.el-submenu__icon-arrow {
|
||||
position: relative;
|
||||
right: 0;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.el-menu--collapse {
|
||||
.el-submenu {
|
||||
&>.el-submenu__title {
|
||||
&>span {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
.el-submenu__icon-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reset element-ui css
|
||||
.horizontal-collapse-transition {
|
||||
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
|
||||
}
|
||||
100
src/layout/components/TagsView/ScrollPane.vue
Normal file
100
src/layout/components/TagsView/ScrollPane.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
|
||||
<slot />
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const tagAndTagSpacing = 4 // tagAndTagSpacing
|
||||
|
||||
export default {
|
||||
name: 'scroll-pane',
|
||||
props: {
|
||||
watchData: {}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
left: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
scrollWrapper() {
|
||||
return this.$refs.scrollContainer.$refs.wrap
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
watchData: {
|
||||
handler() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.scrollContainer.update()
|
||||
})
|
||||
},
|
||||
immediate: false,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleScroll(e) {
|
||||
const eventDelta = e.wheelDelta || -e.deltaY * 40
|
||||
const $scrollWrapper = this.scrollWrapper
|
||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
|
||||
},
|
||||
moveToTarget(currentTag) {
|
||||
const $container = this.$refs.scrollContainer.$el
|
||||
const $containerWidth = $container.offsetWidth
|
||||
const $scrollWrapper = this.scrollWrapper
|
||||
const tagList = this.$parent.$refs.tag
|
||||
|
||||
let firstTag = null
|
||||
let lastTag = null
|
||||
|
||||
// find first tag and last tag
|
||||
if (tagList.length > 0) {
|
||||
debugger
|
||||
firstTag = tagList[0]
|
||||
lastTag = tagList[tagList.length - 1]
|
||||
}
|
||||
|
||||
if (firstTag === currentTag) {
|
||||
$scrollWrapper.scrollLeft = 0
|
||||
} else if (lastTag === currentTag) {
|
||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
|
||||
} else {
|
||||
// find preTag and nextTag
|
||||
const currentIndex = tagList.findIndex(item => item === currentTag)
|
||||
const prevTag = tagList[currentIndex - 1]
|
||||
const nextTag = tagList[currentIndex + 1]
|
||||
|
||||
// the tag's offsetLeft after of nextTag
|
||||
const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
|
||||
|
||||
// the tag's offsetLeft before of prevTag
|
||||
const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
|
||||
|
||||
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
|
||||
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
|
||||
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
|
||||
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scroll-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
::v-deep {
|
||||
.el-scrollbar__bar {
|
||||
bottom: 0;
|
||||
}
|
||||
.el-scrollbar__wrap {
|
||||
// height: 49px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
467
src/layout/components/TagsView/index.vue
Normal file
467
src/layout/components/TagsView/index.vue
Normal file
@@ -0,0 +1,467 @@
|
||||
<template>
|
||||
<div id='tags-view-container' class='tags-view-container'>
|
||||
<scroll-pane ref='scrollPane' :watch-data='visitedTags' class='tags-view-wrapper'>
|
||||
<router-link v-for='tag in visitedTags' ref='tag' :key='tag.routeName'
|
||||
:class="isActive(tag) ? 'active' : ''"
|
||||
:to='tag.routePath' tag='span' class='tags-view-item'
|
||||
@click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
||||
@contextmenu.prevent.native='openMenu(tag, $event)'>
|
||||
<i v-if='tag.routeName == routeName' class='el-icon-s-home'></i>
|
||||
{{ tag.title }}
|
||||
<span v-if='tag.routeName == routeName' />
|
||||
<span v-else class='el-icon-close' @click.prevent.stop='closeSelectedTag(tag)' />
|
||||
</router-link>
|
||||
</scroll-pane>
|
||||
<ul v-if='selectedTag.routeName==routeName' v-show='visible' :style="{ left: left + 'px', top: top + 'px' }"
|
||||
class='contextmenu'>
|
||||
<li @click='refreshSelectedTag(selectedTag)'><i class='el-icon-refresh-right'></i> 刷新页面</li>
|
||||
<li @click='closeOthersTags(selectedTag)'><i class='el-icon-circle-close'></i> 关闭其他</li>
|
||||
<li @click='closeAllTags'><i class='el-icon-circle-close'></i> 关闭所有</li>
|
||||
</ul>
|
||||
<ul v-else v-show='visible' :style="{ left: left + 'px', top: top + 'px' }" class='contextmenu'>
|
||||
<li @click='refreshSelectedTag(selectedTag)'><i class='el-icon-refresh-right'></i> 刷新页面</li>
|
||||
<li @click='closeSelectedTag(selectedTag)'><i class='el-icon-close'></i> 关闭当前</li>
|
||||
<li @click='closeOthersTags(selectedTag)'><i class='el-icon-circle-close'></i> 关闭其他</li>
|
||||
<li @click='closeAllTags'><i class='el-icon-circle-close'></i> 关闭所有</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ScrollPane from './ScrollPane'
|
||||
import Sortable from 'sortablejs'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { ScrollPane },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
top: 0,
|
||||
left: 0,
|
||||
selectedTag: {},
|
||||
affixTags: [],
|
||||
menulists: [],
|
||||
path: '',
|
||||
routeName: '',
|
||||
title: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visitedTags() {
|
||||
// console.log("+++++++++++++++++===================++++++++++++++++++++",this.$store.state.tagsView.visitedTags)
|
||||
let arr = this.$store.state.tagsView.visitedTags
|
||||
arr.filter((item, index) => arr.indexOf(item) === index)
|
||||
//console.log("########----------",this.$store.state.user.userInfo.loginName)
|
||||
// if(this.$store.state.user.userInfo==null){
|
||||
// return arr;
|
||||
// }else{
|
||||
// if(this.$store.state.user.userInfo.roleCode[0]=='root'){
|
||||
// // arr[0]={
|
||||
// // routeName:"qualityzhilestimate",
|
||||
// // routePath: "/harmonic-boot/area/powerAssessment",
|
||||
// // title: "电能质量综合评估"
|
||||
// // };
|
||||
|
||||
// // arr[0]={
|
||||
// // routeName:"test",
|
||||
// // routePath: "/jbei/QualityOverview",
|
||||
// // title: "电能质量概览"
|
||||
// // };
|
||||
// arr[0]={
|
||||
// routeName:"dashboard",
|
||||
// routePath: "/dashboard/index",
|
||||
// title: "首页概览"
|
||||
// };
|
||||
// }
|
||||
// if(this.$store.state.user.userInfo.loginName=='njcnpqs'){
|
||||
|
||||
// arr[0]={
|
||||
// routeName:"uesrmanagement",
|
||||
// routePath: "/user-boot/user/list",
|
||||
// title: "用户管理"
|
||||
// };
|
||||
|
||||
// }else if(this.$store.state.user.userInfo.loginName=='njcnser'){
|
||||
|
||||
// arr[0]={
|
||||
// routeName:"premage",
|
||||
// routePath: "/BusinessAdministrator/TerminalManagement/FrontManagement",
|
||||
// title: "前置管理"
|
||||
// };
|
||||
|
||||
// }else if(this.$store.state.user.userInfo.loginName=='njcnsh'){
|
||||
|
||||
// arr[0]={
|
||||
// routeName:"sys-user-boot-check",
|
||||
// routePath: "/user/checkUserListview",
|
||||
// title: "审核列表"
|
||||
// };
|
||||
|
||||
// }else if(this.$store.state.user.userInfo.loginName=='njcnsj'){
|
||||
|
||||
// arr[0]={
|
||||
// routeName:"Management",
|
||||
// routePath: "/BusinessAdministrator/Audit/Operations/Management",
|
||||
// title: "审计列表管理"
|
||||
// };
|
||||
|
||||
// }else{
|
||||
|
||||
// arr[0]={
|
||||
// routeName:"qualityzhilestimate",
|
||||
// routePath: "/harmonic-boot/area/powerAssessment",
|
||||
// title: "电能质量综合评估"
|
||||
// };
|
||||
|
||||
// arr[0]={
|
||||
// routeName:"test",
|
||||
// routePath: "/jbei/QualityOverview",
|
||||
// title: "电能质量概览"
|
||||
// };
|
||||
|
||||
|
||||
// console.log("########----------",this.$store.state.user)
|
||||
// arr[0]={
|
||||
// routeName:"dashboard",
|
||||
// routePath: "/dashboard/index",
|
||||
// title: "首页概览"
|
||||
// };
|
||||
this.menulists = JSON.parse(window.sessionStorage.getItem('menus'))
|
||||
this.getmuen(this.menulists[0])
|
||||
arr[0] = {
|
||||
routeName: this.routeName,
|
||||
routePath: this.path,
|
||||
title: this.title
|
||||
}
|
||||
// }
|
||||
// }
|
||||
// console.log('++++++++++++', arr)
|
||||
return arr
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.addTags()
|
||||
//this.moveToCurrentTag();
|
||||
},
|
||||
visible(value) {
|
||||
if (value) {
|
||||
document.body.addEventListener('click', this.closeMenu)
|
||||
} else {
|
||||
document.body.removeEventListener('click', this.closeMenu)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.addTags()
|
||||
this.setSort()
|
||||
//this.filtertag()
|
||||
},
|
||||
methods: {
|
||||
getmuen(data) {
|
||||
if (data.children.length == 0) {
|
||||
this.path = data.routePath
|
||||
this.routeName = data.routeName
|
||||
this.title = data.title
|
||||
} else {
|
||||
this.getmuen(data.children[0])
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
filtertag() {
|
||||
let arr = this.$store.state.tagsView.visitedTags
|
||||
arr.filter((item, index) => arr.indexOf(item) === index)
|
||||
return arr
|
||||
},
|
||||
isActive(tag) {
|
||||
return tag.routePath === this.$route.fullPath
|
||||
},
|
||||
isAffix(tag) {
|
||||
const { affixTags } = this.$store.state.tagsView
|
||||
return affixTags.some((t) => t.routeName === tag.routeName)
|
||||
},
|
||||
addTags() {
|
||||
// alert(0)
|
||||
const { name } = this.$route
|
||||
if (name) {
|
||||
this.$store.dispatch('tagsView/addView', this.$route)
|
||||
}
|
||||
return false
|
||||
},
|
||||
//移除当前 标签
|
||||
moveToCurrentTag() {
|
||||
// alert(1)
|
||||
const tags = this.$refs.tag
|
||||
tags.splice(0, 1)
|
||||
// this.$router.push("/Statistical-analysis/indicatorClassification");
|
||||
this.$nextTick(() => {
|
||||
for (const tag of tags) {
|
||||
if (tag.to === this.$route.fullPath) {
|
||||
//if (tag.to !== "/Statistical-analysis/indicatorClassification") {
|
||||
this.$refs.scrollPane.moveToTarget(tag)
|
||||
break
|
||||
//}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
//刷新当前
|
||||
refreshSelectedTag(tag) {
|
||||
// alert(2)
|
||||
const fullPath = tag.routePath
|
||||
this.$store.commit('tagsView/DEL_CACHED_VIEW', tag.routeName)
|
||||
this.$nextTick(() => {
|
||||
this.$router.replace({
|
||||
path: '/redirect' + fullPath
|
||||
})
|
||||
})
|
||||
},
|
||||
open() {
|
||||
|
||||
},
|
||||
//关闭选择
|
||||
closeSelectedTag(tag) {
|
||||
// console.log("+++++++++++++++++++++",tag)
|
||||
if (tag.title == '算法编辑器') {
|
||||
this.$confirm('此操作将关闭删除该标签,是否已保存! 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$store.dispatch('tagsView/delTag', tag).then(({ visitedTags }) => {
|
||||
if (this.isActive(tag)) {
|
||||
this.toLastView(visitedTags, tag)
|
||||
// this.$message({
|
||||
// type: 'success',
|
||||
// message: '确认保存成功!'
|
||||
// });
|
||||
//this.$router.push("/Statistical-analysis/indicatorClassification");
|
||||
// this.$nextTick(() => {
|
||||
// this.$router.replace({
|
||||
// path: "/Statistical-analysis/indicatorClassification",
|
||||
// });
|
||||
// this.$router.push("/Statistical-analysis/indicatorClassification");
|
||||
// });
|
||||
}
|
||||
})
|
||||
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消关闭'
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$store.dispatch('tagsView/delTag', tag).then(({ visitedTags }) => {
|
||||
if (this.isActive(tag)) {
|
||||
this.toLastView(visitedTags, tag)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
//关闭其他
|
||||
closeOthersTags(tag) {
|
||||
// alert(4)
|
||||
this.$router.push(tag.routePath)
|
||||
const fullPath = tag.routePath
|
||||
this.$store.dispatch('tagsView/delOthersTags', tag)
|
||||
this.$nextTick(() => {
|
||||
this.$router.replace({
|
||||
path: '/redirect' + fullPath
|
||||
})
|
||||
})
|
||||
this.moveToCurrentTag()
|
||||
},
|
||||
//关闭所有
|
||||
closeAllTags() {
|
||||
// alert(5)
|
||||
this.$store.dispatch('tagsView/delAllTags')
|
||||
//this.$router.push("/dashboard/index");
|
||||
//this.$router.push("/jbei/QualityOverview");
|
||||
this.$nextTick(() => {
|
||||
|
||||
// this.$router.replace({
|
||||
// path: "/dashboard/index",
|
||||
// });
|
||||
//this.$router.push("/dashboard/index");
|
||||
// this.$router.replace({
|
||||
// path: "/jbei/QualityOverview",
|
||||
// });
|
||||
// this.$router.push("/jbei/QualityOverview");
|
||||
})
|
||||
// 关完还剩下的
|
||||
const { visitedTags } = this.$store.state.tagsView
|
||||
const lastTag = visitedTags[visitedTags.length - 1]
|
||||
if (lastTag) {
|
||||
if (this.$route.fullPath !== lastTag.routePath) {
|
||||
this.$router.push(lastTag.routePath)
|
||||
}
|
||||
} else {
|
||||
this.getmuen(this.menulists[0])
|
||||
this.$router.replace({ path: '/redirect' + this.path })
|
||||
//if (this.$route.name === "dashboard") {
|
||||
// this.$router.replace({ path: "/redirect" + this.$route.path });
|
||||
//} else {
|
||||
// this.$router.push("/");
|
||||
//}
|
||||
}
|
||||
},
|
||||
toLastView(visitedTags, view) {
|
||||
// alert(6)
|
||||
const latestTag = visitedTags.slice(-1)[0]
|
||||
if (latestTag) {
|
||||
this.$router.push(latestTag.routePath)
|
||||
} else {
|
||||
if (view.name === 'dashboard') {
|
||||
// this.$router.replace({ path: "/redirect" + view.routePath });
|
||||
} else {
|
||||
this.$router.push('/')
|
||||
}
|
||||
}
|
||||
},
|
||||
openMenu(tag, e) {
|
||||
const menuMinWidth = 105
|
||||
const windowWidth = document.documentElement.clientWidth
|
||||
const maxLeft = windowWidth - menuMinWidth // left boundary
|
||||
const left = e.clientX + 15 // 15: margin right
|
||||
|
||||
if (left > maxLeft) {
|
||||
this.left = maxLeft
|
||||
} else {
|
||||
this.left = left
|
||||
}
|
||||
|
||||
this.top = e.clientY
|
||||
this.visible = true
|
||||
this.selectedTag = tag
|
||||
},
|
||||
closeMenu() {
|
||||
this.visible = false
|
||||
},
|
||||
setSort() {
|
||||
const el = this.$refs.scrollPane.$el.querySelector('.el-scrollbar__view')
|
||||
this.sortable = Sortable.create(el, {
|
||||
ghostClass: 'tags-view-ghost', // Class name for the drop placeholder,
|
||||
setData: function(dataTransfer) {
|
||||
// to avoid Firefox bug
|
||||
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
|
||||
dataTransfer.setData('Text', '')
|
||||
}
|
||||
})
|
||||
//console.log("kjkjkjkjkjkjkjkjkjkjk",this.$router)
|
||||
// this.$router.push('/Statistical-analysis/indicatorClassification')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.tags-view-container {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
background: rgb(255, 255, 255);
|
||||
border-bottom: 1px solid #d8dce5;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
|
||||
|
||||
.tags-view-wrapper {
|
||||
.tags-view-item {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 26px;
|
||||
padding: 0 8px;
|
||||
margin-top: 4px;
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
line-height: 26px;
|
||||
color: $themeColor;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
border: 1px solid #d9ecff;
|
||||
border-radius: 3px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
background-color: $themeColor;
|
||||
border-color: $themeColor;
|
||||
|
||||
&::before {
|
||||
position: relative;
|
||||
//display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 2px;
|
||||
// background: #fff;
|
||||
border-radius: 50%;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.contextmenu {
|
||||
position: fixed;
|
||||
z-index: 3000;
|
||||
padding: 5px 0;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
list-style-type: none;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
|
||||
|
||||
li {
|
||||
padding: 7px 16px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
//reset element css of el-icon-close
|
||||
::v-deep .el-scrollbar__wrap {
|
||||
overflow: auto !important;
|
||||
height: 48px !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
::v-deep ::-webkit-scrollbar-thumb {
|
||||
background: $themeColor !important;
|
||||
height: 8px ! important
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: block;
|
||||
width: 8px !important;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
::v-deep .el-scrollbar__thumb {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
cursor: pointer !important;
|
||||
border-radius: inherit;
|
||||
background-color: $themeColor !important;
|
||||
-webkit-transition: .3s background-color;
|
||||
transition: .3s background-color;
|
||||
}
|
||||
</style>
|
||||
115
src/layout/components/alarmcenter/alarmcenter.vue
Normal file
115
src/layout/components/alarmcenter/alarmcenter.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
created(){
|
||||
// setInterval(()=>{
|
||||
// this.open1()
|
||||
// },60000)
|
||||
setInterval(()=>{
|
||||
this.ddd()
|
||||
},200000)
|
||||
},
|
||||
mounted(){
|
||||
|
||||
},
|
||||
methods:{
|
||||
// // 打开一个新的通知
|
||||
// openNotify(userNotification) {
|
||||
// // userNotification 中的userNotifyId是唯一的
|
||||
// const h = this.$createElement
|
||||
// let notify= this.$notify.success({
|
||||
// title: data.notification.notifyName,
|
||||
// dangerouslyUseHTMLString: true,
|
||||
// position: 'bottom-right',
|
||||
// message: h(
|
||||
// 'p',
|
||||
// {
|
||||
// // 相当于`v-bind:style`
|
||||
// style: {
|
||||
// color: 'red',
|
||||
// fontSize: '14px'
|
||||
// },
|
||||
// class: 'pointer',
|
||||
// on: {
|
||||
// click: () => {
|
||||
// this.closeNotification(
|
||||
// data.notification.data.message,
|
||||
// data.userNotifyId,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// data.notification.data.message
|
||||
// ),
|
||||
// duration: 60 * 1000
|
||||
// })
|
||||
// this.notifications[data.userNotifyId] = notify
|
||||
// },
|
||||
// //关闭单个通知
|
||||
// closeNotification(message, id){
|
||||
// this.notifications[id].close();
|
||||
// delete this.notifications[id];
|
||||
// },
|
||||
// // 关闭所有通知
|
||||
// closeAllNotification(){
|
||||
// for (let key in this.notifications) {
|
||||
// this.notifications[key].close();
|
||||
// delete this.notifications[key];
|
||||
// }
|
||||
// }
|
||||
open1() {
|
||||
const h = this.$createElement
|
||||
const hrender = h('p', null, [
|
||||
h('div', [
|
||||
h('div','终端名称:pqs600-200 '), // 传变量
|
||||
h('div','告警类型:流量告警'),
|
||||
h('div','告警发生时间:2022-05-25 12:25:54'),
|
||||
], null),
|
||||
h('button', {
|
||||
class: '样式',
|
||||
}, "处理"),
|
||||
])
|
||||
|
||||
var rq = document.getElementById('ppp')
|
||||
this.$notify({
|
||||
title: '告警通知',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: hrender,
|
||||
type: 'warning',
|
||||
// position: 'bottom-right',
|
||||
offset: 50,
|
||||
duration: 0,
|
||||
// showClose: false,
|
||||
onClick: () => {
|
||||
//this.toApproval(approvalQuery)
|
||||
this.$router.push("/BusinessAdministrator/alarManagement/AlarmInformation");
|
||||
},
|
||||
onClose: () => {
|
||||
// alert(`Notify已关闭,说明异常或已查看`)
|
||||
}
|
||||
})
|
||||
//this.yuyin()
|
||||
},
|
||||
ddd(){
|
||||
this.$notify.closeAll()
|
||||
},
|
||||
yuyin(){
|
||||
let utterThis = new window.SpeechSynthesisUtterance();
|
||||
// utterThis.text = data.toString(); //播放内容
|
||||
utterThis.text= '终端pqs9000-300空调外机启动测试发生严重告警,请尽快联系管理员处理'; //播放内容
|
||||
window.speechSynthesis.speak(utterThis);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user