fix 角色授权模式修改,数据权限修改

This commit is contained in:
yxh 2024-04-12 17:14:34 +08:00
parent a7fc7b583d
commit f69356a4b6
16 changed files with 597 additions and 181 deletions

8
package-lock.json generated
View File

@ -19,7 +19,7 @@
"echarts": "^5.4.2",
"echarts-gl": "^2.0.9",
"echarts-wordcloud": "^2.1.0",
"element-plus": "^2.3.3",
"element-plus": "^2.6.3",
"js-cookie": "^3.0.1",
"jsplumb": "^2.15.6",
"lodash": "^4.17.21",
@ -2243,9 +2243,9 @@
"peer": true
},
"node_modules/element-plus": {
"version": "2.4.3",
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.4.3.tgz",
"integrity": "sha512-b3q26j+lM4SBqiyzw8HybybGnP2pk4MWgrnzzzYW5qKQUgV6EG1Zg7nMCfgCVccI8tNvZoTiUHb2mFaiB9qT8w==",
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.6.3.tgz",
"integrity": "sha512-U4L/mr+1r+EmAUYUHrs0V/8hHMdBGP07rPymSC72LZCN4jK1UwygQYICegTQ5us4mxeqBvW6wfoEfo003fwCqw==",
"dependencies": {
"@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.3.1",

View File

@ -20,7 +20,7 @@
"echarts": "^5.4.2",
"echarts-gl": "^2.0.9",
"echarts-wordcloud": "^2.1.0",
"element-plus": "^2.3.3",
"element-plus": "^2.6.3",
"js-cookie": "^3.0.1",
"jsplumb": "^2.15.6",
"lodash": "^4.17.21",

View File

@ -57,13 +57,20 @@ export function dataScope(data:any) {
})
}
export function setRoleUsers(data:any) {
return request({
url: '/api/v1/system/role/setRoleUser',
method: 'put',
data:data
})
}
// 根据角色ID查询部门树结构
export function roleDeptTreeSelect(roleId:number) {
export function roleDeptTreeSelect() {
return request({
url: '/api/v1/system/role/deptTreeSelect',
method: 'get',
params:{roleId}
method: 'get'
})
}

View File

@ -19,6 +19,15 @@ export function getUserList(query:Object) {
})
}
export function getUsersById(roleId:number) {
return request({
url: '/api/v1/system/user/getByRoleId',
method: 'get',
params:{roleId}
})
}
export function getUserSelector(query:Object) {
return request({
url: '/api/v1/system/user/selector',

View File

@ -1,14 +1,6 @@
<template>
<el-row :gutter="10" style="width: 100%;" v-if="multiple">
<el-col :span="6">
<el-form-item>
<el-button size="default" type="success" class="ml10" @click="confirmUser">确定选取</el-button>
</el-form-item>
</el-col>
</el-row>
<div class="system-user-list-container" style="min-height: 600px;">
<el-table :data="tableData.data" style="width: 100%" v-if="!multiple">
<el-table :data="tableData.data" style="width: 100%" >
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="userNickname" label="姓名" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="100" >
@ -17,11 +9,6 @@
</template>
</el-table-column>
</el-table>
<el-table ref="tableMultipleRef" :data="tableData.data" style="width: 100%" @selection-change="handleSelectionChange" v-else>
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="userNickname" label="姓名" show-overflow-tooltip></el-table-column>
</el-table>
<pagination
v-show="tableData.total>0"
:total="tableData.total"
@ -33,9 +20,8 @@
</template>
<script lang="ts">
import {toRefs, reactive, onMounted, ref, defineComponent, getCurrentInstance} from 'vue';
import {ElMessageBox, ElMessage} from 'element-plus';
import {getUserSelector} from '/@/api/system/user/index';
import {toRefs, reactive, defineComponent, getCurrentInstance} from 'vue';
import {getUserSelector} from '/@/api/system/user';
interface TableDataState {
ids:number[];
@ -72,10 +58,6 @@ export default defineComponent({
genderData:{
type:Array,
default:()=>[]
},
multiple:{
type:Boolean,
default:false
}
},
emits:['ok'],
@ -83,7 +65,6 @@ export default defineComponent({
setup(prop,{emit}) {
const {proxy,props} = <any>getCurrentInstance();
const {sys_user_sex} = proxy.useDict('sys_user_sex')
const tableMultipleRef = ref();
const state = reactive<TableDataState>({
ids:[],
userItem:[],
@ -113,44 +94,15 @@ export default defineComponent({
getUserSelector(param).then((res:any)=>{
state.tableData.data = res.data.userList??[];
state.tableData.total = res.data.total;
toggleSelection()
});
};
const toggleSelection = (rows?: any) => {
if (rows) {
rows.forEach((row) => {
tableMultipleRef.value!.toggleRowSelection(row, undefined)
})
} else {
tableMultipleRef.value!.clearSelection()
}
}
const confirmUser = () => {
let userItem:any[] = [];
userItem = state.userItem
if(userItem.length===0){
ElMessage.error('请勾选用户');
return
}else{
emit("ok",userItem);
}
};
//
const handleSelectionChange = (selection:any[])=> {
state.ids = selection.map(item => item.id)
state.userItem = selection.map(item => item)
};
const onOpenSelectUser = (row:any) => {
emit("ok",row);
}
return {
sys_user_sex,
setUserList,
handleSelectionChange,
onOpenSelectUser,
confirmUser,
tableMultipleRef,
...toRefs(state),
};
},

View File

@ -1,6 +1,6 @@
<template>
<div>
<el-dialog title="选择用户" v-model="visible" width="60%" top="5vh" append-to-body :close-on-click-modal="false">
<el-dialog title="选择用户" v-model="visible" width="80%" top="5vh" append-to-body :close-on-click-modal="false">
<div class="system-user-container">
<el-row :gutter="10" style="width: 100%;">
<el-col :span="6">
@ -21,7 +21,7 @@
</el-aside>
</el-card>
</el-col>
<el-col :span="18">
<el-col :span="12">
<el-card shadow="hover">
<div class="system-user-search mb15">
<el-form :model="param" ref="queryRef" :inline="true" label-width="68px">
@ -64,6 +64,32 @@
<UserList ref="userListRef" :dept-data="deptData" :gender-data="sys_user_sex" :param="param" :multiple="multiple" @ok="handleSelectUserOk"/>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover">
<el-row :gutter="10">
<el-col :span="10">
<p style="height: 32px;line-height: 32px;">已选择{{selectedUsers.length}}</p>
</el-col>
<el-col :span="7">
<el-button type="success" plain @click="goBack">确认返回</el-button>
</el-col>
<el-col :span="7">
<el-button type="danger" plain @click="removeAll">全部移除</el-button>
</el-col>
<el-col :span="24">
<el-table :data="selectedUserInfo">
<el-table-column label="操作" >
<template #default="scope">
<el-button type="danger" plain @click="remove(scope.$index)">移除</el-button>
</template>
</el-table-column>
<el-table-column prop="userNickname" label="姓名" />
</el-table>
</el-col>
</el-row>
<el-pagination layout="prev, pager, next" :total="selectedUsers.length" v-model:current-page="selectedUsersPage"/>
</el-card>
</el-col>
</el-row>
</div>
</el-dialog>
@ -71,7 +97,7 @@
</template>
<script lang="ts">
import {toRefs, reactive, ref, defineComponent, watch, getCurrentInstance, nextTick} from 'vue';
import {toRefs, reactive, ref, defineComponent, watch, getCurrentInstance, nextTick, computed} from 'vue';
import {ElTree,FormInstance} from 'element-plus';
import { Search } from '@element-plus/icons-vue'
import UserList from './component/userList.vue';
@ -97,10 +123,15 @@ export default defineComponent({
multiple:{
type:Boolean,
default:false
},
selectedUsers:{
type:Array,
default:()=>[]
}
},
emits:['selectUser'],
emits:['selectUser','okBack'],
setup(prop,{emit}) {
const selectedUsersPage = ref(1)
const visible = ref(false)
const {proxy} = <any>getCurrentInstance();
const {sys_user_sex} = proxy.useDict('sys_user_sex')
@ -125,6 +156,16 @@ export default defineComponent({
dateRange:[]
},
});
const selectedUserInfo = computed({
get:()=>{
let start = (selectedUsersPage.value-1)*10
let end = start+10
return prop.selectedUsers.slice(start,end)
} ,
set:(v)=>{
emit("selectUser",v);
}
});
const getUserList = ()=>{
userListRef.value.setUserList();
};
@ -161,10 +202,24 @@ export default defineComponent({
})
}
const handleSelectUserOk = (row:any)=>{
selectedUserInfo.value = [...selectedUserInfo.value,row]
}
const goBack = ()=>{
visible.value = false;
emit("selectUser",row);
emit("okBack");
}
const removeAll = ()=>{
selectedUserInfo.value = []
}
const remove = (index:number)=>{
index = (selectedUsersPage.value-1)*10+index
let newSel:any = [...selectedUserInfo.value]
selectedUserInfo.value = []
newSel.splice(index,1)
selectedUserInfo.value = newSel
}
return {
selectedUsersPage,
visible,
queryRef,
userListRef,
@ -173,11 +228,15 @@ export default defineComponent({
treeRef,
search,
sys_user_sex,
selectedUserInfo,
openDialog,
getUserList,
handleSelectUserOk,
handleNodeClick,
resetQuery,
goBack,
removeAll,
remove,
...toRefs(state),
};
},

View File

@ -20,12 +20,9 @@
<img w-full :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
</div>
<div v-else>
<div class="up-img">
<div class="up-img" v-else>
<el-upload
v-model:file-list="dataFileList"
:limit="limit"
class="avatar-uploader"
:action="action"
:show-file-list="false"
@ -39,7 +36,6 @@
<el-icon v-else class="avatar-uploader-icon"><ele-Plus /></el-icon>
</el-upload>
</div>
</div>
</template>
@ -90,6 +86,10 @@ export default defineComponent({
return item
})
uploadedFile = _.cloneDeep(value)
if(props.limit == 1){
uploadedFile = [];
imageUrl.value = (value[0]?value[0].url:'') as string;
}
return value
},
set: val => {

View File

@ -12,7 +12,7 @@ import 'element-plus/dist/index.css';
import '/@/theme/index.scss';
import mitt from 'mitt';
import VueGridLayout from 'vue-grid-layout';
import {getUpFileUrl, handleTree, parseTime, selectDictLabel} from '/@/utils/gfast';
import {findChildrenByPid, flattenTree, getUpFileUrl, handleTree, parseTime, selectDictLabel} from '/@/utils/gfast';
import Websocket from '/@/utils/websocket';
import {useDict} from '/@/api/system/dict/data';
import {getItems, setItems, getOptionValue, isEmpty} from '/@/api/items'
@ -53,6 +53,8 @@ app.use(pinia)
app.config.globalProperties.getUpFileUrl=getUpFileUrl
app.config.globalProperties.handleTree=handleTree
app.config.globalProperties.flattenTree=flattenTree
app.config.globalProperties.findChildrenByPid=findChildrenByPid
app.config.globalProperties.useDict=useDict
app.config.globalProperties.selectDictLabel=selectDictLabel

View File

@ -80,6 +80,33 @@ export function handleTree(data:any[], id:string, parentId:string, children:stri
return treeData != '' ? treeData : data;
}
export function flattenTree(treeArray:any[]):any[] {
const result:any[] = [];
function flatten(node:any) {
result.push(node);
if (node.children && node.children.length > 0) {
node.children.forEach((child:any[]) => flatten(child));
}
}
treeArray.forEach(node => flatten(node));
return result;
}
export function findChildrenByPid(pid:any, flattenedArray :any[]):any[] {
const result:any[] = [];
flattenedArray.forEach(node => {
if (node.pid === pid) {
result.push(node);
const grandchildren = findChildrenByPid(node.id, flattenedArray);
if (grandchildren.length > 0) {
result.push(...grandchildren);
}
}
});
return result;
}
// 回显数据字典
export function selectDictLabel(data:any[], value:string):string {

View File

@ -40,7 +40,7 @@ service.interceptors.response.use(
ElMessageBox.alert('登录状态已过期,请重新登录', '提示', {confirmButtonText:'确定'})
.then(() => {
Session.clear(); // 清除浏览器全部临时缓存
window.location.href = '/'; // 去登录页
window.location.href = import.meta.env.BASE_URL; // 去登录页
})
.catch(() => {});
} else if (code !== 0) {

View File

@ -68,13 +68,13 @@
</template>
</el-dialog>
</div>
<select-user ref="selectUserRef" @selectUser="confirmUser" :multiple="true"></select-user>
<select-user ref="selectUserRef" @selectUser="confirmUser" :selectedUsers="deptUser"></select-user>
</template>
<script lang="ts">
import {reactive, toRefs, defineComponent, getCurrentInstance,ref,unref} from 'vue';
import {addDept,editDept, getDeptList} from "/@/api/system/dept";
import {getUserByIds} from '/@/api/system/user/index';
import {getUserByIds} from '/@/api/system/user';
import {ElMessage} from "element-plus";
import selectUser from "/@/components/selectUser/index.vue"
@ -208,18 +208,23 @@ export default defineComponent({
const handleClose = (data:any,key:number) => {
deptUser.value.splice(key, 1);
state.ruleForm.leader = deptUser.value.map(item => item.id)
state.ruleForm.leader = deptUser.value.map((item:any) => item.id)
};
const confirmUser = (data:any[]) => {
let leaderArr = state.ruleForm.leader??[];
data.map(function (item) {
if(data.length>0){
data.map((item:any)=>{
//
if (!leaderArr.includes(item.id)){
deptUser.value.push(item)
deptUser.value.push(item as never)
leaderArr.push(item.id)
}
});
})
state.ruleForm.leader = leaderArr;
}else{
deptUser.value = []
state.ruleForm.leader = []
}
};
//
const handleSelectUser = () =>{

View File

@ -71,9 +71,19 @@
</template>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" >
<el-form-item label="权限标识">
<el-select v-model="ruleForm.roles" multiple placeholder="选择角色" clearable class="w100">
<el-option v-for="role in roles" :key="'role_'+role.id" :label="role.name" :value="role.id"></el-option>
</el-select>
<el-cascader
:options="roles"
:props="{ checkStrictly: true,emitPath: false, value: 'id', label: 'name',multiple: true }"
placeholder="请选择角色"
clearable
class="w100"
v-model="ruleForm.roles"
>
<template #default="{ node, data }">
<span>{{ data.name }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" >
@ -213,7 +223,8 @@ export default defineComponent({
nextTick(()=>{
//
getMenuParams().then((res:any)=>{
state.roles = res.data.roles;
const roles = res.data.roles??[];
state.roles = proxy.handleTree(roles??[], "id","pid","children",true);
const menu = { id: 0, title: '主类目', children: [] };
menu.children = proxy.handleTree(res.data.menus, "id","pid");
state.menuData=new Array(menu) as any;

View File

@ -8,7 +8,7 @@
<div class="personal-user-left">
<el-upload
class=" h100 personal-user-left-upload avatar-uploader"
:action="baseURL+'/api/v1/system/upload/singleImg'"
:action="baseURL+'api/v1/system/upload/singleImg'"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:data="dataParam"

View File

@ -1,28 +1,71 @@
<template>
<div class="system-sysJob-edit">
<!-- 分配角色数据权限对话框 -->
<el-dialog title="数据权限设置" v-model="openDataScope" width="769px" append-to-body :close-on-click-modal="false">
<el-dialog title="数据权限设置" v-model="openDataScope" width="90%" append-to-body :close-on-click-modal="false">
<el-alert title="注:此功能界面需要与代码查询条件配合使用,并非所有接口都需设置数据权限,多用于业务模块!" :closable="false" type="warning" style="margin-bottom: 12px;"/>
<el-form ref="formRef" :model="form" label-width="80px">
<el-form-item label="角色名称">
<el-input v-model="form.roleName" :disabled="true" />
</el-form-item>
</el-form>
<el-table ref="tableRef" :data="menuTableData" style="width: 100%" row-key="path" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="菜单名称" >
<template #default="scope">
<SvgIcon :name="scope.row.icon" />
<span class="ml10">{{ scope.row.title }}</span>
</template>
</el-table-column>
<el-table-column label="api接口" >
<template #default="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-form-item label="权限范围">
<el-select v-model="form.dataScope">
<el-option
v-for="item in dataScopeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据权限" v-show="form.dataScope == 2">
<el-table-column label="类型" show-overflow-tooltip width="80">
<template #default="scope">
<el-tag :type="scope.row.menuType===0?'danger':(scope.row.menuType===1?'success':'warning')"
size="small">{{scope.row.menuType===0?'目录':(scope.row.menuType===1?'菜单':'按钮') }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="600">
<template #header>
<el-radio-group v-model="optionsActionValue" @change="setOptionsActionValueHandle">
<template v-for="item in dataScopeOptions" :key="item.value">
<el-radio v-if="item.value!='2'" :label="item.value" >{{item.label}}</el-radio>
</template>
</el-radio-group>
</template>
<template #default="scope">
<div class="option-con">
<el-radio-group v-model="menuAuthData[scope.row.id]">
<template v-for="item in dataScopeOptions" :key="item.value">
<el-radio :label="item.value" @change="setOptionsItemHandle(item.value,scope.row.id)">
<el-badge v-if="item.value=='2' && menuAuthData[scope.row.id]=='2'" type="success" :value="getDeptLen(scope.row.id)" :max="99" class="item" :show-zero="false">{{item.label}}</el-badge>
<span v-else>{{item.label}}</span>
</el-radio>
</template>
</el-radio-group>
<el-link type="primary" @click="openSelDeptHandler(scope.row.id)" :underline="false" v-show="menuAuthData[scope.row.id] && menuAuthData[scope.row.id]=='2'">选择部门</el-link>
</div>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDataScope"> </el-button>
<el-button @click="cancelDataScope"> </el-button>
</div>
</template>
</el-dialog>
<!-- 选择部门对话框 -->
<el-dialog title="选择部门" v-model="openSelDept" width="800px" append-to-body :close-on-click-modal="false">
<el-row :gutter="35">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event)">展开/折叠</el-checkbox>
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event)">全选/全不选</el-checkbox>
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event)">父子联动</el-checkbox>
<el-checkbox v-model="deptCheckStrictly" @change="handleCheckedTreeConnect($event)">父子联动</el-checkbox>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-tree
@ -32,17 +75,16 @@
default-expand-all
ref="deptRef"
node-key="deptId"
:check-strictly="!form.deptCheckStrictly"
:check-strictly="!deptCheckStrictly"
:props="deptProps"
></el-tree>
</el-col>
</el-row>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDataScope"> </el-button>
<el-button @click="cancelDataScope"> </el-button>
<el-button type="primary" @click="submitDept"> </el-button>
<el-button type="success" @click="submitSonMenuDept">确定并应用到子菜单</el-button>
<el-button @click="cancelDept"> </el-button>
</div>
</template>
</el-dialog>
@ -50,13 +92,23 @@
</template>
<script lang="ts">
import {defineComponent, reactive, ref} from "vue";
import {dataScope, getRole, roleDeptTreeSelect} from "/@/api/system/role";
import {defineComponent, getCurrentInstance, nextTick, reactive, ref} from "vue";
import {dataScope, getRole, roleDeptTreeSelect, roleMenuTreeSelect} from "/@/api/system/role";
import {ElMessage} from "element-plus/es";
import {findChildrenByPid, flattenTree} from "/@/utils/gfast";
import * as events from "events";
export default defineComponent({
name: "dataScope",
computed: {
events() {
return events
}
},
setup(props,{emit}){
const tableRef = ref()
const openSelDept = ref(false);
const {proxy} = getCurrentInstance() as any;
const openDataScope = ref(false)
const deptExpand = ref(true)
const deptNodeAll = ref(false)
@ -64,6 +116,9 @@ export default defineComponent({
const menuOptions = ref([])
const deptRef = ref();
const formRef = ref();
const deptCheckStrictly = ref(false)
const optionsActionValue = ref("0")
const setDeptId = ref(0)
const deptProps = ref({
children: "children",
label: "deptName"
@ -71,33 +126,39 @@ export default defineComponent({
//
const dataScopeOptions = ref([
{
value: "1",
label: "全部数据权限"
value: 1,
label: "全部"
},
{
value: "2",
label: "自定数据权限"
value: 3,
label: "本部门"
},
{
value: "3",
label: "本部门数据权限"
value: 4,
label: "本部门及以下"
},
{
value: "4",
label: "本部门及以下数据权限"
value: 5,
label: "仅本人"
},
{
value: "5",
label: "仅本人数据权限"
value: 2,
label: "自定义"
}
])
const menuAuthData = ref([])
const deptAuthData = ref([])
const form = reactive({
roleId:undefined,
roleName:'',
dataScope:'3',
deptCheckStrictly: false,
authData:[{
menuId:'0',
scope:'0',
deptIds:[]
}]
})
const menuTableData = ref([])
const menuTableList = ref([])
// /
const handleCheckedTreeExpand = (value:any) => {
let treeList = deptOptions.value;
@ -111,12 +172,21 @@ export default defineComponent({
}
/** 树权限(父子联动) */
const handleCheckedTreeConnect = (value:any) => {
form.deptCheckStrictly = value ? true : false;
deptCheckStrictly.value = value ? true : false;
}
/** 提交按钮(数据权限) */
const submitDataScope = () => {
if (form.roleId != undefined) {
form.deptIds = getDeptAllCheckedKeys();
form.authData = []
//
let rows = tableRef.value.getSelectionRows()
rows.map((item:any)=>{
let index = item.id
form.authData.push({
menuId:index,
scope:menuAuthData.value[index],
deptIds:deptAuthData.value[index]??[]
})
})
dataScope(form).then((response:any) => {
if (response.code === 0) {
ElMessage.success("设置成功");
@ -126,32 +196,83 @@ export default defineComponent({
ElMessage.error("设置失败")
}
});
}
}
const cancelDataScope = () => {
closeDialog();
};
const submitDept = ()=>{
deptAuthData.value[setDeptId.value] = getDeptAllCheckedKeys() as never;
cancelDept()
}
const submitSonMenuDept = ()=>{
const checkedDeptId = getDeptAllCheckedKeys() as never;
deptAuthData.value[setDeptId.value] = getDeptAllCheckedKeys() as never;
//
const children = proxy.findChildrenByPid(setDeptId.value,menuTableList.value)
children.map((item:any)=>{
deptAuthData.value[item.id] = getDeptAllCheckedKeys() as never;
})
cancelDept()
}
const cancelDept = () => {
deptCheckStrictly.value= false
openSelDept.value = false
};
//
const openDialog = (row: any) => {
openDataScope.value = true;
roleDeptTreeSelect().then(response => {
deptOptions.value = response.data.depts||[];
});
resetForm();
if(row) {
getRole(row.id).then((res:any)=>{
if(res.data.role){
form.roleName = res.data.role.name;
form.roleId = res.data.role.id;
form.dataScope=res.data.role.dataScope.toString();
}
})
getRoleDeptTreeselect(row.id)
getMenuTreeselect(row.id)
}
openDataScope.value = true;
};
/** 根据角色ID查询部门树结构 */
const getRoleDeptTreeselect = (roleId:number) =>{
roleDeptTreeSelect(roleId).then(response => {
deptOptions.value = response.data.depts||[];
deptRef.value.setCheckedKeys(response.data.checkedKeys, true);
});
const getRoleDeptTreeselect = (menuId:any) =>{
nextTick(()=>{
deptRef.value?.setCheckedKeys([], false)
if(deptAuthData.value[menuId]){
deptRef.value.setCheckedKeys(deptAuthData.value[menuId], true);
}
})
}
const getMenuTreeselect = (roleId:number) =>{
roleMenuTreeSelect(roleId).then(res=>{
menuTableData.value = proxy.handleTree(res.data.rules??[], "id","pid");
menuTableList.value = proxy.flattenTree(menuTableData.value)
const menuData:any = []
const deptData:any = []
const rows:never[] = []
if(res.data.dataScope){
res.data.dataScope.map((item:any)=>{
menuData[item.menuId] = item.dataScope
deptData[item.menuId] = item.deptIds
})
menuAuthData.value = menuData
deptAuthData.value = deptData
//
menuTableList.value.map((item:any)=>{
if(menuAuthData.value[item.id]){
rows.push(item as never)
}
})
nextTick(()=>{
//
rows.map((item:any)=>{
tableRef.value.toggleRowSelection(item,true)
})
})
}
})
}
//
const closeDialog = () => {
@ -166,26 +287,81 @@ export default defineComponent({
const resetForm = ()=>{
form.roleId=undefined
form.roleName=''
form.dataScope='3'
form.deptCheckStrictly= false
form.deptIds=[]
form.authData = []
deptCheckStrictly.value= false
menuAuthData.value = []
deptAuthData.value = []
};
const handleSelectionChange = (val: any[]) => {
}
const setOptionsActionValueHandle = (value:any)=>{
//
menuTableList.value.map((item:any)=>{
menuAuthData.value[item.id] = value as never
})
}
const setOptionsItemHandle = (value:any,id:any)=>{
const children = proxy.findChildrenByPid(id,menuTableList.value)
//
menuTableList.value.some((item:any)=>{
if(item.id == id){
children.unshift(item)
return true
}
return false
})
children.map((item:any)=>{
tableRef.value.toggleRowSelection(item,true)
})
//
children.map((item:any)=>{
menuAuthData.value[item.id] = value as never
})
}
const openSelDeptHandler = (id:any)=>{
openSelDept.value = true
setDeptId.value = id
getRoleDeptTreeselect(id)
}
const getDeptLen = (id:any)=>{
if(deptAuthData.value[id]){
return (<Array<any>>deptAuthData.value[id]).length
}
return 0
}
return {
tableRef,
openSelDept,
openDialog,
dataScopeOptions,
deptExpand,
openDataScope,
deptNodeAll,
deptOptions,
deptCheckStrictly,
deptProps,
menuOptions,
deptRef,
formRef,
optionsActionValue,
cancelDataScope,
submitDataScope,
handleCheckedTreeExpand,
handleCheckedTreeNodeAll,
handleCheckedTreeConnect,
menuTableData,
handleSelectionChange,
setOptionsActionValueHandle,
menuAuthData,
setOptionsItemHandle,
openSelDeptHandler,
cancelDept,
submitDept,
submitSonMenuDept,
deptAuthData,
setDeptId,
getDeptLen,
form
}
}
@ -205,4 +381,14 @@ export default defineComponent({
padding: 5px;
}
}
.action{
margin-top: 5px;
}
.option-con{
display: flex;
height: 40px;
.el-link{
margin-left: 30px;
}
}
</style>

View File

@ -40,6 +40,53 @@
<el-input v-model="formData.remark" type="textarea" placeholder="请输入角色描述" maxlength="150"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" >
<el-form-item label="有效时间">
<el-radio-group v-model="formData.effectiveType">
<el-radio :label="0">不设置</el-radio>
<el-radio :label="1">按起止日期</el-radio>
<el-radio :label="2">按时间段</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-show="formData.effectiveType===2">
<el-form-item label="每周">
<el-checkbox-group v-model="formData.weekDay">
<el-checkbox :label="1" >周一</el-checkbox>
<el-checkbox :label="2" >周二</el-checkbox>
<el-checkbox :label="3" >周三</el-checkbox>
<el-checkbox :label="4" >周四</el-checkbox>
<el-checkbox :label="5" >周五</el-checkbox>
<el-checkbox :label="6" >周六</el-checkbox>
<el-checkbox :label="0" >周日</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-show="formData.effectiveType===2">
<el-form-item label="时间段" style="width: 360px;">
<el-time-picker
v-model="formData.dayRange"
is-range
format="HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="截止时间"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-show="formData.effectiveType===1">
<el-form-item label="起止日期" style="width: 450px">
<el-date-picker
v-model="formData.dateRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" >
<el-form-item label="菜单权限">
<el-row :gutter="35">
@ -95,6 +142,10 @@ interface DialogRow {
listOrder: number;
remark: string;
menuIds:Array<number>
effectiveType:number;
weekDay:Array<number>;
dayRange:Array<string>;
dateRange:Array<string>;
}
interface RoleState {
loading:boolean;
@ -135,6 +186,13 @@ export default defineComponent({
listOrder: 0,
remark: '',
menuIds:[],
effectiveType:0,
weekDay:[1,2,3,4,5],
dayRange:[
'2024-02-01 08:00:00',
'2024-02-01 19:00:00',
],
dateRange:[],
},
//
rules: {
@ -160,6 +218,9 @@ export default defineComponent({
getRole(row.id).then((res:any)=>{
if(res.data.role){
state.formData = res.data.role;
if(!state.formData.weekDay){
state.formData.weekDay = [1,2,3,4,5]
}
state.formData.menuIds = res.data.menuIds??[]
}
})
@ -229,6 +290,13 @@ export default defineComponent({
listOrder: 0,
remark: '',
menuIds:[],
effectiveType:0,
weekDay:[1,2,3,4,5],
dayRange:[
'2024-02-01 08:00:00',
'2024-02-01 19:00:00',
],
dateRange:[]
}
};
/** 树权限(展开/折叠)*/

View File

@ -51,7 +51,18 @@
<el-table-column label="操作" width="220">
<template #default="scope">
<el-button size="small" text type="primary" @click="onOpenEditRole(scope.row)"><el-icon><ele-EditPen /></el-icon>修改</el-button>
<el-button size="small" text type="primary" @click="handleDataScope(scope.row)"><el-icon><ele-Avatar /></el-icon>数据权限</el-button>
<el-dropdown class="auth-action" @command="handleCommand">
<span class="el-dropdown-link">
授权 <el-icon><ele-ArrowDown /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu class="auth-action-menu">
<el-dropdown-item :command="'resource_'+scope.row.id">资源权限</el-dropdown-item>
<el-dropdown-item :command="'data_'+scope.row.id">数据权限</el-dropdown-item>
<el-dropdown-item :command="'user_'+scope.row.id">用户授权</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button size="small" text type="primary" @click="onRowDel(scope.row)"><el-icon><ele-DeleteFilled /></el-icon>删除</el-button>
</template>
</el-table-column>
@ -59,21 +70,22 @@
</el-card>
<EditRole ref="editRoleRef" @getRoleList="roleList" :roleData="tableData.data"/>
<DataScope ref="dataScopeRef" @getRoleList="roleList"/>
<el-dialog :title="selectRow.name+'-用户列表'" v-model="isShowDialog" width="70vw">
<UserList v-if="isShowDialog" ref="userListRef" :dept-data="deptData" :gender-data="sys_user_sex" :param="userListParam" @getUserList="userList"/>
</el-dialog>
<select-user ref="selectUserRef" @selectUser="confirmUser" @okBack="setRoleUser" :selectedUsers="roleUsers"></select-user>
</div>
</template>
<script lang="ts">
import {toRefs, reactive, onMounted, ref, defineComponent, toRaw,getCurrentInstance} from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
import { ElMessageBox, ElMessage,ElLoading } from 'element-plus';
import EditRole from '/@/views/system/role/component/editRole.vue';
import DataScope from '/@/views/system/role/component/dataScope.vue';
import {deleteRole, getRoleList} from "/@/api/system/role";
import {getDeptTree} from '/@/api/system/user/index';
import {deleteRole, getRoleList, setRoleUsers} from "/@/api/system/role";
import {getDeptTree, getUsersById} from '/@/api/system/user';
import UserList from '/@/views/system/user/component/userList.vue';
import selectUser from "/@/components/selectUser/index.vue";
//
interface TableData {
@ -89,7 +101,7 @@ interface TableData {
}
interface TableDataState {
isShowDialog:boolean;
selectRow:object;
selectRow:any;
deptData:any[];
userListParam: {
roleId:number | undefined;
@ -109,14 +121,18 @@ interface TableDataState {
export default defineComponent({
name: 'apiV1SystemRoleList',
components: {EditRole,DataScope,UserList},
components: {selectUser, EditRole,DataScope,UserList},
setup() {
const selectUserRef = ref()
const {proxy} = getCurrentInstance() as any;
const {sys_user_sex} = proxy.useDict('sys_user_sex')
const addRoleRef = ref();
const userListRef = ref();
const editRoleRef = ref();
const dataScopeRef =ref();
const roleListData = ref<Array<TableData>>()
const roleUsers = ref([])
const setRole = ref(0)
const state = reactive<TableDataState>({
isShowDialog: false,
deptData: [],
@ -157,6 +173,7 @@ export default defineComponent({
createdAt: item.createdAt,
});
})
roleListData.value = data
state.tableData.data = proxy.handleTree(data??[], "id","pid","children",true);
})
};
@ -178,13 +195,23 @@ export default defineComponent({
editRoleRef.value.openDialog();
};
//
const onOpenEditRole = (row: Object) => {
const onOpenEditRole = (row: Object|undefined) => {
editRoleRef.value.openDialog(toRaw(row));
};
//
const handleDataScope=(row:any)=>{
dataScopeRef.value.openDialog(toRaw(row))
}
//
const handleUserScope = ((row:any)=>{
const ld = ElLoading.service()
setRole.value = row.id
getUsersById(row.id).then((res:any)=>{
ld.close()
roleUsers.value=res.data.userList??[]
selectUserRef.value.openDialog()
})
})
//
const onRowDel = (row: any) => {
ElMessageBox.confirm(`此操作将永久删除角色:“${row.name}”,是否继续?`, '提示', {
@ -216,11 +243,54 @@ export default defineComponent({
onMounted(() => {
initTableData();
});
const handleCommand = (command: string )=>{
let commandArr = command.split('_')
let row = roleListData.value?.filter((item:TableData)=>{
return item.id==parseInt(commandArr[1])
})?.[0]
switch (commandArr[0]){
case 'resource':
onOpenEditRole(row)
break
case 'data':
handleDataScope(row)
break
case 'user':
handleUserScope(row)
break
}
}
const confirmUser = (data:any[]) => {
if(data.length>0){
const ids = roleUsers.value.map((item:any)=>{
return item.id
})
console.log('ids = ',ids)
data.map((item:any)=>{
//
if (!ids.includes(item.id)){
roleUsers.value.push(item as never)
}
})
}else{
roleUsers.value = []
}
};
const setRoleUser = ()=>{
const ids = roleUsers.value.map((item:any)=>{
return item.id
})
//
setRoleUsers({roleId:setRole.value,userIds:ids}).then((res:any)=>{
roleList()
})
}
return {
addRoleRef,
editRoleRef,
dataScopeRef,
sys_user_sex,
selectUserRef,
userList,
onOpenUserList,
onOpenAddRole,
@ -230,8 +300,28 @@ export default defineComponent({
onHandleCurrentChange,
roleList,
handleDataScope,
handleUserScope,
handleCommand,
roleUsers,
confirmUser,
setRoleUser,
...toRefs(state),
};
},
});
</script>
<style scoped lang="scss">
.auth-action{
margin:6px 8px 0 8px;
.el-dropdown-link {
cursor: pointer;
color: var(--el-color-primary);
font-size: 12px;
display: flex;
align-items: center;
}
.auth-action-menu{
font-size: 12px;
}
}
</style>