增加用户授权、公司授权 以及优化部门、角色、用户接口

This commit is contained in:
龙运模 2024-07-08 19:58:03 +08:00
parent c2fe2415a4
commit e5ebcbcdbe
25 changed files with 2243 additions and 380 deletions

View File

@ -97,6 +97,49 @@ export default {
post: async function (params) {
return await http.post(this.url, params);
},
},
roleAuth: {
url: `${config.API_URL}/auth.role.auth`,
name: "角色授权",
post: async function (params) {
return await http.post(this.url, params);
}
},
roleMenu:{
url: `${config.API_URL}/auth.role.permission.checked`,
name: "菜单权限",
post: async function (params) {
return await http.post(this.url, params);
}
},
roleCode: {
url: `${config.API_URL}/authorize.role.codes`,
name: "角色对应CODE列表",
post: async function (params) {
return await http.post(this.url, params);
}
},
roleUser:{
url: `${config.API_URL}/roles.users`,
name: "角色成员列表",
post: async function (params) {
return await http.post(this.url, params);
}
},
roleUserAdd:{
url: `${config.API_URL}/roles.add.users`,
name: "添加角色成员",
post: async function (params) {
return await http.post(this.url, params);
}
},
roleUserDel:{
url: `${config.API_URL}/roles.removed.users`,
name: "删除角色成员",
post: async function (params) {
return await http.post(this.url, params);
}
}
},
company:{
@ -114,6 +157,13 @@ export default {
return await http.post(this.url, params);
},
},
update:{
url: `${config.API_URL}/organization.update`,
name: "公司更新",
post: async function (params) {
return await http.post(this.url, params);
},
},
info: {
url: `${config.API_URL}/organization.info`,
name: "公司详情",
@ -149,6 +199,20 @@ export default {
return await http.post(this.url, params);
},
},
permission:{
url: `${config.API_URL}/auth.company.permission.checked`,
name: "公司权限列表",
post: async function (params) {
return await http.post(this.url,params);
}
},
moduleAdd:{
url: `${config.API_URL}/auth.company.module.add`,
name: "公司权限分配",
post: async function (params) {
return await http.post(this.url,params);
}
}
},
dept: {
list: {
@ -230,6 +294,28 @@ export default {
return await http.post(this.url, params);
},
},
allocatRole: {
url: `${config.API_URL}/auth.user.role`,
name: "用户分配角色",
post: async function (params) {
return await http.post(this.url, params);
}
},
userPermission:{
url: `${config.API_URL}/auth.user.permission.checked`,
name: "查看用户权限",
post: async function (params) {
return await http.post(this.url, params);
}
},
userCompanyList:{
url: `${config.API_URL}/company.user.list`,
name: "查看公司用户列表",
get: async function (params) {
return await http.post(this.url, params);
}
},
generateRegistration:{
url: `${config.API_URL}/generate.registration.challenge`,
name: "passKey 创建",

View File

@ -1,5 +1,5 @@
<template>
<svg t="1720158991173" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3275" width="200" height="200"><path d="M694.101333 963.299556H329.728a163.214222 163.214222 0 0 1-117.077333-50.062223 173.340444 173.340444 0 0 1-48.526223-120.604444V222.549333a35.043556 35.043556 0 0 1 9.671112-24.177777 33.109333 33.109333 0 0 1 23.438222-9.955556H826.595556a32.312889 32.312889 0 0 1 23.438222 9.955556 34.190222 34.190222 0 0 1 9.671111 24.177777v570.026667c0 45.226667-17.408 88.632889-48.469333 120.604444a163.214222 163.214222 0 0 1-117.134223 50.062223zM230.4 256.739556v535.893333c0 27.136 10.467556 53.191111 29.127111 72.362667 18.659556 19.228444 43.918222 29.980444 70.257778 29.980444h364.373333c26.396444 0 51.655111-10.808889 70.314667-29.980444 18.602667-19.171556 29.070222-45.226667 29.070222-72.419556v-535.893333H230.4z" p-id="3276"></path><path d="M888.490667 256.739556H135.566222a32.654222 32.654222 0 0 1-23.438222-10.012445 34.702222 34.702222 0 0 1 0-48.298667 32.654222 32.654222 0 0 1 23.438222-9.955555h752.924445c8.817778 0 17.237333 3.584 23.438222 9.955555a34.702222 34.702222 0 0 1 0 48.298667 32.654222 32.654222 0 0 1-23.438222 10.012445z" p-id="3277"></path><path d="M640.739556 244.736a32.654222 32.654222 0 0 1-23.438223-10.012444 34.702222 34.702222 0 0 1-9.671111-24.120889 99.896889 99.896889 0 0 0-29.923555-65.991111 94.208 94.208 0 0 0-65.649778-26.851556c-24.462222 0-47.900444 9.614222-65.706667 26.851556-17.749333 17.237333-28.444444 40.846222-29.866666 65.991111a34.702222 34.702222 0 0 1-9.671112 24.120889 32.654222 32.654222 0 0 1-46.876444 0 34.702222 34.702222 0 0 1-9.671111-24.120889 169.187556 169.187556 0 0 1 49.834667-113.152A159.459556 159.459556 0 0 1 512.056889 51.2c41.699556 0 81.749333 16.611556 111.900444 46.250667 30.151111 29.696 48.014222 70.200889 49.891556 113.152a34.702222 34.702222 0 0 1-9.671111 24.120889 32.654222 32.654222 0 0 1-23.438222 10.012444z m-257.365334 548.522667a32.654222 32.654222 0 0 1-23.438222-10.012445 34.702222 34.702222 0 0 1-9.671111-24.120889V379.904a34.702222 34.702222 0 0 1 9.671111-24.177778 32.654222 32.654222 0 0 1 46.819556 0 34.702222 34.702222 0 0 1 9.671111 24.177778v379.221333a34.702222 34.702222 0 0 1-9.671111 24.120889 32.654222 32.654222 0 0 1-23.381334 10.012445z m257.365334 0a32.654222 32.654222 0 0 1-23.438223-10.012445 34.702222 34.702222 0 0 1-9.671111-24.120889V379.904a34.702222 34.702222 0 0 1 9.671111-24.177778 32.654222 32.654222 0 0 1 46.876445 0 34.702222 34.702222 0 0 1 9.671111 24.177778v379.221333a34.702222 34.702222 0 0 1-9.671111 24.120889 32.654222 32.654222 0 0 1-23.438222 10.012445z" p-id="3278"></path></svg>
<svg t="1720428211445" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3133" width="200" height="200"><path d="M694.101333 963.299556H329.728a163.214222 163.214222 0 0 1-117.077333-50.062223 173.340444 173.340444 0 0 1-48.526223-120.604444V222.549333a35.043556 35.043556 0 0 1 9.671112-24.177777 33.109333 33.109333 0 0 1 23.438222-9.955556H826.595556a32.312889 32.312889 0 0 1 23.438222 9.955556 34.190222 34.190222 0 0 1 9.671111 24.177777v570.026667c0 45.226667-17.408 88.632889-48.469333 120.604444a163.214222 163.214222 0 0 1-117.134223 50.062223zM230.4 256.739556v535.893333c0 27.136 10.467556 53.191111 29.127111 72.362667 18.659556 19.228444 43.918222 29.980444 70.257778 29.980444h364.373333c26.396444 0 51.655111-10.808889 70.314667-29.980444 18.602667-19.171556 29.070222-45.226667 29.070222-72.419556v-535.893333H230.4z" p-id="3134"></path><path d="M888.490667 256.739556H135.566222a32.654222 32.654222 0 0 1-23.438222-10.012445 34.702222 34.702222 0 0 1 0-48.298667 32.654222 32.654222 0 0 1 23.438222-9.955555h752.924445c8.817778 0 17.237333 3.584 23.438222 9.955555a34.702222 34.702222 0 0 1 0 48.298667 32.654222 32.654222 0 0 1-23.438222 10.012445z" p-id="3135"></path><path d="M640.739556 244.736a32.654222 32.654222 0 0 1-23.438223-10.012444 34.702222 34.702222 0 0 1-9.671111-24.120889 99.896889 99.896889 0 0 0-29.923555-65.991111 94.208 94.208 0 0 0-65.649778-26.851556c-24.462222 0-47.900444 9.614222-65.706667 26.851556-17.749333 17.237333-28.444444 40.846222-29.866666 65.991111a34.702222 34.702222 0 0 1-9.671112 24.120889 32.654222 32.654222 0 0 1-46.876444 0 34.702222 34.702222 0 0 1-9.671111-24.120889 169.187556 169.187556 0 0 1 49.834667-113.152A159.459556 159.459556 0 0 1 512.056889 51.2c41.699556 0 81.749333 16.611556 111.900444 46.250667 30.151111 29.696 48.014222 70.200889 49.891556 113.152a34.702222 34.702222 0 0 1-9.671111 24.120889 32.654222 32.654222 0 0 1-23.438222 10.012444z m-257.365334 548.522667a32.654222 32.654222 0 0 1-23.438222-10.012445 34.702222 34.702222 0 0 1-9.671111-24.120889V379.904a34.702222 34.702222 0 0 1 9.671111-24.177778 32.654222 32.654222 0 0 1 46.819556 0 34.702222 34.702222 0 0 1 9.671111 24.177778v379.221333a34.702222 34.702222 0 0 1-9.671111 24.120889 32.654222 32.654222 0 0 1-23.381334 10.012445z m257.365334 0a32.654222 32.654222 0 0 1-23.438223-10.012445 34.702222 34.702222 0 0 1-9.671111-24.120889V379.904a34.702222 34.702222 0 0 1 9.671111-24.177778 32.654222 32.654222 0 0 1 46.876445 0 34.702222 34.702222 0 0 1 9.671111 24.177778v379.221333a34.702222 34.702222 0 0 1-9.671111 24.120889 32.654222 32.654222 0 0 1-23.438222 10.012445z" p-id="3136"></path></svg>
</template>
<script>

View File

@ -33,19 +33,19 @@
},
methods: {
strength(v){
var _level = 0
let _level = 0;
//
var has_length = v.length >= 6
const has_length = v.length >= 6;
//
var has_number = /\d/.test(v)
const has_number = /\d/.test(v);
//
var has_lovercase = /[a-z]/.test(v)
const has_lovercase = /[a-z]/.test(v);
//
var has_uppercase = /[A-Z]/.test(v)
const has_uppercase = /[A-Z]/.test(v);
//3
var no_continuity = !/(\w)\1{2}/.test(v)
const no_continuity = !/(\w)\1{2}/.test(v);
//
var has_special = /[`~!@#$%^&*()_+<>?:"{},./;'[\]]/.test(v)
const has_special = /[`~!@#$%^&*()_+<>?:"{},./;'[\]]/.test(v);
if(v.length <= 0){
_level = 0

View File

@ -13,7 +13,7 @@
<el-image :src="item.url?item.url:item" :zoom-rate="1.2" :max-scale="7" :min-scale="0.2" :hide-on-click-modal="true" :preview-teleported="true" :initial-index="index" :preview-src-list="imageList" class="avatar" fit="cover" />
<div class="deleteIcon" @click.stop="imgDelete(index)">
<div class="iconBox">
<div class="iconBtn"><sc-icon-Delete /></div>
<el-icon class="iconBtn"><sc-icon-Delete /></el-icon>
</div>
</div>
</div>
@ -175,6 +175,7 @@ export default {
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
}
}

View File

@ -5,6 +5,41 @@
// 示例如下
const routes = [
{
name: "add-permission",
path:"/setting/company/add-permission",
component:"setting/company/add-permission",
meta: {
code:"permission_system_company_permission",
icon: "sc-icon-Home",
title: "功能授权",
hidden: true
},
},
{
name: "company-user-permission",
path:"/setting/user/company-user-list",
component:"setting/user/company-user-list",
meta: {
code:"permission_system_user_list",
icon: "sc-icon-Home",
title: "用户列表",
hidden: true
},
},
{
name: "view-permission",
path:"/setting/user/view-permission",
component:"setting/user/view-permission",
meta: {
code:"permission_system_user_view_permission",
icon: "sc-icon-Home",
title: "查看权限",
hidden: true
},
},
{
name: "home",
path: "/home",

View File

@ -28,7 +28,7 @@ const router = createRouter({
document.title = config.APP_NAME
//判断是否已加载过动态/静态路由
var isGetRouter = false;
let isGetRouter = false;
router.beforeEach(async (to, from, next) => {
@ -66,13 +66,13 @@ router.beforeEach(async (to, from, next) => {
}
//加载动态/静态路由
if(!isGetRouter){
let apiMenu = tool.data.get("MENU") || [] //
let apiMenu = tool.data.get("MENU") || []
let userInfo = tool.data.get("USER_INFO")
let userMenu = treeFilter(userRoutes, node => {
return node.meta.role ? node.meta.role.filter(item=>userInfo.role.indexOf(item)>-1).length > 0 : true
})
let menu = [...userMenu, ...apiMenu]
var menuRouter = filterAsyncRouter(menu)
let menuRouter = filterAsyncRouter(menu);
menuRouter = flatAsyncRoutes(menuRouter)
menuRouter.forEach(item => {
router.addRoute("layout", item)
@ -102,12 +102,12 @@ router.onError((error) => {
//入侵追加自定义方法、对象
router.sc_getMenu = () => {
var apiMenu = tool.data.get("MENU") || [] // tool.data.get("MENU")
const apiMenu = tool.data.get("MENU") || [];
let userInfo = tool.data.get("USER_INFO")
let userMenu = treeFilter(userRoutes, node => {
return node.meta.role ? node.meta.role.filter(item=>userInfo.role.indexOf(item)>-1).length > 0 : true
})
var menu = [...userMenu, ...apiMenu]
const menu = [...userMenu, ...apiMenu];
return menu
}
@ -122,14 +122,14 @@ function filterAsyncRouter(routerMap) {
item.path = `/i/${item.name}`;
}
//MAP转路由对象
var route = {
const route = {
path: item.path,
name: item.name,
meta: item.meta,
redirect: item.redirect,
children: item.children ? filterAsyncRouter(item.children) : null,
component: loadComponent(item.component)
}
};
accessedRouters.push(route)
})
return accessedRouters

View File

@ -54,6 +54,7 @@
}
.el-menu {border: none!important;}
.el-menu .el-menu-item.is-active{background: var(--el-menu-hover-bg-color)}
.el-menu .el-menu-item a {color: inherit;text-decoration: none;display: block;width:100%;height:100%;position: absolute;top:0;left:0;}
.el-form-item-msg {font-size: 12px;color: #999;clear: both;width: 100%;}
.el-container {height: 100%;}
@ -111,6 +112,7 @@
.el-table {font-size: 12px;}
.el-radio-button__inner {font-size: 12px;}
.el-checkbox-button__inner {font-size: 12px;}
.el-checkbox .el-checkbox__label{font-weight: 400;font-size: 12px;}
.el-sub-menu .el-icon {font-size: 16px;color: #aaa;display: flex;align-items: center;justify-content: flex-start;margin-right: 0;}
.el-sub-menu.is-active .el-sub-menu__title{color: var(--el-color-primary)}
.el-sub-menu.is-active .el-sub-menu__title .el-icon{color: var(--el-color-primary)}

View File

@ -0,0 +1,348 @@
<template>
<el-container class="mainBox">
<el-header>
<div class="left-panel">
<el-button type="primary" :size="size" @click="savePermission">保存权限</el-button>
</div>
<div class="right-panel"><div class="companyName">{{name}}</div></div>
</el-header>
<el-main class="nopadding">
<div class="treeTable">
<div :class="list.length===0?'thenTitle thenTitleBottom':'thenTitle'">
<div class="tr">
<div class="th module">功能模块</div>
<div class="th check"><el-checkbox :indeterminate="isCheckFun" @change="allCheckChange" v-model="checkedFun" :size="size" /></div>
<div class="th thFlex">
<div class="menu name">菜单</div>
<div class="th authority">数据操作权限</div>
</div>
</div>
</div>
<div class="tableBody">
<div class="tr" v-for="(item,index) in list" :key="index">
<div class="td module">{{item.meta.title}}</div>
<div class="td check"><el-checkbox v-model="item.checked" :indeterminate="item.isCheck" @change="menuCheckChange(item)" :size="size" /></div>
<div class="td tdChild">
<div class="nextTd" v-for="(em,ind) in item.children" :key="ind">
<div class="tdName menu">
<el-checkbox @change="moduleCheckChange(item,em)" :indeterminate="em.isCheck" v-model="em.checked" :size="size">{{em.meta.title}}</el-checkbox>
</div>
<div class="tdName authority">
<div class="childTr">
<div class="preBox" v-for="(li,lidex) in em.meta.data_permission" :key="lidex">
<el-checkbox @change="checkChange(item,em)" v-model="li.checked" :size="size">{{li.title}}</el-checkbox>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</el-main>
</el-container>
</template>
<script>
export default {
name: "addPermission",
data(){
return{
size:'small',
id: this.$route.query.id,
name:this.$route.query.name,
list:[]
}
},
computed:{
isCheckFun(){
let isTrue = false;
let num = this.list.length;
let checkNum = this.list.filter((item)=>item.checked).length;
let isCheckNum = this.list.filter((item)=>item.isCheck).length;
isTrue = checkNum>0 && checkNum == num?false:checkNum>0 || isCheckNum>0 ? true:false;
return isTrue
},
checkedFun(){
let isTrue = false;
let num = this.list.length;
let checkNum = this.list.filter((item)=>item.checked).length;
isTrue = checkNum>0 && checkNum == num?true:false;
return isTrue
}
},
mounted() {
this.getPermission();
},
methods:{
async getPermission() {
let params = {
company_id:this.id
}
const res = await this.$API.system.company.permission.post(params);
res.data.forEach(item=>{
if(item.children){
item.children.forEach(em=>{
if(em.meta.data_permission){
let check = em.meta.data_permission.filter((li)=>li.checked).length;
let ed = em.meta.data_permission.length;
em.isCheck = check>0 && check != ed?true:false;
if(ed>0){
em.checked = check>0 && check== ed?true:false;
}
}
})
let check = item.children.filter((em)=>em.checked).length;
let isCheck = item.children.filter((em)=>em.isCheck).length;
let ed = item.children.length;
item.isCheck = (check>0 && check != ed) || (isCheck>0 && check!=ed)?true:false;
item.checked = check>0 && check== ed?true:false;
}
})
this.list = res.data;
},
allCheckChange(e){
this.list.forEach(item=>{
item.checked = e;
if(item.children){
item.children.forEach(em=>{
em.checked = e;
if(em.meta.data_permission){
em.meta.data_permission.forEach((li)=>{
li.checked = e;
})
}
if(em.checked){
em.isCheck = false;
}
})
if(item.checked){
item.isCheck = false;
}
}
})
},
menuCheckChange(e){
this.list.forEach(item=>{
if(e.id == item.id){
if(item.children){
item.children.forEach(em=>{
em.checked = e.checked;
if(em.meta.data_permission){
em.meta.data_permission.forEach((li)=>{
li.checked = e.checked;
})
}
if(em.checked){
em.isCheck = false;
}
})
}
if(item.checked){
item.isCheck = false;
}
}
})
},
moduleCheckChange(pre,e){
this.list.forEach(item=>{
if(pre.id == item.id){
if(item.children){
item.children.forEach(em=>{
if(em.id == e.id){
if(em.meta.data_permission){
em.meta.data_permission.forEach((li)=>{
li.checked = e.checked;
})
}
if(e.checked){
e.isCheck = false;
}
}
})
let check = item.children.filter((em)=>em.checked).length;
let isCheck = item.children.filter((em)=>em.isCheck).length;
let ed = item.children.length;
item.checked = check>0 && check == ed?true:false;
item.isCheck = (check>0 || isCheck>0) && ed!=check?true:false;
}
}
})
},
checkChange(max,pre){
this.list.forEach(item=>{
if(item.id == max.id){
if(item.children){
item.children.forEach((em)=>{
if(pre.id == em.id){
let check = em.meta.data_permission.filter((em)=>em.checked).length;
let ed = em.meta.data_permission.length;
em.checked = check>0 && check == ed?true:false;
em.isCheck = check>0 && check != ed?true:false;
}
})
}
let check = item.children.filter((em)=>em.checked).length;
let isCheck = item.children.filter((em)=>em.isCheck).length;
let ed = item.children.length;
item.checked = check>0 && check == ed?true:false;
item.isCheck = (check>0 || isCheck>0) && ed!=check?true:false;
}
})
},
async savePermission() {
let params = this.setList();
const res = await this.$API.system.company.moduleAdd.post(params);
if(res.code == 200){
this.$message.success("授权成功");
this.getPermission();
}
},
setList(){
let obj = {
company_id:this.id,
menu_permission:[],
data_permission:[]
}
this.list.forEach(item=>{
if(item.checked || item.isCheck){
obj.menu_permission.push(item.meta.code);
}
if(item.children){
item.children.forEach(em=>{
if(em.checked || em.isCheck){
obj.menu_permission.push(em.meta.code);
}
if(em.meta.data_permission){
let list = em.meta.data_permission.filter(e=>e.checked).map(u=>{
let obj = {
actions:u.actions,
title:u.title
}
return obj
});
if(list.length>0){
obj.data_permission.push({[em.meta.code]:list})
}
}
})
}
})
return obj
}
}
}
</script>
<style lang="scss" scoped>
.companyName{
color: var(--el-color-primary);
font-size: 14px;
}
.nopadding{
padding: 10px 0;
}
.module{
flex-basis: 120px;
display: flex;
align-items: center;
justify-content: center;
}
.check{
flex-basis: 60px;
display: flex;
align-items: center;
justify-content: center;
}
.menu{
flex-basis: 180px;
}
.authority{
flex:1;
text-align: center;
}
.treeTable{
border: 1px solid var(--el-border-color-light);
}
.thenTitle .tr {
display: flex;
align-items: stretch;
border-bottom:1px solid var(--el-border-color-light);
height: 40px;
background: var(--el-bg-color-overlay);
.th{
padding: 0 10px;
border-left: 1px solid var(--el-border-color-light);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.th:first-child{
border-left: none;
}
.thFlex{
display: flex;
flex: 1;
padding: 0;
.name{
flex-basis: 180px;
padding: 10px;
}
}
}
.thenTitleBottom .tr{
border-bottom: 0;
}
.tableBody .tr{
display: flex;
align-items: stretch;
justify-content: space-between;
border-bottom:1px solid var(--el-border-color-light);
.td{
padding: 0 10px;
border-left: 1px solid var(--el-border-color-light);
.nextTd{
display: flex;
align-items: center;
border-bottom:1px solid var(--el-border-color-light);
}
.nextTd:last-child{
border-bottom: 0;
}
}
.td:first-child{
border-left: 0;
}
.tdChild{
flex: 1;
padding: 0;
border-left: 1px solid var(--el-border-color-light);
.tdName:last-child{
border-left: 1px solid var(--el-border-color-light);
}
.tdName{
padding: 0 10px;
min-height: 33px;
}
.childTr{
display: flex;
flex-wrap: wrap;
flex: 1;
.preBox{
display: flex;
align-items: center;
flex-wrap: wrap;
margin-right: 20px;
width: 110px;
}
}
}
}
.tableBody .tr:last-child{
border-bottom: 0;
}
</style>

View File

@ -49,9 +49,9 @@
<el-dropdown-menu>
<el-dropdown-item @click="table_show(scope.row, 'see')" icon="sc-icon-See">查看详情</el-dropdown-item>
<el-dropdown-item @click="table_edit(scope.row, 'edit')" icon="sc-icon-Edit">编辑公司</el-dropdown-item>
<el-dropdown-item @click="table_del(scope.row, 'delete')" icon="sc-icon-AbilityAuthorization" divided>功能授权</el-dropdown-item>
<el-dropdown-item @click="table_del(scope.row, 'delete')" icon="sc-icon-DataAuthorization">数据授权</el-dropdown-item>
<el-dropdown-item @click="table_del(scope.row, 'delete')" icon="sc-icon-UserList" divided>用户列表</el-dropdown-item>
<el-dropdown-item icon="sc-icon-AbilityAuthorization" @click="table_empower(scope.row)" divided>功能授权</el-dropdown-item>
<el-dropdown-item icon="sc-icon-DataAuthorization">数据授权</el-dropdown-item>
<el-dropdown-item icon="sc-icon-UserList" @click="table_user_ist(scope.row)" divided>用户列表</el-dropdown-item>
<el-dropdown-item @click="table_del(scope.row, 'delete')" icon="sc-icon-Delete">删除公司</el-dropdown-item>
</el-dropdown-menu>
</template>
@ -162,6 +162,27 @@ export default {
})
},
//
table_empower(row){
this.$router.push({
path: '/setting/company/add-permission',
query: {
id: row.id,
name:row.name
}
})
},
//
table_user_ist(row){
this.$message.warning(row.name+' 暂无接口')
// this.$router.push({
// path: '/setting/user/company-user-list',
// query: {
// id: row.id,
// name:row.name
// }
// })
},
//
selectionChange(selection){
this.selection = selection;
@ -178,6 +199,7 @@ export default {
if(res.code !=200){
row.active_status = !row.active_status;
}
delete row.$switch_status;
delete row.$switch_yx;
}, 500);
},

View File

@ -13,7 +13,7 @@
<el-input v-model="form.domain" placeholder="公司系统入口地址" clearable></el-input>
</el-form-item>
<el-form-item label="公司类型" prop="company_type">
<el-select v-model="form.company_type" @visible-change="getCompanyTypeSelect" placeholder="请输入部门名称" clearable style="width: 100%;">
<el-select v-model="form.company_type" @visible-change="getCompanyTypeSelect" placeholder="请选择公司类型" clearable style="width: 100%;">
<el-option v-for="item in setMap.companyType" :key="item" :label="item.label" :value="item.company_type"></el-option>
</el-select>
</el-form-item>
@ -22,6 +22,10 @@
</el-form-item>
<el-form-item label="证件照" prop="doc_url">
<ossImgListUpload :list="form.doc_url" :length="3" @parentParams="faultParentParams" />
<p class="el-form-item-msg">可接受格式为jpgjpegpnggif图片大小不超过5M</p>
<p class="el-form-item-msg">可接受证件类型:营业执照组织机构代码证统一社会信用代码证事业单位法人证书</p>
<p class="el-form-item-msg">可以添加"高德开放平台备案、地图开发申请、地图开发认证"等水印</p>
<p class="el-form-item-msg">但不能遮挡关键信息例如公司名称公司证件号</p>
</el-form-item>
<el-form-item label="公司LOGO" prop="logo">
<ossImgUpload @parentParams="parentParams" :url="form.logo" />
@ -30,23 +34,29 @@
<el-input type="textarea" placeholder="请输入备注"></el-input>
</el-form-item>
<div class="dialogBoxTitle"><span class="make"></span><span class="name">企业管理员信息</span></div>
<el-form-item label="负责人/联系方式" prop="status">
<el-form-item label="负责人/联系方式" required>
<el-row justify="space-between">
<el-col :span="5">
<el-input v-model="form.owner" placeholder="公司负责人"></el-input>
<el-form-item prop="owner">
<el-input v-model="form.owner" placeholder="负责人"></el-input>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item prop="mobile">
<el-input v-model="form.mobile" placeholder="联系方式"></el-input>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="email">
<el-input v-model="form.email" placeholder="邮箱地址"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="账号" prop="admin_access">
<el-input v-model="form.admin_access" placeholder="请填写管理员账号"></el-input>
</el-form-item>
<el-form-item label="登录密码" prop="password">
<el-form-item label="登录密码" prop="password" v-if="mode == 'add'">
<el-input v-model="form.password" type="password" placeholder="请填写密码"></el-input>
</el-form-item>
<el-form-item label="生成系统使用协议" prop="accord">
@ -100,6 +110,30 @@ export default {
full_name: [
{required: true, message: '公司名称不能为空', trigger: 'blur'}
],
name:[
{required: true, message: '公司简称不能为空', trigger: 'blur'}
],
domain:[
{required: true, message: '入口地址不能为空', trigger: 'blur'}
],
address:[
{required: true, message: '请填写公司地址', trigger: 'blur'}
],
email:[
{required: true, message: '请填写邮件地址', trigger: 'blur'}
],
mobile:[
{required: true, message: '请填写联系方式', trigger: 'blur'}
],
logo:[
{required: true, message: '公司LOGO不能为空'}
],
doc_url:[
{required: true, message: '证件照不能为空'}
],
owner:[
{required: true, message: '负责人不能为空', trigger: 'blur'}
],
admin_access: [
{required: true, message: '账号不能为空', trigger: 'blur'}
],
@ -120,7 +154,7 @@ export default {
return this
},
//
//
async getCompanyTypeSelect(e){
if(!e) return
const res = await this.$API.system.company.typeSelect.post();
@ -139,7 +173,12 @@ export default {
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSave = true;
const res = await this.$API.system.company.add.post(this.form);
let res
if(this.mode == "add"){
res = await this.$API.system.company.add.post(this.form);
}else{
res = await this.$API.system.company.update.post(this.form);
}
this.isSave = false;
if(res.code == 200){
this.$emit('success', this.form, this.mode);
@ -154,7 +193,6 @@ export default {
let params = {
id:data.id
}
const res = await this.$API.system.company.info.post(params);
if(res.code == 200){
this.form.id = res.data.id;
@ -165,7 +203,7 @@ export default {
this.form.address = res.data.address;
this.form.email = res.data.platform_user && res.data.platform_user.email?res.data.platform_user.email:'';
this.form.logo = res.data.logo;
this.form.doc_url = [];
this.form.doc_url = res.data.doc_attach && res.data.doc_attach.length>0?res.data.doc_attach.map(em=>em.doc_url):[];
this.form.owner = res.data.owner;
this.form.mobile = res.data.mobile;
this.form.admin_access = res.data.admin_access;

View File

@ -4,23 +4,26 @@
<el-form-item label="公司名称" prop="full_name">
<span>{{form.full_name}}</span>
</el-form-item>
<el-form-item label="公司系统入口地址" prop="label">
<el-form-item label="公司系统入口地址" prop="domain">
<span>{{form.domain}}</span>
</el-form-item>
<el-form-item label="系统开通日期" prop="label">
<el-form-item label="系统开通日期" prop="activation_date">
<span>{{form.activation_date}}</span>
</el-form-item>
<el-form-item label="公司类型" prop="label">
<span></span>
<el-form-item label="公司类型" prop="company_type_name">
<span>{{form.company_type_name}}</span>
</el-form-item>
<el-form-item label="公司地址" prop="label">
<el-form-item label="公司地址" prop="address">
<span>{{form.address}}</span>
</el-form-item>
<el-form-item label="负责人/联系方式" prop="status">
<el-form-item label="负责人/联系方式" prop="owner">
<span>{{form.owner}} {{form.mobile}}</span>
</el-form-item>
<el-form-item label="证件照" prop="remark">
<el-image style="height: 40px" :src="form.logo"></el-image>
<el-form-item label="公司LOGO" prop="logo">
<el-image style="height: 80px;width: 80px;border-radius: 2px;" fit="cover" :src="form.logo"></el-image>
</el-form-item>
<el-form-item label="证件照" prop="doc_attach">
<el-image v-for="item in form.doc_attach" :key="item" style="height: 80px;width: 80px;border-radius: 2px;" fit="cover" :src="item.doc_url"></el-image>
</el-form-item>
</el-form>
<template #footer>
@ -38,6 +41,9 @@ export default {
titleMap: {
show: '查看公司详情'
},
setMap:{
companyType:[]
},
visible: false,
//
form: {},
@ -53,14 +59,30 @@ export default {
this.visible = true;
return this
},
//
async getCompanyTypeSelect(e){
if(!e) return
const res = await this.$API.system.company.typeSelect.post();
if(res.code == 200){
this.setMap['companyType'] = res.data;
}
},
//
async setData(data) {
let params = {
id:data.id
}
await this.getCompanyTypeSelect(true);
const res = await this.$API.system.company.info.post(params);
if(res.code == 200){
this.form = res.data;
this.form.company_type_name = "";
this.setMap.companyType.forEach(em=>{
if(em.company_type === res.data.company_type){
this.form.company_type_name = em.label
}
})
}
}
}

View File

@ -2,7 +2,7 @@
<el-container class="mainBox mainBoxHeaderNoBorder">
<el-header>
<div class="left-panel">
<el-button type="primary" :size="size" icon="el-icon-plus" @click="add"></el-button>
<el-button type="primary" :size="size" icon="el-icon-plus" @click="add">新增部门</el-button>
<el-button type="danger" :size="size" plain icon="el-icon-delete" :disabled="selection.length==0" @click="batch_del"></el-button>
</div>
<div class="right-panel">
@ -24,8 +24,7 @@
<el-button class="noBorderBtn" icon="el-icon-more" :size="size"></el-button>
<template #dropdown>
<el-dropdown-menu>
<!-- <el-dropdown-item @click="handlerCommand(scope.row, 'see')" icon="sc-icon-See">查看 </el-dropdown-item>-->
<!-- <el-dropdown-item @click="handlerCommand(scope.row, 'review')" icon="sc-icon-Review" v-if="scope.row.review_status == 0">审核</el-dropdown-item>-->
<!-- <el-dropdown-item @click="handlerCommand(scope.row, 'review')" icon="sc-icon-Review">审核</el-dropdown-item>-->
<!-- <el-dropdown-item @click="handlerCommand(scope.row, 'cancel')" icon="sc-icon-Revoke">撤回</el-dropdown-item>-->
<el-dropdown-item @click="table_edit(scope.row, 'edit')" icon="sc-icon-Edit">修改</el-dropdown-item>
<el-dropdown-item @click="table_del(scope.row, 'delete')" icon="sc-icon-Delete" divided>删除</el-dropdown-item>
@ -97,18 +96,17 @@
status: row.active_status,
};
const res = await this.$API.system.dept.status.post(params);
if(res.code ==200){
console.log(res.data)
}else{
if(res.code !=200){
row.active_status = !row.active_status;
}
delete row.$switch_status;
delete row.$switch_yx;
}, 500);
},
//
async table_del(row){
const reqData = {id: row.id};
const res = await this.$API.demo.post.post(reqData);
const res = await this.$API.system.dept.delete.post(reqData);
if(res.code == 200){
this.$refs.table.refresh()
this.$message.success("删除成功")
@ -120,11 +118,15 @@
async batch_del(){
this.$confirm(`确定删除选中的 ${this.selection.length} 项吗?如果删除项中含有子集将会被一并删除`, '提示', {
type: 'warning'
}).then(() => {
}).then(async () => {
const loading = this.$loading();
const params = {ids: this.selection.map(em => em.id)};
const res = await this.$API.system.dept.delete.post(params);
if (res.code == 200) {
this.$refs.table.refresh()
this.$message.success("删除成功")
}
loading.close();
this.$message.success("操作成功")
}).catch(() => {
})

View File

@ -1,14 +1,14 @@
<template>
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<el-form :model="form" :rules="rules" :disabled="mode=='show'" ref="dialogForm" label-width="100px">
<el-form-item label="上级部门" prop="parentId">
<el-cascader v-model="form.parentId" :options="groups" :props="groupsProps" :show-all-levels="false" clearable style="width: 100%;"></el-cascader>
<el-form-item label="上级部门" prop="parent_id">
<el-cascader v-model="form.parent_id" :options="depts" :props="deptsProps" :show-all-levels="false" clearable style="width: 100%;"></el-cascader>
</el-form-item>
<el-form-item label="部门名称" prop="label">
<el-input v-model="form.label" placeholder="请输入部门名称" clearable></el-input>
<el-form-item label="部门名称" prop="name">
<el-input v-model="form.name" placeholder="请输入部门名称" clearable></el-input>
</el-form-item>
<el-form-item label="是否有效" prop="status">
<el-switch v-model="form.status" :active-value="1" :inactive-value="0"></el-switch>
<el-form-item label="状态" prop="active_status">
<el-switch v-model="form.active_status" :active-value="true" :inactive-value="false"></el-switch>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" clearable type="textarea"></el-input>
@ -16,7 +16,7 @@
</el-form>
<template #footer>
<el-button @click="visible=false" > </el-button>
<el-button v-if="mode!='show'" type="primary" :loading="isSaveing" @click="submit()"> </el-button>
<el-button v-if="mode!='show'" type="primary" :loading="isSave" @click="submit()"> </el-button>
</template>
</el-dialog>
</template>
@ -33,28 +33,27 @@
show: '查看'
},
visible: false,
isSaveing: false,
isSave: false,
//
form: {
parent_id: "",
id:"",
parentId: "",
label: "",
sort: 1,
status: "1",
name: "",
active_status: true,
remark: ""
},
//
rules: {
sort: [
{required: true, message: '请输入排序', trigger: 'change'}
],
label: [
name: [
{required: true, message: '请输入部门名称'}
]
],
active_status: [
{required: true,}
],
},
//
groups: [],
groupsProps: {
depts: [],
deptsProps: {
value: "id",
emitPath: false,
checkStrictly: true
@ -73,37 +72,35 @@
},
//
async getGroup(){
var res = await this.$API.system.dept.list.get();
this.groups = res.data;
const res = await this.$API.system.dept.active.post();
if(res.code == 200){
this.depts = res.data;
}
},
//
submit(){
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSaveing = true;
var res = await this.$API.demo.post.post(this.form);
this.isSaveing = false;
this.isSave = true;
const res = await this.$API.system.dept.add.post(this.form);
this.isSave = false;
if(res.code == 200){
this.$emit('success', this.form, this.mode)
this.visible = false;
this.$message.success("操作成功")
}else{
this.$alert(res.message, "提示", {type: 'error'})
}
}
})
},
//
setData(data){
this.form.id = data.id
this.form.label = data.label
this.form.status = data.status
this.form.sort = data.sort
this.form.parentId = data.parentId
this.form.remark = data.remark
//
//Object.assign(this.form, data)
async setData(data) {
let params = {
id: data.id
}
const res = await this.$API.system.dept.info.post(params);
if (res.code == 200) {
this.form = res.data;
}
}
}
}

View File

@ -0,0 +1,252 @@
<template>
<!-- 自定义表格 -->
<el-scrollbar max-height="400px">
<div class="customTable">
<div class="tableBody" v-if="list.length>0">
<template v-for="(item,inde) in list" :key="inde">
<div class="trTitle">
<div class="name">
<el-checkbox :indeterminate="item.isCheck" v-model="item.checked" @change="menuCheckChange(item)" :size="size">{{item.meta.title}}</el-checkbox>
</div>
<div class="coseBtn" @click="item.show=!item.show">
<div class="coseBtnIcon">
<span v-if="item.show"><el-icon-arrowDown /></span>
<span v-else><el-icon-arrowRight /></span>
</div>
</div>
</div>
<template v-if="item.show">
<div class="tr" v-for="(em,ind) in item.children" :key="ind">
<div class="td module">
<el-checkbox :indeterminate="em.isCheck" v-model="em.checked" @change="moduleCheckChange(item,em)" :size="size">{{em.meta.title}}</el-checkbox>
</div>
<div class="td tdChild">
<div class="nextTd">
<div class="tdName authority">
<div class="boxName" v-for="(li,ind) in em.meta.data_permission" :key="ind">
<el-checkbox v-model="li.checked" :size="size" @change="checkChange(item,em)"><span class="name">{{li.title}}</span></el-checkbox>
</div>
</div>
</div>
</div>
</div>
</template>
</template>
</div>
</div>
</el-scrollbar>
</template>
<script>
export default {
data() {
return {
size: "default",
list:[]
};
},
props:{
data:{
type:Array
}
},
watch:{
data(val){
val.forEach(item=>{
item.show = true;
if(item.children){
item.children.forEach(em=>{
if(em.meta.data_permission){
let check = em.meta.data_permission.filter((li)=>li.checked).length;
let ed = em.meta.data_permission.length;
em.isCheck = check>0 && check != ed?true:false;
if(ed>0){
em.checked = check>0 && check== ed?true:false;
}
}
})
let check = item.children.filter((em)=>em.checked).length;
let isCheck = item.children.filter((em)=>em.isCheck).length;
let ed = item.children.length;
item.isCheck = (check>0 && check != ed) || (isCheck>0 && check != ed)?true:false;
item.checked = check>0 && check== ed?true:false;
}
})
this.list = JSON.parse(JSON.stringify(val));
}
},
computed:{
},
methods:{
menuCheckChange(e){
this.list.forEach(item=>{
if(e.id == item.id){
if(item.children){
item.children.forEach(em=>{
em.checked = e.checked;
if(em.meta.data_permission){
em.meta.data_permission.forEach((li)=>{
li.checked = e.checked;
})
}
if(em.checked){
em.isCheck = false;
}
})
}
if(item.checked){
item.isCheck = false;
}
}
})
},
moduleCheckChange(pre,e){
this.list.forEach(item=>{
if(pre.id == item.id){
if(item.children){
item.children.forEach(em=>{
if(em.id == e.id){
if(em.meta.data_permission){
em.meta.data_permission.forEach((li)=>{
li.checked = e.checked;
})
}
if(e.checked){
e.isCheck = false;
}
}
})
let check = item.children.filter((em)=>em.checked).length;
let isCheck = item.children.filter((em)=>em.isCheck).length;
let ed = item.children.length;
item.checked = check>0 && check == ed?true:false;
item.isCheck = (check>0 || isCheck>0) && ed!=check?true:false;
}
}
})
},
checkChange(max,pre){
this.list.forEach(item=>{
if(item.id == max.id){
if(item.children){
item.children.forEach((em)=>{
if(pre.id == em.id){
let check = em.meta.data_permission.filter((em)=>em.checked).length;
let ed = em.meta.data_permission.length;
em.checked = check>0 && check == ed?true:false;
em.isCheck = check>0 && check != ed?true:false;
}
})
}
let check = item.children.filter((em)=>em.checked).length;
let isCheck = item.children.filter((em)=>em.isCheck).length;
let ed = item.children.length;
item.checked = check>0 && check == ed?true:false;
item.isCheck = (check>0 || isCheck>0) && ed!=check?true:false;
}
})
},
}
};
</script>
<style lang="scss" scoped>
.module{
flex-basis: 120px;
display: flex;
align-items: center;
justify-content: flex-start;
}
.check{
flex-basis: 60px;
display: flex;
align-items: center;
justify-content: center;
}
.menu{
flex:1;
}
.authority{
flex-basis: 80px;
text-align: center;
}
.customTable{
border: 1px solid var(--el-border-color-light);
border-bottom: 0;
}
.tableBodyNull{
border-top:1px solid var(--el-border-color-light);
}
.tableBody .trTitle{
background: var(--el-bg-color-overlay);
display: flex;
justify-content: space-between;
align-items: center;
height: 36px;
padding: 0 10px;
border-bottom: 1px solid var(--el-border-color-light);
.name{
flex: 1;
}
.coseBtn{
flex-basis: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
.coseBtnIcon{
width: 14px;
color: var(--el-color-primary);
}
}
}
.tableBody .tr{
display: flex;
align-items: stretch;
justify-content: space-between;
border-bottom:1px solid var(--el-border-color-light);
.td{
padding: 0 10px;
border-left: 1px solid var(--el-border-color-light);
.nextTd{
border-bottom:1px solid var(--el-border-color-light);
flex: 1;
}
.nextTd:last-child{
border-bottom: 0;
}
}
.td:first-child{
border-left: 0;
}
.tdChild{
flex: 1;
padding: 0;
border-left: 1px solid var(--el-border-color-light);
.tdName:first-child{
border-left: 0;
}
.tdName{
border-left: 1px solid var(--el-border-color-light);
padding: 0 10px;
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
.boxName{
display: flex;
align-items: center;
margin-right: 20px;
width: 90px;
}
}
}
}
.tableBody .tr:last-child{
//border-bottom: 0;
}
</style>

View File

@ -2,29 +2,26 @@
<el-container class="mainBox mainBoxHeaderNoBorder">
<el-header>
<div class="left-panel">
<el-button type="primary" :size="size" icon="el-icon-plus" @click="add"></el-button>
<el-button type="danger" :size="size" plain icon="el-icon-delete" :disabled="selection.length==0" @click="batch_del"></el-button>
<el-button type="primary" :size="size" icon="el-icon-plus" @click="add">新建</el-button>
<el-button type="danger" :size="size" plain icon="el-icon-delete" :disabled="selection.length==0" @click="batch_del">删除</el-button>
<el-button type="primary" :size="size" plain :disabled="selection.length!=1" @click="permission">权限设置</el-button>
</div>
<div class="right-panel">
<div class="right-panel-search">
<el-input :size="size" v-model="search.keyword" placeholder="角色名称" clearable></el-input>
<el-button :size="size" type="primary" icon="el-icon-search" @click="upsearch"></el-button>
</div>
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="list.apiObj" row-key="id" @selection-change="selectionChange" stripe :size="size">
<scTable ref="table" :apiObj="list.apiObj" :column="list.column" row-key="id" @selection-change="selectionChange" stripe :size="size">
<el-table-column type="selection" align="center" width="50"></el-table-column>
<el-table-column label="序号" type="index" align="center" width="50"></el-table-column>
<el-table-column label="角色名称" prop="label" width="150"></el-table-column>
<el-table-column label="状态" prop="status" width="80">
<template #default="scope">
<el-switch v-model="scope.row.status" @change="changeSwitch($event, scope.row)" :loading="scope.row.$switch_status" :active-value="true" :inactive-value="false"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="date" width="180"></el-table-column>
<el-table-column label="备注" prop="remark" min-width="150"></el-table-column>
<el-table-column label="状态" prop="status" align="center" width="100">
<template #default="scope">
<el-switch :size="size" v-model="scope.row.active_status" @change="changeSwitch($event, scope.row)" :loading="scope.row.$switch_status" :active-value="true" :inactive-value="false"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" align="center" width="170">
<template #default="scope">
<el-dropdown>
@ -72,9 +69,6 @@
column:[]
},
selection: [],
search: {
keyword: null
}
}
},
methods: {
@ -92,40 +86,36 @@
this.$refs.saveDialog.open('edit').setData(row)
})
},
//
table_show(row){
this.dialog.save = true
this.$nextTick(() => {
this.$refs.saveDialog.open('show').setData(row)
})
},
//
permission(){
this.dialog.permission = true
this.dialog.permission = true;
this.$nextTick(() => {
this.$refs.permissionDialog.open()
const role_id = this.selection[0]["id"];
this.$refs.permissionDialog.open(role_id)
})
},
//
async table_del(row){
var reqData = {id: row.id}
var res = await this.$API.demo.post.post(reqData);
const params = {ids: [row.id]};
const res = await this.$API.system.role.delete.post(params);
if(res.code == 200){
this.$refs.table.refresh()
this.$message.success("删除成功")
}else{
this.$alert(res.message, "提示", {type: 'error'})
}
},
//
async batch_del(){
this.$confirm(`确定删除选中的 ${this.selection.length} 项吗?如果删除项中含有子集将会被一并删除`, '提示', {
this.$confirm(`确定删除选中的 ${this.selection.length} 项吗?`, '提示', {
type: 'warning'
}).then(() => {
}).then(async () => {
const loading = this.$loading();
const params = {ids: this.selection.map(em=>em.id)};
const res = await this.$API.system.role.delete.post(params);
if (res.code == 200) {
this.$refs.table.refresh()
this.$message.success("删除成功")
}
loading.close();
this.$message.success("操作成功")
}).catch(() => {
})
@ -136,21 +126,23 @@
},
//
changeSwitch(val, row){
row.status = row.status == '1'?'0':'1'
row.$switch_status = true;
setTimeout(()=>{
setTimeout(async () => {
let params = {
id: row.id,
status: row.active_status,
};
const res = await this.$API.system.role.status.post(params);
if (res.code != 200) {
row.active_status = !row.active_status;
}
delete row.$switch_status;
row.status = val;
this.$message.success("操作成功")
delete row.$switch_yx;
}, 500)
},
//
upsearch(){
},
//ID
filterTree(id){
var target = null;
let target = null;
function filter(tree){
tree.forEach(item => {
if(item.id == id){

View File

@ -0,0 +1,179 @@
<template>
<el-scrollbar max-height="400px">
<div class="customTable">
<div :class="list.length===0?'thenTitle thenTitleBottom':'thenTitle'">
<div class="tr">
<div class="th btnCheckout"><el-checkbox @change="allCheckChange" :indeterminate="isCheckFun" v-model="checkedFun" :size="size"></el-checkbox></div>
<div class="th seq">序号</div>
<div class="th name">姓名</div>
<div class="th department">部门</div>
<div class="th mobile">手机号</div>
</div>
</div>
<div :class="list.length==0?'tableBody tableBodyNull':'tableBody'">
<template v-if="list.length>0">
<div class="tr" v-for="(item,index) in list" :key="index">
<div class="td btnCheckout"><el-checkbox v-model="item.checked" :size="size"></el-checkbox></div>
<div class="td seq">{{index+1}}</div>
<div class="td name">{{item.name}}</div>
<div class="td department">{{item.department}}</div>
<div class="td mobile">{{item.mobile}}</div>
</div>
</template>
<el-empty v-else :description="emptyText" :image-size="100"></el-empty>
</div>
</div>
</el-scrollbar>
</template>
<script>
export default {
name: "members.vue",
data(){
return{
size: "default",
list:[],
emptyText:'暂无数据'
}
},
props:{
data:{
type:Array,
}
},
watch:{
data(val){
val.forEach(item=>{
item.checked = false;
})
this.list = JSON.parse(JSON.stringify(val));
},
},
computed:{
checkedFun(){
let isTrue = false;
let num = this.list.length;
let checkNum = this.list.filter((item)=>item.checked).length;
isTrue = checkNum>0 && checkNum == num?true:false;
return isTrue
},
isCheckFun(){
let isTrue = false;
let num = this.list.length;
let checkNum = this.list.filter((item)=>item.checked).length;
isTrue = (checkNum>0 && checkNum == num) || checkNum==0 ?false:true;
return isTrue
},
},
mounted() {
},
methods:{
allCheckChange(e){
this.list.forEach(item=>{
if(item){
item.checked = e;
}
})
},
}
}
</script>
<style lang="scss" scoped>
.btnCheckout{
flex-basis: 60px;
display: flex;
align-items: center;
justify-content: center;
}
.seq{
flex-basis: 60px;
display: flex;
align-items: center;
justify-content: center;
}
.name{
flex:1;
display: flex;
align-items: center;
justify-content: center;
}
.department{
flex-basis: 150px;
display: flex;
align-items: center;
justify-content: center;
}
.mobile{
flex-basis: 150px;
display: flex;
align-items: center;
justify-content: center;
}
.customTable{
border: 1px solid var(--el-border-color-light);
font-size: 12px;
}
.thenTitle .tr {
display: flex;
align-items: stretch;
border-bottom:1px solid var(--el-border-color-light);
height: 40px;
.th{
padding: 0 10px;
border-left: 1px solid var(--el-border-color-light);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.th:first-child{
border-left: 0;
}
}
.thenTitleBottom .tr{
border-bottom: 0;
}
.tableBodyNull{
border-top:1px solid var(--el-border-color-light);
}
.tableBody .tr{
display: flex;
align-items: stretch;
justify-content: space-between;
border-bottom:1px solid var(--el-border-color-light);
.td{
padding: 0 10px;
border-left: 1px solid var(--el-border-color-light);
.nextTd{
display: flex;
align-items: center;
border-bottom:1px solid var(--el-border-color-light);
}
.nextTd:last-child{
border-bottom: 0;
}
}
.td:first-child{
border-left: 0;
}
.tdChild{
flex: 1;
padding: 0;
border-left: 1px solid var(--el-border-color-light);
.tdName:first-child{
border-left: 0;
}
.tdName{
border-left: 1px solid var(--el-border-color-light);
padding: 0 10px;
}
}
}
.tableBody .tr:last-child{
border-bottom: 0;
}
</style>

View File

@ -1,190 +1,356 @@
<template>
<el-dialog title="角色权限设置" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<el-tabs tab-position="top">
<el-tab-pane label="菜单权限">
<div class="treeMain">
<el-tree ref="menu" node-key="name" :data="menu.list" :props="menu.props" show-checkbox></el-tree>
<el-dialog
title="权限设置"
v-model="visible"
:width="720"
destroy-on-close
@closed="$emit('closed')"
>
<div class="dialogBody">
<div class="btnPot" v-if="activeNum==1">
<el-button type="danger" plain :size="size" @click="deleteMember">移除成员</el-button>
<el-button type="primary" plain :size="size" @click="memberShow=true && this.getDeptTree()">添加成员</el-button>
</div>
<el-tabs tab-position="top" @tab-change="activeClick">
<el-tab-pane label="角色权限">
<dataTree ref="dataTree" :data="menu.list"/>
</el-tab-pane>
<el-tab-pane label="数据权限">
<el-form label-width="100px" label-position="left">
<el-form-item label="规则类型">
<el-select v-model="data.dataType" placeholder="请选择">
<el-option label="全部可见" value="1"></el-option>
<el-option label="本人可见" value="2"></el-option>
<el-option label="所在部门可见" value="3"></el-option>
<el-option label="所在部门及子级可见" value="4"></el-option>
<el-option label="选择的部门可见" value="5"></el-option>
<el-option label="自定义" value="6"></el-option>
</el-select>
</el-form-item>
<el-form-item label="选择部门" v-show="data.dataType=='5'">
<div class="treeMain" style="width: 100%;">
<el-tree ref="dept" node-key="id" :data="data.list" :props="data.props" show-checkbox></el-tree>
</div>
</el-form-item>
<el-form-item label="规则值" v-show="data.dataType=='6'">
<el-input v-model="data.rule" clearable type="textarea" :rows="6" placeholder="请输入自定义规则代码"></el-input>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="控制台模块">
<div class="treeMain">
<el-tree ref="grid" node-key="key" :data="grid.list" :props="grid.props" :default-checked-keys="grid.checked" show-checkbox></el-tree>
</div>
</el-tab-pane>
<el-tab-pane label="控制台">
<el-form label-width="100px" label-position="left">
<el-form-item label="控制台视图">
<el-select v-model="dashboard" placeholder="请选择">
<el-option v-for="item in dashboardOptions" :key="item.value" :label="item.label" :value="item.value">
<span style="float: left">{{ item.label }}</span>
<span style="float: right; color: #8492a6; font-size: 12px">{{ item.views }}</span>
</el-option>
</el-select>
<div class="el-form-item-msg">用于控制角色登录后控制台的视图</div>
</el-form-item>
</el-form>
<el-tab-pane label="角色成员">
<members ref="members" :data="roleUser.list" />
</el-tab-pane>
</el-tabs>
</div>
<template #footer>
<el-button @click="visible = false"> </el-button>
<el-button type="primary" :loading="isSaveing" @click="submit()"> </el-button>
<el-button type="primary" v-if="activeNum==0" :loading="isSaveing" @click="submit()"> </el-button>
</template>
</el-dialog>
<el-dialog
title="选择成员"
v-model="memberShow"
:width="720"
destroy-on-close
@closed="closedClose"
>
<div class="bodyView">
<div class="viewLeft">
<div class="viewTitle">部门</div>
<div class="viewCom">
<el-scrollbar>
<treeUser class="treeUser" ref="treeList" :data="deptTree" :userIds="userIds" @roleChecked="roleChecked" />
</el-scrollbar>
</div>
</div>
<div class="iconRight">
<div class="icon">
<el-icon-ArrowRight></el-icon-ArrowRight>
</div>
</div>
<div class="viewRight">
<div class="viewTitle">已选成员 ({{userCheckList.length}})</div>
<div class="viewCom">
<el-scrollbar>
<div class="checkList" v-for="(item,index) in userCheckList" :key="index" @click="deleteUser(item)">
<div class="leftTitle">
<div class="avatar">{{ userAvatar(item) }}</div>
<div class="name">{{item.name}}</div>
</div>
<div class="userBtn"><el-icon-Close></el-icon-Close></div>
</div>
</el-scrollbar>
</div>
</div>
</div>
<template #footer>
<el-button @click="memberShow = false"> </el-button>
<el-button type="primary" :loading="isMember" @click="userSubmit"> </el-button>
</template>
</el-dialog>
</template>
<script>
import dataTree from "./dataTree";
import members from "./members";
import treeUser from "./tree"
export default {
emits: ['success', 'closed'],
components: {
dataTree,
members,
treeUser
},
emits: ["success", "closed"],
data() {
return {
size:'small',
visible: false,
isSaveing: false,
activeNum:0,
menu: {
list: [],
checked: [],
props: {
label: (data)=>{
return data.meta.title
}
}
},
grid: {
list: [],
checked: ["welcome", "ver", "time", "progress", "echarts", "about"],
props: {
label: (data)=>{
return data.title
roleUser:{
list:[]
},
disabled: (data)=>{
return data.isFixed
}
}
},
data: {
dataType :"1",
list: [],
checked: [],
props: {},
rule: ""
},
dashboard: "0",
dashboardOptions: [
{
value: '0',
label: '数据统计',
views: 'stats'
memberShow:false,
deptTree:[],
isMember:false,
userCheckList:[],
userIds:[],
},
{
value: '1',
label: '工作台',
views: 'work'
},
]
}
role_id: 0,
};
},
mounted() {
this.getMenu()
this.getDept()
this.getGrid()
},
methods: {
open(){
this.visible = true;
userAvatar(row) {
return row.name.substring(0, 1)
},
open(role_id) {
this.visible = true;
this.role_id = role_id;
this.getMenu();
this.getRoleList();
},
submit() {
this.isSaveing = true;
//
var checkedKeys = this.$refs.menu.getCheckedKeys().concat(this.$refs.menu.getHalfCheckedKeys())
console.log(checkedKeys)
var checkedKeys_dept = this.$refs.dept.getCheckedKeys().concat(this.$refs.dept.getHalfCheckedKeys())
console.log(checkedKeys_dept)
setTimeout(()=>{
const params = this.setList(this.$refs.dataTree.list);
setTimeout(async ()=>{
const res = await this.$API.system.role.roleAuth.post(params);
if(res.code === 200){
this.isSaveing = false;
this.visible = false;
this.$message.success("操作成功")
this.$emit('success')
},1000)
this.$message.success("授权成功");
this.$emit("success");
}
})
},
setList(list){
let obj = {
role_id:this.role_id,
menu_permission:[],
data_permission:[]
}
list.forEach(item=>{
if(item.checked || item.isCheck){
obj.menu_permission.push(item.meta.code);
}
if(item.children){
item.children.forEach(em=>{
if(em.checked || em.isCheck){
obj.menu_permission.push(em.meta.code);
}
if(em.meta.data_permission){
let list = em.meta.data_permission.filter(e=>e.checked).map(u=>{
let obj = {
actions:u.actions,
title:u.title
}
return obj
});
if(list.length>0){
obj.data_permission.push({[em.meta.code]:list})
}
}
})
}
})
return obj
},
activeClick(e){
this.activeNum = e;
},
async getMenu() {
var res = await this.$API.system.menu.list.get()
this.menu.list = res.data
//key
this.menu.checked = ["system", "user", "user.add", "user.edit", "user.del", "directive.edit", "other", "directive"]
this.$nextTick(() => {
let filterKeys = this.menu.checked.filter(key => this.$refs.menu.getNode(key).isLeaf)
this.$refs.menu.setCheckedKeys(filterKeys, true)
let params = {
role_id: this.role_id,
};
const res = await this.$API.system.role.roleMenu.post(params);
this.menu.list = res.data;
},
async getRoleList() {
let params = {
role_id: this.role_id,
};
const res = await this.$API.system.role.roleUser.post(params);
this.roleUser.list = res.data;
this.userCheckList = res.data;
this.userIds = res.data.map(item=>item.id);
},
async getDeptTree() {
const res = await this.$API.system.role.tree.post();
this.deptTree = this.treeShow(res.data);
},
//
treeShow(list){
list.forEach(item=>{
item.isOpen = false;
if(item.children){
this.treeShow(item.children)
}
})
return list
},
roleChecked(em){
let arr = this.userIds;
if(arr.indexOf(em.id) ==-1){
this.userIds.push(em.id);
this.userCheckList.push(em);
return
}
this.userIds.forEach((item,index)=>{
if(item == em.id){
this.userIds.splice(index,1);
}
})
this.userCheckList.forEach((item,index)=>{
if(item.id == em.id){
this.userCheckList.splice(index,1);
}
})
},
async getDept(){
var res = await this.$API.system.dept.list.get();
this.data.list = res.data
this.data.checked = ["12", "2", "21", "22", "1"]
this.$nextTick(() => {
let filterKeys = this.data.checked.filter(key => this.$refs.dept.getNode(key).isLeaf)
this.$refs.dept.setCheckedKeys(filterKeys, true)
deleteUser(em){
this.userIds.forEach((item,index)=>{
if(item == em.id){
this.userIds.splice(index,1);
}
})
this.userCheckList.forEach((item,index)=>{
if(item.id == em.id){
this.userCheckList.splice(index,1);
}
})
},
getGrid(){
this.grid.list = [
{
key: "welcome",
title: "欢迎",
isFixed: true
},
{
key: "ver",
title: "版本信息",
isFixed: true
},
{
key: "time",
title: "时钟"
},
{
key: "progress",
title: "进度环"
},
{
key: "echarts",
title: "实时收入"
},
{
key: "about",
title: "关于项目"
//
deleteMember(){
let ids = [];
this.$refs.members.list.forEach(item=>{
if(item.checked){
ids.push(item.id);
}
]
})
setTimeout(async()=>{
let params = {
user_ids:ids,
role_id:this.role_id
}
const res = await this.$API.system.role.roleUserDel.post(params);
if(res.code == 200){
await this.getRoleList();
}
},100)
},
//
closedClose(){
this.memberShow = false;
},
//
async userSubmit() {
let params = {
role_ids: [this.role_id],
user_ids: this.userCheckList.map(em=>em.id)
};
this.isMember = true;
const res = await this.$API.system.role.roleUserAdd.post(params);
if(res.code == 200){
this.memberShow = false;
this.$message.success('保存成功');
this.isMember = false;
await this.getRoleList();
}
},
},
};
</script>
<style scoped>
.treeMain {height:280px;overflow: auto;border: 1px solid #dcdfe6;margin-bottom: 10px;}
<style lang="scss" scoped>
.dialogBody{
position: relative;
margin: -20px 0;
}
.btnPot{
position: absolute;
top: 6px;
right: 0;
z-index: 10;
}
.bodyView{
display: flex;
font-size: 12px;
.viewLeft{
flex: 1;
display: flex;
flex-direction: column;
.treeUser{
padding: 10px 15px 10px 0;
}
}
.iconRight{
flex-basis: 30px;
display: flex;
align-items: center;
justify-content: center;
.icon{
width: 14px;
}
}
.viewRight{
flex: 1;
display: flex;
flex-direction: column;
.checkList{
display: flex;
justify-content: space-between;
margin:8px 15px 8px 15px;
.leftTitle{
flex: 1;
display: flex;
align-items: center;
cursor: pointer;
color: var(--el-color-primary);
.avatar{
background: var(--el-color-primary);
color: var(--el-color-white);
border-radius: 50%;
display: inline-block;
height: 21px;
width: 21px;
text-align: center;
line-height: 21px;
}
.name{
margin-left: 10px;
}
}
.userBtn{
flex-basis: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.userBtn:hover{
color: var(--el-color-primary);
}
}
.checkList:first-child{
margin-top: 10px;
}
.checkList:last-child{
margin-bottom: 10px;
}
}
.viewTitle{
flex-basis: 35px;
}
.viewCom{
flex: 1;
border: 1px solid var(--el-border-color-light);
min-height: 200px;
max-height: 400px;
border-radius: 8px;
}
}
</style>

View File

@ -1,14 +1,11 @@
<template>
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" draggable destroy-on-close @closed="$emit('closed')">
<el-form :model="form" :rules="rules" :disabled="mode=='show'" ref="dialogForm" label-width="120px" label-position="right">
<el-form-item label="角色名称" prop="label">
<el-input v-model="form.label" clearable></el-input>
<el-form-item label="角色名称" prop="role_name">
<el-input v-model="form.role_name" placeholder="请填写角色名称" clearable></el-input>
</el-form-item>
<el-form-item label="角色别名" prop="alias">
<el-input v-model="form.alias" clearable></el-input>
</el-form-item>
<el-form-item label="是否有效" prop="status">
<el-switch v-model="form.status" active-value="1" inactive-value="0"></el-switch>
<el-form-item label="状态" prop="active_status">
<el-switch v-model="form.active_status" :active-value="true" :inactive-value="false"></el-switch>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" clearable type="textarea"></el-input>
@ -16,7 +13,7 @@
</el-form>
<template #footer>
<el-button @click="visible=false" > </el-button>
<el-button v-if="mode!='show'" type="primary" :loading="isSaveing" @click="submit()"> </el-button>
<el-button v-if="mode!='show'" type="primary" :loading="isSave" @click="submit()"> </el-button>
</template>
</el-dialog>
</template>
@ -33,26 +30,21 @@
show: '查看'
},
visible: false,
isSaveing: false,
isSave: false,
//
form: {
id:"",
label: "",
alias: "",
sort: 1,
status: 1,
role_name: "",
active_status: true,
remark: ""
},
//
rules: {
sort: [
{required: true, message: '请输入排序', trigger: 'change'}
],
label: [
role_name: [
{required: true, message: '请输入角色名称'}
],
alias: [
{required: true, message: '请输入角色别名'}
active_status: [
{required: true,}
]
}
}
@ -71,15 +63,13 @@
submit(){
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSaveing = true;
var res = await this.$API.demo.post.post(this.form);
this.isSaveing = false;
this.isSave = true;
const res = await this.$API.system.role.add.post(this.form);
this.isSave = false;
if(res.code == 200){
this.$emit('success', this.form, this.mode)
this.visible = false;
this.$message.success("操作成功")
}else{
this.$alert(res.message, "提示", {type: 'error'})
}
}
})
@ -87,14 +77,9 @@
//
setData(data){
this.form.id = data.id
this.form.label = data.label
this.form.alias = data.alias
this.form.sort = data.sort
this.form.status = data.status
this.form.role_name = data.role_name
this.form.active_status = data.active_status
this.form.remark = data.remark
//
//Object.assign(this.form, data)
}
}
}

View File

@ -0,0 +1,136 @@
<template>
<!-- 自定义表格 -->
<div class="tableBody">
<div class="tr" v-for="(item,index) in data" :key="index">
<div class="td tdTitle" @click="openFile(item)">
<div class="file" v-if="item.children || (item.user_info && item.user_info.length)"><el-icon-FolderOpened></el-icon-FolderOpened></div>
<div class="file" v-else><el-icon-Folder></el-icon-Folder></div>
<div class="name">{{item.name}}</div>
</div>
<template v-if="item.isOpen">
<div class="td tdUser" v-if="item.user_info && item.user_info.length>0">
<div :class="userChecked(userIds,em)?'userList':'userList userChecked'" v-for="(em,ind) in item.user_info" :key="ind" @click="roleChecked(em)">
<div class="userName">
<div class="avatar">{{ userAvatar(em) }}</div>
<div class="name">{{em.name}}</div>
</div>
<div class="userBtn" v-if="!userChecked(userIds,em)"><el-icon-Check></el-icon-Check></div>
</div>
</div>
</template>
<template v-if="item.children && item.isOpen">
<treeDept class="td tdCom" :data="item.children" :userIds="userIds" @roleChecked="roleChecked" />
</template>
</div>
</div>
</template>
<script>
export default {
name:'treeDept',
data() {
return {
size: "small",
isShow:true,
};
},
props:{
data:{
type:Array,
required: true
},
userIds:{
type:Array
}
},
watch:{
},
computed:{
},
methods:{
userAvatar(row) {
return row.name.substring(0, 1)
},
userChecked(arr,em){
return arr.indexOf(em.id)!=-1?false:true
},
roleChecked(em){
this.$emit('roleChecked',em);
},
openFile(item){
this.$nextTick(()=>{
item.isOpen = !item.isOpen;
})
}
}
};
</script>
<style lang="scss" scoped>
.tableBody .tr{
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: space-between;
.td{
padding: 3px 0 3px 12px;
}
.td:first-child{
border-left: 0;
}
.tdTitle{
display: flex;
justify-content: flex-start;
cursor: pointer;
.file{
width: 14px;
margin-right: 5px;
}
}
.tdUser{
.userList{
padding:4px 0 4px 12px;
display: flex;
justify-content: space-between;
.userName{
flex: 1;
display: flex;
align-items: center;
cursor: pointer;
.avatar{
background: var(--el-text-color-disabled);
color: var(--el-color-white);
border-radius: 50%;
display: inline-block;
height: 21px;
width: 21px;
text-align: center;
line-height: 21px;
}
.name{
margin-left: 10px;
}
}
.userBtn{
flex-basis: 12px;
display: flex;
align-items: center;
justify-content: center;
}
}
.userChecked{
color: var(--el-color-primary);
.userName{
.avatar{
background:var(--el-color-primary);
}
}
}
}
}
.tableBody .tr:last-child{
border-bottom: 0;
}
</style>

View File

@ -0,0 +1,74 @@
<template>
<el-container class="mainBox">
<el-header>
<div class="left-panel">
<div class="companyName">{{name}}</div>
</div>
<div class="right-panel">
<div class="right-panel-search">
<el-input :size="size" v-model="params.keyword" placeholder="关键字" clearable></el-input>
<el-button :size="size" type="primary" icon="el-icon-search" @click="upsearch"></el-button>
</div>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
tableName="listCustomColumn"
@selection-change="selectionChange"
@sizeChange="sizeChange"
:params="params"
:apiObj="list.apiObj"
:column="list.column"
row-key="id"
stripe
>
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column label="序号" type="index" width="50"></el-table-column>
</scTable>
</el-main>
</el-container>
</template>
<script>
export default {
name: "company-user-list",
data(){
return{
size:'small',
id: this.$route.query.id,
name:this.$route.query.name,
list: {
apiObj: this.$API.system.user.userCompanyList,
column: [],
},
selection: [],
params:{
company_id:this.$route.query.id,
url:'company.user.list',
keyword: '',
},
}
},
mounted() {
},
methods:{
//
upsearch() {
this.$refs.table.upData(this.search);
},
//
selectionChange(selection) {
this.selection = selection;
},
}
}
</script>
<style scoped lang="scss">
.companyName{
color: var(--el-color-primary);
font-size: 14px;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<el-container class="mainBox ">
<el-aside width="200px" v-loading="showGrouploading">
<el-aside width="200px" v-loading="showGroupLoading">
<el-container>
<el-header>
<el-input placeholder="输入关键字进行过滤" :size="size" v-model="groupFilterText" clearable></el-input>
@ -13,20 +13,20 @@
<el-container>
<el-header>
<div class="left-panel">
<el-button type="primary" :size="size" icon="el-icon-plus" @click="add"></el-button>
<el-button type="primary" :size="size" icon="el-icon-plus" @click="add">新增用户</el-button>
<el-button type="danger" plain :size="size" icon="el-icon-delete" :disabled="selection.length==0" @click="batch_del"></el-button>
<el-button type="primary" plain :size="size" :disabled="selection.length==0">分配角色</el-button>
<el-button type="primary" plain :size="size" :disabled="selection.length==0">密码重置</el-button>
<el-button type="primary" plain :size="size" :disabled="selection.length==0" @click="role">分配角色</el-button>
<el-button type="primary" plain :size="size" :disabled="selection.length==0" @click="rePwd">密码重置</el-button>
</div>
<div class="right-panel">
<div class="right-panel-search">
<el-input v-model="search.name" :size="size" placeholder="关键字" clearable></el-input>
<el-input v-model="params.name" :size="size" placeholder="关键字" clearable></el-input>
<el-button type="primary" :size="size" icon="el-icon-search" @click="upSearch"></el-button>
</div>
</div>
</el-header>
<el-main class="nopadding">
<scTable ref="table" :apiObj="apiObj" @selection-change="selectionChange" stripe :size="size" remoteSort remoteFilter>
<scTable ref="table" :apiObj="list.apiObj" :column="list.column" @selection-change="selectionChange" stripe :size="size">
<el-table-column type="selection" align="center" width="45"></el-table-column>
<el-table-column label="序号" type="index" align="center" width="50"></el-table-column>
<template #avatar="scope">
@ -34,6 +34,13 @@
<el-avatar :src="scope.row.avatar" size="small"></el-avatar>
</div>
</template>
<template #roles="scope">
<span v-if="scope.row.user_roles">
<span v-for="(em,index) in scope.row.user_roles.role_names" :key="index">
<span>{{em}}</span><span v-if="index+1<scope.row.user_roles.role_names.length"></span>
</span>
</span>
</template>
<template #active_status="scope">
<el-switch :size="size" v-model="scope.row.active_status" @change="changeSwitch($event, scope.row)" :loading="scope.row.$switch_status" :active-value="true" :inactive-value="false"></el-switch>
</template>
@ -45,6 +52,7 @@
<el-dropdown-menu>
<el-dropdown-item @click="table_show(scope.row, 'show')" icon="sc-icon-See">用户详情</el-dropdown-item>
<el-dropdown-item @click="table_edit(scope.row, 'edit')" icon="sc-icon-Edit">编辑用户</el-dropdown-item>
<el-dropdown-item @click="table_empower(scope.row)" icon="sc-icon-AbilityAuthorization" divided>查看权限</el-dropdown-item>
<el-dropdown-item @click="table_del(scope.row, 'delete')" icon="sc-icon-Delete">删除用户</el-dropdown-item>
</el-dropdown-menu>
</template>
@ -58,29 +66,38 @@
</el-container>
<save-dialog v-if="dialog.save" ref="saveDialog" @success="handleSuccess" @closed="dialog.save=false"></save-dialog>
<re-pwd-dialog v-if="dialog.rePwdD" ref="rePwdDialog" @success="handleSuccess" @closed="dialog.rePwdD=false"></re-pwd-dialog>
<dis-role-dialog v-if="dialog.role" ref="diRoleDialog" @success="handleSuccess" @closed="dialog.role=false"></dis-role-dialog>
</template>
<script>
import saveDialog from './save'
import rePwdDialog from './rePwd'
import disRoleDialog from './role'
export default {
name: 'user',
components: {
saveDialog
saveDialog, rePwdDialog, disRoleDialog
},
data() {
return {
size:'small',
dialog: {
save: false
save: false,
rePwdD: false,
role: false
},
showGrouploading: false,
showGroupLoading: false,
groupFilterText: '',
group: [],
list:{
apiObj: this.$API.system.user.list,
column:[]
},
selection: [],
search: {
params: {
name: null
}
}
@ -94,6 +111,28 @@
this.getGroup()
},
methods: {
rePwd() {
this.dialog.rePwdD = true
this.$nextTick(() => {
const id = this.selection[0]['id']
this.$refs.rePwdDialog.open('add', id)
})
},
role() {
this.dialog.role = true
this.$nextTick(() => {
const data = this.selection;
const row = {
id: data[0]['id'],
login_name: data[0]['login_name'],
name: data[0]['name'],
group: data[0]['user_roles'],
mobile: data[0]['mobile'],
avatar:data[0]['avatar']
}
this.$refs.diRoleDialog.open().setData(row)
})
},
//
add(){
this.dialog.save = true
@ -116,48 +155,55 @@
})
},
//
async table_del(row, index){
var reqData = {id: row.id}
var res = await this.$API.demo.post.post(reqData);
async table_del(row){
const reqData = {ids: [row.id]};
const res = await this.$API.system.user.delete.post(reqData);
if(res.code == 200){
// OR /
this.$refs.table.tableData.splice(index, 1);
this.$refs.table.refresh();
this.$message.success("删除成功")
}else{
this.$alert(res.message, "提示", {type: 'error'})
}
},
//
async batch_del(){
this.$confirm(`确定删除选中的 ${this.selection.length} 项吗?`, '提示', {
type: 'warning'
}).then(() => {
}).then(async () => {
const loading = this.$loading();
this.selection.forEach(item => {
this.$refs.table.tableData.forEach((itemI, indexI) => {
if (item.id === itemI.id) {
this.$refs.table.tableData.splice(indexI, 1)
const params = {ids: this.selection.map(em => em.id)};
const res = await this.$API.system.user.delete.post(params);
if (res.code == 200) {
this.$refs.table.refresh();
this.$message.success("删除成功");
}
})
})
loading.close();
this.$message.success("操作成功")
}).catch(() => {
})
},
//
table_empower(row){
this.$router.push({
path: '/setting/user/view-permission',
query: {
id: row.id,
name:row.name,
}
})
},
//
selectionChange(selection){
this.selection = selection;
},
//
async getGroup(){
this.showGrouploading = true;
this.showGroupLoading = true;
const res = await this.$API.system.dept.active.post();
this.showGrouploading = false;
if(res.code == 200){
const allNode = {id: '', label: '所有'};
res.data.unshift(allNode);
this.group = res.data;
}
this.showGroupLoading = false;
},
//
groupFilterNode(value, data){
@ -183,23 +229,24 @@
if(res.code !=200){
row.active_status = !row.active_status;
}
delete row.$switch_status;
delete row.$switch_yx;
}, 500);
},
//
upSearch(){
this.$refs.table.upData(this.search)
this.$refs.table.upData(this.params)
},
//
handleSuccess(data, mode){
if(mode=='add'){
data.id = new Date().getTime()
this.$refs.table.tableData.unshift(data)
this.$refs.table.refresh();
}else if(mode=='edit'){
this.$refs.table.tableData.filter(item => item.id===data.id ).forEach(item => {
Object.assign(item, data)
})
}
this.$refs.table.refresh();
}
}
}

View File

@ -0,0 +1,99 @@
<template>
<el-dialog title="重置用户密码" v-model="visible" draggable :width="500">
<el-form :model="form" :rules="rules" :disabled="mode==='show'" ref="dialogForm" label-width="100px"
label-position="right">
<el-form-item label="当前密码" prop="old_pwd">
<el-input v-model="form.old_pwd" type="password" show-password
placeholder="请输入当前密码"></el-input>
</el-form-item>
<el-form-item label="新密码" prop="new_pwd">
<el-input v-model="form.new_pwd" type="password" show-password placeholder="请输入新密码"></el-input>
<sc-password-strength v-model="form.new_pwd"></sc-password-strength>
<div class="el-form-item-msg">请输入包含英文数字的8位以上密码</div>
</el-form-item>
<el-form-item label="确认新密码" prop="conf_pwd">
<el-input v-model="form.conf_pwd" type="password" show-password
placeholder="请再次输入新密码"></el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible=false"> </el-button>
<el-button v-if="mode!=='show'" type="primary" :loading="isSave" @click="submit()"> </el-button>
</template>
</el-dialog>
</template>
<script>
import scPasswordStrength from '@/components/scPasswordStrength'
export default {
emits: ['success', 'closed'],
components: {
scPasswordStrength
},
data() {
return {
form: {
old_pwd:"",
new_pwd: "",
conf_pwd: "",
id: ""
},
mode: "add",
show: false,
isSave: false,
visible: false,
rules: {
old_pwd: [
{required: true, message: '请输入当前密码'}
],
new_pwd: [
{required: true, message: '请输入新密码'}
],
conf_pwd: [
{required: true, message: '请再次输入新密码'},
{
validator: (rule, value, callback) => {
if (value !== this.form.new_pwd) {
callback(new Error('两次输入密码不一致'));
} else {
callback();
}
}
}
]
}
}
},
methods: {
open(mode = 'add', id) {
this.form.id = id;
this.mode = mode;
this.visible = true;
this.show = true;
return this
},
submit() {
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
const reqData = {
user_id: this.form.id,
old_pwd:this.form.old_pwd,
conf_pwd: this.form.conf_pwd
};
const res = await this.$API.user.editPass.post(reqData);
if (res.code === 200) {
this.visible = false;
this.$message.success("密码重置成功")
}
} else {
return false;
}
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,107 @@
<template>
<el-dialog title="分配角色" v-model="visible" draggable :width="500">
<el-form :model="form" :rules="rules" :disabled="mode==='show'" ref="dialogForm" label-width="100px"
label-position="right">
<el-form-item label="头像" prop="avatar">
<ossImgUpload @parentParams="parentParams" :url="form.avatar" />
</el-form-item>
<el-form-item label="登录账号" prop="login_name">
<el-input v-model="form.login_name" placeholder="用于登录系统" clearable :disabled="show"></el-input>
<div class="el-form-item-msg">账号信息用于登录系统不允许修改</div>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入完整的真实姓名" clearable :disabled="show"></el-input>
</el-form-item>
<el-form-item label="所属角色" prop="role_ids">
<el-select v-model="form.role_ids" multiple filterable style="width: 100%">
<el-option v-for="item in groups" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible=false"> </el-button>
<el-button v-if="mode!=='show'" type="primary" :loading="isSave" @click="submit()"> </el-button>
</template>
</el-dialog>
</template>
<script>
export default {
emits: ['success', 'closed'],
data() {
return {
show: false,
isSave: false,
visible: false,
form: {
avatar:"",
user_id: "",
login_name: "",
name: "",
role_ids: []
},
rules: {
role_ids: [
{required: true, message: '请选择所属角色', trigger: 'change'}
]
},
groups: [],
groupsProps: {
value: "id",
multiple: true,
checkStrictly: true
},
}
},
mounted() {
this.getGroup()
},
methods: {
open() {
this.visible = true;
this.show = true;
return this
},
async getGroup() {
const res = await this.$API.system.role.list.get();
if(res.code == 200){
this.groups = res.data.rows;
}
},
//
parentParams(files){
this.form.avatar = files;
},
submit() {
this.$refs.dialogForm.validate(async (valid) => {
if (valid) {
this.isSave = true;
const res = await this.$API.system.user.allocatRole.post(this.form);
if (res.code === 200) {
this.$emit('success', this.form, this.mode)
this.visible = false;
this.$message.success("分配成功")
}
this.isSave = false;
} else {
this.isSave = false;
return false;
}
})
},
setData(data) {
this.form.user_id = data.id
this.form.avatar = data.avatar;
this.form.login_name = data.login_name
this.form.name = data.name
this.form.role_ids = data.group?data.group.role_ids:[]
this.form.mobile = data.mobile
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,22 +1,34 @@
<template>
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" draggable destroy-on-close @closed="$emit('closed')">
<el-form :model="form" :rules="rules" :disabled="mode=='show'" ref="dialogForm" label-width="100px" label-position="right">
<el-form-item label="头像" prop="avatar">
<ossImgUpload @parentParams="parentParams" :url="form.avatar" />
</el-form-item>
<el-form-item label="登录账号" prop="login_name">
<el-input v-model="form.login_name" placeholder="请填写登录账号" clearable></el-input>
<el-input v-model="form.login_name" placeholder="请填写登录账号" :disabled="mode!='add'?true:false" clearable></el-input>
<p class="el-form-item-msg" v-if="mode == 'edit'">账号信息用于登录系统不允许修改</p>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-form-item label="姓名/工号" required>
<el-row :gutter="24" justify="space-between">
<el-col :span="12">
<el-form-item prop="name">
<el-input v-model="form.name" placeholder="请填写真实姓名" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="emp_id">
<el-input v-model="form.emp_id" placeholder="请填写工号" clearable></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="联系电话" prop="mobile">
<el-input v-model="form.mobile" placeholder="请填写联系电话" clearable></el-input>
</el-form-item>
<el-form-item label="电子邮件" prop="email">
<el-input v-model="form.email" placeholder="请填写电子邮件" clearable></el-input>
</el-form-item>
<el-form-item label="登录密码" prop="password">
<el-form-item label="登录密码" prop="password" v-if="mode == 'add'">
<el-input type="password" v-model="form.password" placeholder="请填写密码" clearable show-password></el-input>
</el-form-item>
<el-form-item label="所属部门" prop="dept_id">
@ -53,6 +65,7 @@
id:"",
login_name: "",
name:"",
emp_id:"",
mobile:"",
email:"",
avatar: "",
@ -71,6 +84,15 @@
name: [
{required: true, message: '请输入真实姓名'}
],
emp_id:[
{required: true, message: '请输入工号'}
],
mobile: [
{required: true, message: '请输入联系方式'}
],
email: [
{required: true, message: '请输入邮箱地址'}
],
password: [
{required: true, message: '请输入登录密码'},
{validator: (rule, value, callback) => {
@ -80,7 +102,7 @@
callback();
}}
],
password2: [
password_cnf: [
{required: true, message: '请再次输入密码'},
{validator: (rule, value, callback) => {
if (value !== this.form.password) {
@ -90,10 +112,10 @@
}
}}
],
dept: [
dept_id: [
{required: true, message: '请选择所属部门'}
],
group: [
role_ids: [
{required: true, message: '请选择所属角色', trigger: 'change'}
]
},
@ -110,7 +132,6 @@
checkStrictly: false,
emitPath:false
}
// checkStrictly: false,
}
},
mounted() {
@ -127,11 +148,15 @@
//
async getGroup(){
const res = await this.$API.system.role.list.get();
if(res.code == 200){
this.groups = res.data.rows;
}
},
async getDept(){
const res = await this.$API.system.dept.active.post();
if(res.code == 200){
this.depts = res.data;
}
},
parentParams(item){
this.form.avatar = item;
@ -156,14 +181,16 @@
//
setData(data){
this.form.id = data.id
this.form.userName = data.userName
this.form.avatar = data.avatar
this.form.login_name = data.login_name
this.form.name = data.name
this.form.emp_id = data.emp_id
this.form.mobile = data.mobile
this.form.email = data.email
this.form.avatar = data.avatar
this.form.dept_id = data.dept_id
this.form.group = data.group
this.form.dept = data.dept
this.form.role_ids = data.user_roles && data.user_roles.role_ids?data.user_roles.role_ids:[]
//
//Object.assign(this.form, data)
}
}
}

View File

@ -0,0 +1,246 @@
<template>
<el-container class="mainBox">
<el-header>
<div class="left-panel">
<span class="roleName">{{name}}</span>角色信息
<template v-for="(item,index) in user_roles" :key="index">
<span class="roleTag">
<el-tag class="ml-2" :type="index==1?'success':index==2?'info':index==3?'danger':index==4?'warning':''">{{item}}</el-tag>
</span>
</template>
</div>
<div class="right-panel">
<el-alert title="个人用户权限不可编辑,需要编辑请到到角色编辑对应的权限" type="warning" :closable="false" />
</div>
</el-header>
<el-main class="nopadding">
<div class="treeTable">
<div :class="list.length===0?'thenTitle thenTitleBottom':'thenTitle'">
<div class="tr">
<div class="th module">功能模块</div>
<div class="th check"><el-checkbox :indeterminate="isCheckFun" @change="allCheckChange" :disabled="showPermission" v-model="checkedFun" :size="size" /></div>
<div class="th thFlex">
<div class="menu name">菜单</div>
<div class="th authority">数据操作权限</div>
</div>
</div>
</div>
<div class="tableBody">
<div class="tr" v-for="(item,index) in list" :key="index">
<div class="td module">{{item.meta.title}}</div>
<div class="td check"><el-checkbox v-model="item.checked" :indeterminate="item.isCheck" @change="menuCheckChange(item)" :disabled="showPermission" :size="size" /></div>
<div class="td tdChild">
<div class="nextTd" v-for="(em,ind) in item.children" :key="ind">
<div class="tdName menu">
<el-checkbox @change="moduleCheckChange(item,em)" :indeterminate="em.isCheck" v-model="em.checked" :disabled="showPermission" :size="size">{{em.meta.title}}</el-checkbox>
</div>
<div class="tdName authority">
<div class="childTr">
<div class="preBox" v-for="(li,lidex) in em.meta.data_permission" :key="lidex">
<el-checkbox @change="checkChange(item,em,li)" v-model="li.checked" :disabled="showPermission" :size="size">{{li.title}}</el-checkbox>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</el-main>
</el-container>
</template>
<script>
export default {
name: "view-permission",
data(){
return{
size:'default',
id: this.$route.query.id,
name:this.$route.query.name,
user_roles:[],
list:[],
showPermission:false
}
},
computed:{
isCheckFun(){
let isTrue = false;
let num = this.list.length;
let checkNum = this.list.filter((item)=>item.checked).length;
let isCheckNum = this.list.filter((item)=>item.isCheck).length;
isTrue = checkNum>0 && checkNum == num?false:checkNum>0 || isCheckNum>0 ? true:false;
return isTrue
},
checkedFun(){
let isTrue = false;
let num = this.list.length;
let checkNum = this.list.filter((item)=>item.checked).length;
isTrue = checkNum>0 && checkNum == num?true:false;
return isTrue
}
},
mounted() {
this.getPermission();
},
methods:{
async getPermission() {
let params = {
user_id:this.id
}
const res = await this.$API.system.user.userPermission.post(params);
this.user_roles = res.data.role;
res.data.menu.forEach(item=>{
if(item.children){
item.children.forEach(em=>{
if(em.meta.data_permission){
let check = em.meta.data_permission.filter((li)=>li.checked).length;
let ed = em.meta.data_permission.length;
em.isCheck = check>0 && check != ed?true:false;
if(ed>0){
em.checked = check>0 && check== ed?true:false;
}
}
})
let check = item.children.filter((em)=>em.checked).length;
let isCheck = item.children.filter((em)=>em.isCheck).length;
let ed = item.children.length;
item.isCheck = (check>0 && check != ed) || (isCheck>0 && check !=ed)?true:false;
item.checked = check>0 && check== ed?true:false;
}
})
this.list = res.data.menu;
},
allCheckChange(){
return
},
menuCheckChange(em){
em.checked = !em.checked;
return
},
moduleCheckChange(_a,em){
em.checked = !em.checked;
return
},
checkChange(_a,_b,em){
em.checked = !em.checked;
return
}
}
}
</script>
<style lang="scss" scoped>
.nopadding{
padding: 10px 0;
}
.module{
flex-basis: 120px;
display: flex;
align-items: center;
justify-content: center;
}
.check{
flex-basis: 60px;
display: flex;
align-items: center;
justify-content: center;
}
.menu{
flex-basis: 180px;
}
.authority{
flex:1;
text-align: center;
}
.treeTable{
border: 1px solid var(--el-border-color-light);
}
.thenTitle .tr {
display: flex;
align-items: stretch;
border-bottom:1px solid var(--el-border-color-light);
height: 40px;
background: var(--el-bg-color-overlay);
.th{
padding: 0 10px;
border-left: 1px solid var(--el-border-color-light);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.th:first-child{
border-left: none;
}
.thFlex{
display: flex;
flex: 1;
padding: 0;
.name{
flex-basis: 180px;
padding: 10px;
}
}
}
.thenTitleBottom .tr{
border-bottom: 0;
}
.tableBody .tr{
display: flex;
align-items: stretch;
justify-content: space-between;
border-bottom:1px solid var(--el-border-color-light);
.td{
padding: 0 10px;
border-left: 1px solid var(--el-border-color-light);
.nextTd{
display: flex;
align-items: center;
border-bottom:1px solid var(--el-border-color-light);
}
.nextTd:last-child{
border-bottom: 0;
}
}
.td:first-child{
border-left: 0;
}
.tdChild{
flex: 1;
padding: 0;
border-left: 1px solid var(--el-border-color-light);
.tdName:last-child{
border-left: 1px solid var(--el-border-color-light);
}
.tdName{
padding: 0 10px;
min-height: 33px;
}
.childTr{
display: flex;
flex-wrap: wrap;
flex: 1;
.preBox{
display: flex;
align-items: center;
flex-wrap: wrap;
margin-right: 20px;
width: 110px;
}
}
}
}
.tableBody .tr:last-child{
border-bottom: 0;
}
.roleName{
color: var(--el-color-primary);
margin-right: 10px;
}
.roleTag{
margin-right: 10px;
}
</style>