365 lines
12 KiB
Vue
365 lines
12 KiB
Vue
<template>
|
|
<div class="system-edit-role-container">
|
|
<el-dialog :title="(formData.id===0?'添加':'修改')+'角色'" v-model="isShowDialog" width="769px">
|
|
<el-form ref="formRef" :model="formData" :rules="rules" size="default" label-width="90px">
|
|
<el-row :gutter="35">
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" >
|
|
<el-form-item label="上级角色">
|
|
<el-cascader
|
|
:options="roleData"
|
|
:props="{ checkStrictly: true,emitPath: false, value: 'id', label: 'name' }"
|
|
placeholder="请选择上级"
|
|
clearable
|
|
class="w100"
|
|
v-model="formData.pid"
|
|
>
|
|
<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" >
|
|
<el-form-item label="角色名称" prop="name">
|
|
<el-input v-model="formData.name" placeholder="请输入角色名称" clearable></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" >
|
|
<el-form-item label="排序">
|
|
<el-input-number v-model="formData.listOrder" :min="0" controls-position="right" placeholder="请输入排序" class="w100" />
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" >
|
|
<el-form-item label="角色状态">
|
|
<el-switch v-model="formData.status" :active-value="1" :inactive-value="0" inline-prompt active-text="启" inactive-text="禁"></el-switch>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" >
|
|
<el-form-item label="角色描述">
|
|
<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">
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
|
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event)">展开/折叠</el-checkbox>
|
|
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event)">全选/全不选</el-checkbox>
|
|
<el-checkbox v-model="menuCheckStrictly" @change="handleCheckedTreeConnect($event)">父子联动</el-checkbox>
|
|
</el-col>
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" >
|
|
<el-tree
|
|
:data="menuData"
|
|
ref="menuRef"
|
|
:props="menuProps"
|
|
:default-checked-keys="formData.menuIds"
|
|
node-key="id"
|
|
show-checkbox class="menu-data-tree tree-border"
|
|
:check-strictly="!menuCheckStrictly"/>
|
|
</el-col>
|
|
</el-row>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
</el-form>
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="onCancel" size="default">取 消</el-button>
|
|
<el-button type="primary" @click="onSubmit" size="default" :loading="loading">{{formData.id===0?'新 增':'修 改'}}</el-button>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { reactive, toRefs, defineComponent,ref,getCurrentInstance,unref } from 'vue';
|
|
import {addRole, editRole, getRole, getRoleParams} from "/@/api/system/role";
|
|
import {ElMessage} from "element-plus";
|
|
import {refreshBackEndControlRoutes} from "/@/router/backEnd";
|
|
|
|
|
|
// 定义接口来定义对象的类型
|
|
interface MenuDataTree {
|
|
id: number;
|
|
pid:number;
|
|
title: string;
|
|
children?: MenuDataTree[];
|
|
}
|
|
interface DialogRow {
|
|
id:number;
|
|
pid:number;
|
|
name: string;
|
|
status: number;
|
|
listOrder: number;
|
|
remark: string;
|
|
menuIds:Array<number>
|
|
effectiveType:number;
|
|
weekDay:Array<number>;
|
|
dayRange:Array<string>;
|
|
dateRange:Array<string>;
|
|
}
|
|
interface RoleState {
|
|
loading:boolean;
|
|
isShowDialog: boolean;
|
|
formData: DialogRow;
|
|
menuData: Array<MenuDataTree>;
|
|
menuExpand:boolean;
|
|
menuNodeAll:boolean;
|
|
menuCheckStrictly:boolean;
|
|
menuProps: {
|
|
children: string;
|
|
label: string;
|
|
disabled: string;
|
|
};
|
|
rules: object;
|
|
}
|
|
|
|
export default defineComponent({
|
|
name: 'systemEditRole',
|
|
props:{
|
|
roleData:{
|
|
type:Array,
|
|
default:()=>[]
|
|
}
|
|
},
|
|
setup(props,{emit}) {
|
|
const {proxy} = getCurrentInstance() as any;
|
|
const formRef = ref<HTMLElement | null>(null);
|
|
const menuRef = ref();
|
|
const state = reactive<RoleState>({
|
|
loading:false,
|
|
isShowDialog: false,
|
|
formData: {
|
|
id:0,
|
|
pid:0,
|
|
name: '',
|
|
status: 1,
|
|
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: {
|
|
name:[
|
|
{required: true, message: "角色名称不能为空", trigger: "blur"},
|
|
]
|
|
},
|
|
menuData: [],
|
|
menuExpand:false,
|
|
menuNodeAll:false,
|
|
menuCheckStrictly:false,
|
|
menuProps: {
|
|
children: 'children',
|
|
label: 'title',
|
|
disabled:'disabled'
|
|
},
|
|
});
|
|
// 打开弹窗
|
|
const openDialog = (row?: DialogRow) => {
|
|
resetForm();
|
|
getMenuData();
|
|
if(row) {
|
|
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??[]
|
|
}
|
|
})
|
|
}
|
|
state.isShowDialog = true;
|
|
};
|
|
// 关闭弹窗
|
|
const closeDialog = () => {
|
|
state.isShowDialog = false;
|
|
};
|
|
// 取消
|
|
const onCancel = () => {
|
|
closeDialog();
|
|
};
|
|
// 新增
|
|
const onSubmit = () => {
|
|
const formWrap = unref(formRef) as any;
|
|
if (!formWrap) return;
|
|
formWrap.validate((valid: boolean) => {
|
|
if (valid) {
|
|
state.loading = true;
|
|
state.formData.menuIds = getMenuAllCheckedKeys();
|
|
if(state.formData.id===0){
|
|
//添加
|
|
addRole(state.formData).then(()=>{
|
|
ElMessage.success('角色添加成功');
|
|
closeDialog(); // 关闭弹窗
|
|
resetMenuSession()
|
|
emit('getRoleList')
|
|
}).finally(()=>{
|
|
state.loading = false;
|
|
})
|
|
}else{
|
|
//修改
|
|
editRole(state.formData).then(()=>{
|
|
ElMessage.success('角色修改成功');
|
|
closeDialog(); // 关闭弹窗
|
|
resetMenuSession()
|
|
emit('getRoleList')
|
|
}).finally(()=>{
|
|
state.loading = false;
|
|
})
|
|
}
|
|
}
|
|
});
|
|
};
|
|
// 获取菜单结构数据
|
|
const getMenuData = () => {
|
|
getRoleParams().then((res:any)=>{
|
|
const menus = res.data.menu??[]
|
|
const accessMenus = res.data.accessMenus??[]
|
|
menus.map((item:any)=>{
|
|
item.disabled = !accessMenus.includes(item.id)
|
|
})
|
|
state.menuData = proxy.handleTree(menus, "id","pid");
|
|
})
|
|
};
|
|
const resetForm = ()=>{
|
|
state.menuCheckStrictly=false;
|
|
state.menuExpand = false;
|
|
state.menuNodeAll = false;
|
|
state.formData = {
|
|
id:0,
|
|
pid:0,
|
|
name: '',
|
|
status: 1,
|
|
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:[]
|
|
}
|
|
};
|
|
/** 树权限(展开/折叠)*/
|
|
const handleCheckedTreeExpand = (value:any) => {
|
|
let treeList = state.menuData;
|
|
for (let i = 0; i < treeList.length; i++) {
|
|
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
|
}
|
|
}
|
|
|
|
/** 树权限(全选/全不选) */
|
|
const handleCheckedTreeNodeAll = (value:any) => {
|
|
menuRef.value.setCheckedNodes(value ? state.menuData : []);
|
|
}
|
|
|
|
/** 树权限(父子联动) */
|
|
const handleCheckedTreeConnect = (value:any) => {
|
|
state.menuCheckStrictly = value ? true : false;
|
|
}
|
|
|
|
/** 所有菜单节点数据 */
|
|
function getMenuAllCheckedKeys() {
|
|
// 目前被选中的菜单节点
|
|
let checkedKeys = menuRef.value.getCheckedKeys();
|
|
// 半选中的菜单节点
|
|
let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
|
|
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
|
|
return checkedKeys;
|
|
}
|
|
|
|
// 重置菜单session
|
|
const resetMenuSession = () => {
|
|
refreshBackEndControlRoutes();
|
|
};
|
|
return {
|
|
openDialog,
|
|
closeDialog,
|
|
onCancel,
|
|
onSubmit,
|
|
menuRef,
|
|
formRef,
|
|
handleCheckedTreeExpand,
|
|
handleCheckedTreeNodeAll,
|
|
handleCheckedTreeConnect,
|
|
resetMenuSession,
|
|
...toRefs(state),
|
|
};
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.tree-border {
|
|
margin-top: 5px;
|
|
border: 1px solid #e5e6e7!important;
|
|
border-radius: 4px;
|
|
}
|
|
.system-edit-role-container {
|
|
.menu-data-tree {
|
|
border: var(--el-input-border, var(--el-border-base));
|
|
border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
|
|
padding: 5px;
|
|
}
|
|
}
|
|
</style>
|