Commit a168bbe2 authored by Wallen姚文辉's avatar Wallen姚文辉

一版

parent 2cc7edfa
module.exports = { module.exports = {
presets: [ presets: [
'@vue/cli-plugin-babel/preset' '@vue/cli-plugin-babel/preset'
],
plugins: [
] ]
} }
...@@ -16,4 +16,4 @@ ...@@ -16,4 +16,4 @@
"scripthost" "scripthost"
] ]
} }
} }
\ No newline at end of file
This diff is collapsed.
...@@ -8,9 +8,22 @@ ...@@ -8,9 +8,22 @@
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"@novnc/novnc": "^1.4.0",
"balm-ui": "^10.28.0",
"clipboard": "^2.0.11",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"echarts": "^5.5.0",
"file-saver": "^2.0.5",
"filesaver": "^0.0.13",
"html2canvas": "^1.4.1",
"screenfull": "^6.0.2",
"three": "^0.121.0",
"vanta": "^0.5.24",
"view-ui-plus": "^1.3.16",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-router": "^4.0.3" "vue-echarts": "^6.7.2",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.16", "@babel/core": "^7.12.16",
...@@ -18,8 +31,11 @@ ...@@ -18,8 +31,11 @@
"@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0", "@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0", "@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0", "@vue/cli-service": "~5.0.0",
"@vue/eslint-config-standard": "^6.1.0", "@vue/eslint-config-standard": "^6.1.0",
"axios": "^1.6.8",
"babel-plugin-import": "^1.13.8",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-import": "^2.25.3", "eslint-plugin-import": "^2.25.3",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
......
<template> <template>
<nav> <router-view></router-view>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<router-view/>
</template> </template>
<style> <script>
#app { </script>
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<template>
<div id="arae" style="height: 100%;">
<div id="screen" style="height: 100%;"></div>
</div>
</template>
<script>
import RFB from '@novnc/novnc/core/rfb'
export default {
name: 'Novnc',
data () {
return {
url: '',
rfb: null
}
},
methods: {
getUrl (host) {
let protocol = ''
if (window.location.protocol === 'https:') {
protocol = 'wss://'
} else {
protocol = 'ws://'
}
// 加window.location.host可以走vue.config.js的代理,ws://localhost:8081/vnc/192.168.18.57:5900
const wsUrl = `${protocol}${window.location.host}/vnc/${host}`
console.log(wsUrl)
return wsUrl
},
// vnc连接断开的回调函数
disconnectedFromServer (msg) {
console.log('断开连接', msg)
// clean是boolean指示终止是否干净。在发生意外终止或错误时 clean将设置为 false。
if (msg.detail.clean) {
// 根据 断开信息的msg.detail.clean 来判断是否可以重新连接
} else {
// 这里做不可重新连接的一些操作
console.log('连接不可用(可能需要密码)')
}
this.rfb = null
this.connectVnc()
},
// 连接成功的回调函数
// connectedToServer(event) {
// },
// 连接vnc的函数
connectVnc () {
const PASSWORD = 'ywh940509'
const rfb = new RFB(document.getElementById('screen'), this.url, {
credentials: { password: PASSWORD }
})
rfb.addEventListener('connect', () => {
// var viewer = document.getElementsByTagName('canvas')[0];
console.info('我链接了')
// console.info(navigator.clipboard.readText())
// const a=async()=>{
// const m=await navigator.clipboard.readText()
// console.info(m)
// }
// a()
// document.getElementById('arae').addEventListener('paste', async function (e) {
// console.log(await navigator.clipboard.readText())
// rfb.clipboardPasteFrom(await navigator.clipboard.readText());
// });
// document.getElementById('arae').addEventListener('keyup', function (e) {
// console.log(navigator.clipboard.readText())
// e.keyCode == 86 && rfb.clipboardPasteFrom(navigator.clipboard.readText());
// });
})
rfb.addEventListener('disconnect', this.disconnectedFromServer)
// 复制粘贴
// var clipboard = document.getElementById('clipboard');
// rfb.addEventListener('clipboard', function (e) {
// clipboard.value = e.detail.text;
// });
// rfb.addEventListener('connect', function (e) {
// var viewer = document.getElementsByTagName('canvas')[0];
// document.body.addEventListener('paste', function (e) {
// rfb.clipboardPasteFrom(e.clipboardData.getData('text'));
// });
// });
// scaleViewport指示是否应在本地扩展远程会话以使其适合其容器。禁用时,如果远程会话小于其容器,则它将居中,或者根据clipViewport它是否更大来处理。默认情况下禁用。
rfb.scaleViewport = true
// 是一个boolean指示是否每当容器改变尺寸应被发送到调整远程会话的请求。默认情况下禁用
rfb.resizeSession = true
this.rfb = rfb
}
},
mounted () {
// console.log(this.$route)
this.url = this.getUrl('172.19.153.14')
this.connectVnc()
}
}
</script>
import { createApp } from 'vue' import { createApp } from 'vue';
import App from './App.vue' import App from './App.vue';
import router from './router' import router from './router';
import axios from 'axios';
import store from '@/store/index.js';
import OrganizationView from '@/views/systemview/OrganizationView.vue';
import Role from '@/views/systemview/Role.vue';
import Menu from '@/views/systemview/Menu.vue';
import UserList from '@/views/systemview/UserList.vue';
import VncShow from '@/views/VncShow.vue';
import EmailCenter from '@/views/systemview/EmailCenter';
import TestReport from '@/views/tool/TestReport';
import Echarts from "vue-echarts";
import 'echarts';
import ECharts from 'vue-echarts';
import ViewUIPlus from 'view-ui-plus';
createApp(App).use(router).mount('#app')
const app = createApp(App).use(store)
import 'view-ui-plus/dist/styles/viewuiplus.css'
axios.defaults.withCredentials = true
axios.defaults.baseURL = '/api'
// axios.defaults.baseURL = 0 ? 'http://172.22.25.173/api' : 'http://47.57.235.86:10001'
app.config.globalProperties.$http = axios
app.component('v-chart', Echarts)
const routers = [
{
path: 'vcnshow',
name: 'vncshow',
component: VncShow
}, {
path: 'organization',
name: 'organization',
component: OrganizationView
}, {
path: 'role',
name: 'role',
component: Role
}, {
path: 'menu',
name: 'menu',
component: Menu
}, {
path: 'userlist',
name: 'userlist',
component: UserList
}, {
path: 'report',
name: 'report',
component: TestReport
}, {
path: 'emialcenter',
name: 'emialcenter',
component: EmailCenter
}
]
axios.interceptors.request.use(function (config) {
if (store.getters.gettoken != "" && config.url != "user/login") config.headers['token'] = store.getters.gettoken
return config;
});
// axios.interceptors.response.use(function (response) {
// if (response.data.code != 41000) return response;
// this.$Message.error("登录已过期")
// store.commit("settoken", '');
// router.push('/login')
// })
router.beforeEach(async (to, from, next) => {
const a = (value) => {
for (let each of value) {
if (each.router) {
const index_ = routers.findIndex(ele => { return ele.name == each.router })
if (index_ != -1) { router.addRoute('home', { 'name': each.router, 'path': each.router, component: routers[index_].component }) }
}
if (each.children) {
a(each.children)
}
}
}
const findMenu = (menu, each) => {
for (let ele in menu) {
if (ele.router == each) return true
if (ele.children) return findMenu(ele.children, each)
}
}
if (to.path == '/login') return next();
if (localStorage.getItem('token')) {
let userinfo = localStorage.getItem("userinfo")
if (!userinfo) {
result = await axios[method]("user/userdetail", 'get')
userinfo = res.data.data
} else {
userinfo = JSON.parse(userinfo)
}
const menu = userinfo.menu
if (findMenu(menu, to.name) && !router.hasRoute(to.name)) {
a(menu)
console.info(router.getRoutes())
return next(to)
}
return next()
} else {
return next('/login')
}
})
function request(method, url, data, apply, successFun = () => { }, failFun = () => { }) {
axios[method](url, method != 'get' ? data : { params: data }).then(res => {
const data = JSON.parse(JSON.stringify(res.data))
if (method != "get" && apply) apply.$Message.success(data.message);
successFun(res.data)
}).catch(error => {
console.info(error)
try {
if (error.response.data.code == 401) {
apply.$Message.error(error.response.data.message);
router.push('login')
} else {
apply && apply.$Message.error(error.response.data.message);
failFun(error.response.data)
}
}
catch {
apply && apply.$Message.error("系统处理错误");
failFun()
}
})
}
function getElements(page_id, apply, fun) {
request('get', 'user/elements', { "id": page_id }, apply, fun)
}
app.config.globalProperties.$getElements = getElements
app.config.globalProperties.$request = request
app.config.globalProperties.elePro = function (menu_id) {
return null
}
app.config.globalProperties.$routers = routers
app.provide("$http", axios);
app.provide("$request", request);
app.provide("$getElements", getElements);
app.use(ViewUIPlus).use(router).mount('#app')
import { createRouter, createWebHashHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue' import HomeView from '@/views/HomeView.vue'
import Login from '@/views/Login.vue'
import UserInfo from '@/views/systemview/UserInfo.vue'
const routes = [ const routes = [
{ path: '/', redirect: '/home' },
{ {
path: '/', path: '/:pathMatch(.*)*',
name: 'home', component: () => import('@/views/error/index.vue'),
component: HomeView hidden: true
}, },
{ {
path: '/about', name: 'home',
name: 'about', path: '/home',
// route level code-splitting component: HomeView,
// this generates a separate chunk (about.[hash].js) for this route children: [{
// which is lazy-loaded when the route is visited. path: 'userinfo',
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue') name: 'userinfo',
component: UserInfo,
},]
}, {
path: '/login',
name: '/login',
component: Login,
} }
] ]
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHistory(),
routes routes
}) })
export default router export default router
import { createStore } from 'vuex'
export default new createStore({
state: {
username: '',
token: '',
id: null,
router: '',
userinfo: ''
},
mutations: {
setusername(state, value) {
state.username = value
},
settoken(state, value) {
state.token = value
},
setid(state, value) {
state.id = value
},
setRouter(state, value) {
state.router = value
},
setUsreInfo(state, value) {
state.userinfo = value
}
},
getters: {
getUserInfo: state => {return state.userinfo},
gettoken(state) {
if (state.token == "" || state.token) {
state.token = localStorage.getItem('token')
}
return state.token
},
getId: state => state.id,
getRouter: state => {return state.router}
},
})
const render=(meun_id)=>{
return null
}
export default elePro
\ No newline at end of file
<style>
.layout {
border: 1px solid #d7dde4;
background: #f5f7f9;
position: relative;
border-radius: 4px;
overflow: hidden;
}
.layout-logo {
width: 100px;
height: 30px;
background: #5b6270;
border-radius: 3px;
float: left;
position: relative;
top: 15px;
left: 20px;
}
.layout-nav {
/* width: 200px; */
margin: 0 auto;
/* margin-right: 20px; */
/* text-align: left; */
display: flex;
}
</style>
<template> <template>
<div class="home"> <div class="layout">
<img alt="Vue logo" src="../assets/logo.png"> <Layout>
<HelloWorld msg="Welcome to Your Vue.js App"/> <Header style="box-shadow: 0 3px 3px rgba(0,0,0,.1);">
</div> <Menu mode="horizontal" theme="dark" active-name="1">
</template> <Row>
<Col :lg="12" span="6">
<Poptip trigger="hover" title="个人信息" placement="right-start">
<Space size="large">
<Avatar style="background: #7265e6">{{ userinfo.name && userinfo.name.substring(0, 1) }}
</Avatar>
</Space>
<template #content>
<List size="small" footer="Footer">
<ListItem>用户名:{{ userinfo.name }}</ListItem>
<ListItem>组:{{ userinfo.organization }}</ListItem>
<ListItem>角色:{{ userinfo.role_name }}</ListItem>
<ListItem>邮箱:{{ userinfo.email_address }}</ListItem>
<template #footer>
<Button type="primary"
@click="$router.push({ name: 'userinfo', query: { id: userinfo.id } })" size="small">修改信息</Button>
<Button type="primary"
@click="loginout" style="margin-left: 5px;" size="small">退出登录</Button>
</template>
</List>
</template>
</Poptip>
</Col>
<Col :lg="0" span="18">
<div class="layout-nav">
<MenuItem name="1" style="margin-right: auto;">
<Icon type="ios-navigate"></Icon>
</MenuItem>
<MenuItem name="2" style="margin-right: auto;">
<Icon type="ios-keypad"></Icon>
</MenuItem>
<MenuItem name="3" style="margin-right: auto;">
<Icon type="ios-analytics"></Icon>
</MenuItem>
<MenuItem name="4" style="margin-right: auto;">
<Icon type="ios-paper"></Icon>
</MenuItem>
</div>
</Col>
</Row>
</Menu>
</Header>
<Layout>
<Sider breakpoint="lg" collapsible :collapsed-width="0" v-model="isCollapsed" hide-trigger
:style="{ background: '#fff' }" style="box-shadow: 5px 0px 0px rgba(0,0,0,.1);z-index: 0;">
<Menu active-name="1-2" theme="light" width="auto" :open-names="['1']">
<Submenu v-for="each in menu" :key="each.id" :name="each.id">
<template #title>
<Icon :type="each.icon"></Icon>
{{ each.name }}
</template>
<MenuItem v-for="child in each.children" :key="child.id" :name="child.id"
:to="{ name: child.router }">
{{
child.name }}
</MenuItem>
</Submenu>
</Menu>
</Sider>
<Layout :style="{ padding: '0 5px 5px' }">
<Content :style="{ padding: '24px', background: '#fff', height: screenHeigh }"
style="overflow-y:auto">
<router-view :isCollapsed="isCollapsed"></router-view>
</Content>
</Layout>
</Layout>
</Layout>
</div>
</template>
<script> <script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default { export default {
name: 'HomeView', data() {
components: { return {
HelloWorld isCollapsed: null,
} screenHeigh: null,
myrouter: [],
menu: [],
userinfo: {}
};
},
computed: {
menuitemClasses: function () {
return [
'menu-item',
this.isCollapsed ? 'collapsed-menu' : ''
]
},
},
methods: {
getinfo() {
this.$request('get', 'user/userdetail', null, this, (data) => { this.menu = data.data.menu; this.userinfo = data.data; localStorage.setItem('userinfo', JSON.stringify(data.data)); })
},
loginout(){
this.$request('post','user/logout',null,this,(data)=>{
localStorage.removeItem('token'),
this.$router.push('login')
})
}
},
watch: {
isCollapsed(value1) {
this.screenHeigh = (!value1) ? window.innerHeight - 102 + 'px' : window.innerHeight - 72 + 'px'
},
menu(value) {
const a = (value) => {
for (let each of value) {
if (each.router) {
const index_ = this.$routers.findIndex(ele => { return ele.name == each.router })
if (index_ != -1) { this.$router.addRoute('home', { 'name': each.router, 'path': each.router, component: this.$routers[index_].component }) }
}
if (each.children) {
a(each.children)
}
}
}
a(value)
}
},
mounted() {
this.isCollapsed = window.innerWidth > 992 ? false : true
this.getinfo()
}
} }
</script> </script>
<template>
<div class="box" ref="vantaRef" style="width: 100%; height: 100vh">
<Row>
<Col span="24" :lg="{span:8,offset:8}">
<div class="card">
<div class="login">
<Login @on-submit="handleSubmit">
<UserName name="name" :value="User.name" />
<Password name="password" :value="User.password" />
<Submit />
</Login>
</div>
</div>
</Col>
</Row>
</div>
</template>
<script>
import * as THREE from 'three'//导入样式
import BIRDS from 'vanta/src/vanta.birds'//导入动态样式逻辑
export default {
data() {
return {
User: {
name: null,
password: null
}
}
},
methods: {
handleSubmit(valid, { name, password }) {
if (valid) {
this.$request("post", "user/login", { name, password }, this, (data) => {
this.$store.commit("setusername", data.data.name);
this.$store.commit("settoken", data.data.token);
this.$store.commit("setid", data.data.id);
localStorage.setItem("token", data.data.token);
localStorage.setItem("name", data.data.name);
localStorage.setItem("password", data.data.password);
this.$request('get', 'user/userdetail', null, this, (data) => {localStorage.setItem('userinfo',JSON.stringify(data.data));})
this.$router.push("/home");
})
}
}
},
mounted() {
this.vantaEffect = BIRDS({
el: this.$refs.vantaRef,
THREE: THREE
})
VANTA.BIRDS({
el: this.$refs.vantaRef,
mouseControls: true,
touchControls: true,
gyroControls: false,
minHeight: 200.0,
minWidth: 200.0,
scale: 1.0,
color1: 14381274,
color2: 16443110,
});
},
created() {
this.User.name = localStorage.getItem("name") || null;
this.User.password = localStorage.getItem("password") || null
}
}
</script>
<style>
.card{
height: 300px;
background: rgba(103, 176, 185, 0.7);
transform: translateY(90%);
-webkit-backdrop-filter: blur(5px);
backdrop-filter: blur(5px);
border-radius: 30px 5px 15px 5px;
text-align: center;
}
.login {
max-width: 400px;
margin: 0 auto !important;
transform: translateY(40%);
}
</style>
<template>
<div style="text-align: right;">
<Icon type="md-qr-scanner" color="#5cadff" size=30 @click="FullScreen" />
</div>
<div style="height: 100%;" id="Novnc">
<Novnc></Novnc>
</div>
</template>
<script>
import Novnc from '@/components/VncConnect.vue'
import { Icon } from 'view-ui-plus'
import screenfull from 'screenfull'
export default {
components: {
Novnc
},
data () {
return {
modal: false
}
},
methods: {
FullScreen () {
const element = document.getElementById('Novnc')
screenfull.request(element)
},
fullscreenElement () {
const fullscreenEle = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement
return fullscreenEle
}
}
}
</script>
<template>
<Exception type="404" />
</template>
<script>
export default {
}
</script>
\ No newline at end of file
<template>
<PageHeader :title="title">
<template #action>
<Button v-if="elements.indexOf('5-1') != -1" name="新增邮箱" type="primary"
@click="modlShow = true">新增邮箱</Button>
</template>
</PageHeader>
<div style="margin-top: 8px;">
<Table row-key="id" :columns="columns" :data="emails">
<template #name="{ row }">
<strong>{{ row.name }}</strong>
</template>
<template v-if="elements.indexOf('5-2') != -1" name="编辑列" #action="{ row }">
<Button type="primary" size="small" style="margin-right: 5px"
@click="addinfo = JSON.parse(JSON.stringify(row)); modlShow = true">编辑</Button>
<Button type="error" size="small" @click="delEmail(row.id)">删除</Button>
</template>
</Table>
</div>
<Space wrap>
<Modal :title="addinfo.id ? '编辑邮箱' : '添加邮箱'" v-model="modlShow" class-name="vertical-center-modal">
<Form ref="addForm" :model="addinfo" :rules="ruleValidate" :label-width="80">
<FormItem label="邮箱持有者" prop="name">
<Input v-model="addinfo.name" placeholder="请输入名字"></Input>
</FormItem>
<FormItem label="邮箱地址" prop="address">
<Input v-model="addinfo.address" placeholder="请输入邮箱地址"></Input>
</FormItem>
</Form>
<template #footer>
<Button @click="closeShow()">取消</Button>
<Button type="primary" @click="addinfo.id ? editEmail() : addEmail()">确认</Button>
</template>
</Modal>
</Space>
</template>
<script>
export default {
props: ['isCollapsed',],
data() {
return {
page_id: 20,
title: "邮箱中心",
modlShow: false,
addinfo: {
name: null,
address: null
},
emails: [],
ruleValidate: {
name: [
{ required: true, message: '持有者不能为空', trigger: 'blur' }
],
address: [
{ required: true, message: '邮箱地址不能为空', trigger: 'blur' },
{ type: 'email', message: '邮箱格式错误', trigger: 'blur' }
]
},
columns: [
{
title: '持有人',
key: 'name',
align: 'center'
}, {
title: '邮箱地址',
key: 'address',
align: 'center'
}
],
elements: []
}
},
methods: {
closeShow() {
this.addinfo = {
name: null,
address: null
},
this.modlShow = false;
},
async addEmail() {
var next_ = await this.$refs["addForm"].validate((valid) => {
if (!valid) {
this.$Message.error('请完善信息')
};
})
if (!next_) return
this.$request("post", "/tool/testport/addemailuser", this.addinfo, this, () => { this.getEmail(); this.closeShow() })
},
getEmail() {
this.$request("get", "/tool/testport/emailuserlist", null, this, (data) => { this.emails = data.data })
},
async editEmail() {
var next_ = await this.$refs["addForm"].validate((valid) => {
if (!valid) {
this.$Message.error('请完善信息')
};
})
if (!next_) return
this.$request("post", "/tool/testport/editemailuser", this.addinfo, this, () => { this.getEmail(); this.closeShow() })
},
delEmail(id_) {
this.$request("delete", "/tool/testport/deleteemailuser/" + id_, null, this, () => { this.getEmail(); })
},
},
watch: {
elements(value) {
if (value.indexOf('5-2') != -1 && this.columns.findIndex(each => { return each.title == '编辑' }) == -1) {
this.columns.push({
title: '编辑',
slot: 'action',
width: 200,
align: 'center'
})
} else {
const index = this.columns.findIndex(ele => { return ele.title == 'Action' })
index != -1 && this.columns.splice(index, 1)
}
}
},
created() {
this.$getElements(this.page_id, this, (data) => this.elements = data.data)
this.getEmail();
}
};
</script>
<style>
.vertical-center-modal {
display: flex;
align-items: center;
justify-content: center;
}
.vertical-center-modal .ivu-modal {
top: 0;
}
</style>
\ No newline at end of file
This diff is collapsed.
<template>
<PageHeader :title="title">
<template #action>
<Button v-if="elements.indexOf('1-1') != -1" name="添加顶级组织" type="primary" @click="modlShow = true">添加顶级组织</Button>
</template>
</PageHeader>
<div style="margin-top: 8px;">
<Table highlight border row-key="id" :columns="columns" :data="orgData">
<template #name="{ row }">
<strong>{{ row.name }}</strong>
</template>
<template v-if="elements.indexOf('1-2') != -1" name="编辑列" #action="{ row }">
<Button v-if="elements.indexOf('1-3') != -1" name="新增子组织" type="primary" size="small" style="margin-right: 5px"
@click="addinfo.parent_id = row.id; addinfo.parent_name = row.name; modlShow = true">新增子组织</Button>
<Button v-if="elements.indexOf('1-4') != -1" name="删除" type="error" size="small" @click="delOrg(row.id)">删除</Button>
</template>
</Table>
</div>
<Space wrap>
<Modal title="添加组织" v-model="modlShow" class-name="vertical-center-modal" @on-cancel="closeShow()" >
<Form ref="addForm" :model="addinfo" :rules="ruleValidate" :label-width="80">
<FormItem label="父组织" prop="parent_name">
<Input v-model="addinfo.parent_name" disabled></Input>
</FormItem>
<FormItem label="组织名" prop="name">
<Input v-model="addinfo.name" placeholder="请输入组织名"></Input>
</FormItem>
</Form>
<template #footer>
<Button @click="closeShow()">取消</Button>
<Button type="primary" @click="addOrg()">确认</Button>
</template>
</Modal>
</Space>
</template>
<script>
export default {
props: ['isCollapsed',],
data() {
return {
page_id:14,
title: "组织管理",
modlShow: false,
addinfo: {
parent_id: null,
parent_name: null,
name: null
},
ruleValidate: {
name: [
{ required: true, message: '组织名不能为空', trigger: 'blur' }
],
},
elements: [],
columns: [
{
title: '组织名',
key: 'name',
tree: true
}
],
orgData: [
]
}
},
methods: {
closeShow() {
this.modlShow = false;
this.addinfo = {
parent_id: 0,
parent_name: null,
name: null,
}
},
async addOrg() {
var next_ = await this.$refs["addForm"].validate((valid) => {
if (!valid) {
this.$Message.error('请完善信息')
};
})
if (!next_) return
this.$request("post", "/identity/add_organization", this.addinfo, this, () => { this.getOrg(); this.closeShow() })
},
getOrg() {
this.$request("get","/identity/organization",null,this,(data)=>{this.orgData=data.data})
},
async delOrg(id_) {
this.$request("delete","/identity/delete_organization/" + id_,null,this,()=>{this.getOrg();})
},
},
watch: {
elements(value) {
console.info(value)
if (this.elements.indexOf("1-2") != -1) {
this.columns.push({
title: '编辑',
slot: 'action',
width: 200,
align: 'center'
})
} else {
const index = this.columns.findIndex(ele => { return ele.title == 'Action' })
index != -1 && this.columns.splice(index, 1)
}
}
},
created() {
this.$getElements(this.page_id,this,(data)=>this.elements=data.data)
this.getOrg()
}
};
</script>
<style>
.vertical-center-modal {
display: flex;
align-items: center;
justify-content: center;
}
.vertical-center-modal .ivu-modal {
top: 0;
}
</style>
\ No newline at end of file
<template>
<PageHeader :title="title">
<template #action>
<Button v-if="elements.indexOf('3-1') != -1" name="新增角色" type="primary"
@click="modlShow = true">新增角色</Button>
</template>
</PageHeader>
<div style="margin-top: 8px;">
<Row class="code-row-bg">
<Col :lg="10" span="24">
<Table row-key="id" :columns="columns" :data="allRole"
@on-cell-click="(row, column, data, event) => { column.key == 'name' && getRolePermissions(row.id) }">
<template #name="{ row }">
<strong>{{ row.name }}</strong>
</template>
<template v-if="elements.indexOf('3-2') != -1" name="编辑列" #action="{ row }">
<Button size="small" type="error" shape="circle" icon="md-trash" @click="delRole(row.id)"></Button>
</template>
</Table>
</Col>
<Col :lg="4" span="0">
</Col>
<Col :lg="10" span="0">
<Card v-if="choiceId" style="height: 600px;">
<Form >
<FormItem>
<Table :show-header="false" row-key="id" :columns="menu_columns"
@on-selection-change="(a) => { select_menu = a }" :data="choicePermissions">
<template #name="{ row }">
<strong>{{ row.name }}</strong>
</template>
<template #elements="{ row }">
<Tag v-for="item in row.elements" :key="item.id" :name="item.id"
:checked="item._checked" checkable
@on-change="(chec, name) => { elechoice(row, chec, name) }" color="primary"
style="margin-right: 5px">
{{ item.name }}</Tag>
</template>
</Table>
</FormItem>
<FormItem style="text-align: right;">
<Button type="primary" @click="updatePermissions(choiceId)">确认</Button>
</FormItem>
</Form>
</Card>
</Col>
</Row>
</div>
<Space wrap>
<Modal title="添加角色" v-model="modlShow" class-name="vertical-center-modal">
<Form ref="addForm" :model="addinfo" :rules="ruleValidate" :label-width="80">
<FormItem label="角色名" prop="name">
<Input v-model="addinfo.name" placeholder="请输入角色名"></Input>
</FormItem>
</Form>
<template #footer>
<Button @click="closeShow()">取消</Button>
<Button type="primary" @click="addRole()">确认</Button>
</template>
</Modal>
</Space>
</template>
<script>
export default {
props: ['isCollapsed',],
data() {
return {
page_id:16,
title: "角色管理",
modlShow: false,
addinfo: {
role_name: null
},
allRole: [],
choiceId: null,
choicePermissions: [],
select_menu: [],
select_element: [],
allPermissions: [],
ruleValidate: {
name: [
{ required: true, message: '角色名不能为空', trigger: 'blur' }
],
},
columns: [
{
title: '角色',
key: 'name',
align: 'center'
}
],
menu_columns: [
{
key: "_checked",
type: 'selection'
},
{
title: '菜单名',
key: 'name',
tree: true
}, {
title: '元素',
slot: 'elements',
align: 'center'
}
],
elements:[]
}
},
methods: {
closeShow() {
this.addinfo = {
role_name: null
},
this.modlShow = false;
},
elechoice(row, chec, name) {
const index = row.elements.findIndex(i => { return i.id == name })
const id = row.elements[index].id
const index2 = this.select_element.findIndex(i => { return i.id == id })
if (index2 == -1 && chec)
this.select_element.push({ type: 1, id })
if (index2 != -1 && !chec)
this.select_element.splice(index2, 1)
},
async addRole() {
var next_ = await this.$refs["addForm"].validate((valid) => {
if (!valid) {
this.$Message.error('请完善信息')
};
})
if (!next_) return
this.$request("post", "/identity/add_role", this.addinfo, this, () => { this.getRole(); this.closeShow() })
},
getRole() {
this.$request("get", "/identity/role_list", null, this, (data) => { this.allRole = data.data })
},
async delRole(id_) {
this.$request("delete", "/identity/delete_role/" + id_, null, this, () => { this.getRole(); })
},
getMenu() {
this.$request("get", "/identity/meun_list", null, this, (data) => { this.allPermissions = data.data })
},
getRolePermissions(id_) {
if (this.elements.indexOf("3-3")==-1) return
this.$request("get", "/identity/get_permissions/" + id_, null, this, (data) => { a(data.data) })
this.select_element = []
const a = (Permissions) => {
const m = (elements) => {
elements.forEach(element => {
const index1 = Permissions.findIndex(e => { return (e.p_id == element.id && e.type == 0) })
element._checked = index1 == -1 ? false : true
index1 != -1 && this.select_menu.push({ type: 0, id: element.id })
if (element.elements) {
element.elements.forEach(each => {
const index2 = Permissions.findIndex(e => { return e.p_id == each.id && e.type == 1 })
each._checked = index2 == -1 ? false : true
index2 != -1 && this.select_element.push({ type: 1, id: each.id })
})
}
element.children && m(element.children)
})
}
this.choicePermissions = JSON.parse(JSON.stringify(this.allPermissions));
m(this.choicePermissions);
console.info(this.choicePermissions)
this.choiceId = id_
}
},
updatePermissions(id_) {
this.select_menu.forEach(ele => {
if (this.select_element.findIndex(i => { return i.id == ele.id && i.type == 0 }) == -1)
this.select_element.push({ type: 0, id: ele.id })
})
this.$request("post", "/identity/update_permissions/" + id_, this.select_element, this, () => { this.getRolePermissions(this.choiceId) })
}
},
watch: {
// choiceId(value) {
// value && this.getRolePermissions(value)
// }
// 编辑权限2,删除权限3,操作栏4
elements(value) {
if (value.indexOf('3-2') != -1 && this.columns.findIndex(each=>{return each.title=='编辑'})==-1) {
this.columns.push({
title: '编辑',
slot: 'action',
width: 200,
align: 'center'
})
} else {
const index = this.columns.findIndex(ele => { return ele.title == 'Action' })
index != -1 && this.columns.splice(index, 1)
}
}
},
created() {
this.$getElements(this.page_id,this,(data)=>this.elements=data.data)
this.getMenu();
this.getRole();
}
};
</script>
<style>
.vertical-center-modal {
display: flex;
align-items: center;
justify-content: center;
}
.vertical-center-modal .ivu-modal {
top: 0;
}
</style>
\ No newline at end of file
<template>
<PageHeader :title="title">
</PageHeader>
<Form ref="userValidate" :model="userinfo" :rules="userValidate" :label-width="80" style="margin-top: 20px;">
<FormItem label="用户名" prop="name">
<Input v-model="userinfo.name" placeholder="请输入用户名" style="max-width: 600px;"></Input>
</FormItem>
<!-- v-if="$route.query.id == $store.state.id && $route.query.id" -->
<FormItem v-if="elements.indexOf('4-3')==-1 && $route.query.id == $store.state.id && $route.query.id" label="原密码" prop="oldpassword">
<Input v-model="userinfo.oldpassword" placeholder="请确认原密码" type="password" password
style="max-width: 600px;"></Input>
</FormItem>
<FormItem label="密码" prop="password">
<Input v-model="userinfo.password" placeholder="请输入密码" type="password" password style="max-width: 600px;"></Input>
</FormItem>
<FormItem label="确认密码" prop="secondpassword">
<Input v-model="userinfo.secondpassword" placeholder="请再次输入密码" type="password" password
style="max-width: 600px;"></Input>
</FormItem>
<FormItem v-if="elements.indexOf('4-3')!=-1" name="组织更改" label="组织">
<Select filterable v-model="userinfo.organization_id" style="max-width: 300px;">
<Option v-for="item in organization" :value="item.id">{{ item.path }}</Option>
</Select>
</FormItem>
<FormItem v-if="elements.indexOf('4-3')!=-1" name="角色更改" label="角色" prop="role_id">
<Select filterable v-model="userinfo.role_id" style="max-width: 300px;">
<Option v-for="item in role" :value="item.id">{{ item.name }}</Option>
</Select>
</FormItem>
<FormItem label="jira账户" prop="jiar_account">
<Input v-model="userinfo.jira_account" placeholder="请输入jira账户" style="max-width: 600px;"></Input>
</FormItem>
<FormItem label="jira密码" prop="jira_password">
<Input v-model="userinfo.jira_password" placeholder="请输入jira账户密码" style="max-width: 600px;"
type="password" password ></Input>
</FormItem>
<FormItem label="email" prop="email">
<Input v-model="userinfo.email_address" placeholder="请输入邮箱地址" style="max-width: 600px;"></Input>
</FormItem>
<FormItem style="text-align: left;">
<Button type="primary" @click="submit">提交</Button>
<Button style="margin-left: 8px" @click="cancle">取消</Button>
</FormItem>
</Form>
</template>
<script>
export default {
data() {
const validatePass = (rule, value, callback) => {
if (value === '' && !this.$route.query.id) {
callback(new Error('请输入密码'));
} else {
// && this.$route.query.id == this.$store.state.id && this.$route.query.id
if (this.userinfo.oldpassword == '' && this.$route.query.id == this.$store.state.id && this.$route.query.id) {
this.$refs.userValidate.validateField('oldpassword')
}
if (this.userinfo.secondpassword !== '') {
this.$refs.userValidate.validateField('secondpassword');
}
callback();
}
};
const validatePassCheck = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else if (value !== this.userinfo.password) {
callback(new Error('两次密码不一致!'));
} else {
callback();
}
};
// && this.$route.query.id && this.$route.query.id == this.$store.state.id
const validateOldPassCheck = (rule, value, callback) => {
if (value === '' && this.userinfo.password && this.$route.query.id == this.$store.state.id && this.$route.query.id) {
callback(new Error('请输入旧密码'));
} else callback()
};
const validateJiraPassCheck = (rule, value, callback) => {
if (value === '' && this.userinfo.jiar_account) {
callback(new Error('请输入jira密码'));
} else callback()
};
return {
page_id:17,
elements:[],
userinfo: {
name: '',
password: '',
secondpassword: '',
oldpassword: '',
organization_id: null,
role_id: 0,
jiar_account: '',
jiar_password: '',
email_adress:''
},
userValidate: {
name: [
{ required: true, message: '用户名不能为空', trigger: 'blur' }
],
oldpassword: [
{ validator: validateOldPassCheck, trigger: 'blur' }
],
password: [
{ validator: validatePass, trigger: 'blur' ,required: this.$route.query.id ? false : true}
],
secondpassword: [
{ validator: validatePassCheck, trigger: 'blur' ,required: this.$route.query.id ? false : true}
],
role_id: [
{ required: true, message: '请选择角色', trigger: 'change',type:'number' }
],
email: [
{ type: 'email', message: '邮箱格式错误', trigger: 'blur' }
],
jiar_password: [
{ validator: validateJiraPassCheck, trigger: 'blur' }
]
},
role: [],
organization: [],
}
},
computed: {
title() {
return this.$route.query.id ? "编辑信息" : "新增用户"
}
},
methods: {
async submit(){
var next_ = await this.$refs["userValidate"].validate((valid) => {
if (!valid) {
this.$Message.error('请完善信息')
};
})
if (!next_) return
'id' in this.userinfo?this.updateUser():this.addUser()
},
cancle(){
setTimeout(() => {
this.$router.back()
}, 500);
},
getOrg() {
this.$request("get", "/identity/organization_list", null, this, (data) => { console.info(data), this.organization = data.data })
},
getRole() {
this.$request("get", "/identity/role_list", null, this, (data) => { this.role = data.data })
},
getUser(id) {
this.$request("get", "/user/getuser/"+id, null, this, (data) => { this.userinfo = data.data })
},
addUser() {
console.info(this.userinfo)
this.$request("post", "/user/adduser",this.userinfo, this,()=>{this.cancle()})
},
updateUser() {
this.$request("post", "/user/updateuser", this.userinfo, this,()=>{this.cancle()})
}
},
created() {
this.getOrg();
this.getRole();
this.$route.query.id && this.getUser(this.$route.query.id);
this.$getElements(this.page_id,this,(data)=>this.elements=data.data)
}
}
</script>
<template>
<PageHeader :title="title">
<template #action>
<Button v-if="elements.indexOf('4-1') != -1" name="添加用户" type="primary"
@click="$router.push('userinfo')">添加用户</Button>
</template>
<template #content>
<Space>
<Input v-model="searchinfo.name" placeholder="请输入用户名" style="width: 260px"
@on-contextmenu="(row) => { choice_id = row.id }" />
<Select v-model="searchinfo.organizations" multiple style="width:260px">
<Option v-for="item in organization" :value="item.id" :key="item.id">{{ item.path }}</Option>
</Select>
<Select v-model="searchinfo.roles" multiple style="width:260px">
<Option v-for="item in role" :value="item.id" :key="item.id">{{ item.name }}</Option>
</Select>
<Button type="primary" @click="getusers">搜索</Button>
</Space>
</template>
</PageHeader>
<div style="margin-top: 8px;">
<Table row-key="id" :columns="columns" :data="users" show-context-menu
@on-contextmenu="choiceRowMethod">
<template #date="{ row, index }">
<div>{{ row.create_date }}</div>
</template>
<template v-if="elements.indexOf('4-2') != -1" name="禁用" #action="{ row }">
<Switch :model-value="row.disable" @on-change="(status) => { changeDisable(row, status) }">
<template #open>
<span></span>
</template>
<template #close>
<span></span>
</template>
</Switch>
</template>
<template #contextMenu>
<DropdownItem @click="goEdit()">编辑</DropdownItem>
</template>
</Table>
<Page :total="totals" :page-size="searchinfo.page_size" :model-value="searchinfo.page_num" show-total
style="position: fixed;bottom: 10px;" />
</div>
</template>
<script>
export default {
props: ['isCollapsed',],
data() {
return {
page_id:17,
title: "用户管理",
choiceRow: null,
columns: [
{
title: '姓名',
key: 'name',
align: 'center'
}, {
title: '角色',
key: 'role_name',
align: 'center'
}, {
title: '组',
key: 'path',
align: 'center'
},
{
title: '创建时间',
slot: 'date',
align: 'center'
}
],
users: [
],
totals: 0,
organization: [],
role: [],
searchinfo: {
name: null,
roles: [],
organizations: [],
page_size: 10,
page_num: 1
},
choice_id: null,
elements: []
}
},
methods: {
choiceRowMethod(row){
if (this.elements.indexOf("4-3")==-1) return
this.choiceRow = row
},
goEdit(){
if (!this.choiceRow) return this.$Message.error("权限不足")
this.$router.push({ name: 'userinfo', query: { id: this.choiceRow.id } })
},
getusers() {
this.$request("get", '/user/user_list', this.searchinfo, this, (data) => { this.users = data.data.rows || []; this.totals = data.data.total || 0; console.info(this.users) })
},
changeDisable(row, status) {
this.$request("post", "/user/updateuser", { id: row.id, disable: status ? 1 : 0 }, this)
},
getOrg() {
this.$request("get", "/identity/organization_list", null, this, (data) => { this.organization = data.data})
},
getRole() {
this.$request("get", "/identity/role_list", null, this, (data) => { this.role = data.data ;console.info(this.role)})
},
jsonPath(target, key, key_value, get_value_key) {
const index = target.findindex(item => { item[key] == key_value })
if (index == -1) {
return null
} return target[index][get_value_key]
}
},
watch: {
elements(value) {
if (value.indexOf('4-2') != -1 && this.columns.findIndex(each => { return each.title == '禁用' }) == -1) {
this.columns.push({
title: '禁用',
slot: 'action',
align: 'center'
}
)
} else {
const index = this.columns.findIndex(ele => { return ele.title == 'Action' })
index != -1 && this.columns.splice(index, 1)
}
}
},
created() {
this.$getElements(this.page_id,this,(data)=>this.elements=data.data)
this.getOrg();
this.getRole();
this.getusers();
}
};
</script>
<style>
.vertical-center-modal {
display: flex;
align-items: center;
justify-content: center;
}
.vertical-center-modal .ivu-modal {
top: 0;
}
</style>
\ No newline at end of file
This diff is collapsed.
const { defineConfig } = require('@vue/cli-service') const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({ module.exports = defineConfig({
transpileDependencies: true transpileDependencies: true,
lintOnSave: false,
runtimeCompiler: true,
configureWebpack: {
resolve: {
alias: {
'balm-ui-plus': 'balm-ui/dist/balm-ui-plus.js',
'balm-ui-css': 'balm-ui/dist/balm-ui.css'
}
}
},
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'/api': ''
}
}
}
}
}) })
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