feat: 员工角色

fix/0524_ch
向文可 2 years ago
parent 716eb4bb63
commit 403adddce4

@ -26,7 +26,7 @@ export function getUserInfo() {
// 获取权限列表 // 获取权限列表
export function getPermission(params) { export function getPermission(params) {
return request({ return request({
url: '/u-admin/uc/ucPermission/listUserMenu', url: '/uc/menu',
method: 'get', method: 'get',
params, params,
}); });

@ -12,6 +12,19 @@ export const detail = (id) => {
method: 'get', method: 'get',
}); });
}; };
export const searchPermission = (id) => {
return request({
url: '/uc/employee/role/' + id,
method: 'get',
});
};
export const savePermission = (id, data) => {
return request({
url: '/uc/employee/role/' + id,
method: 'put',
data,
});
};
export const create = (data) => { export const create = (data) => {
return request({ return request({
url: '/uc/employee', url: '/uc/employee',

@ -1,5 +1,6 @@
import * as deptAPI from '@/api/permission/dept.js'; import * as deptAPI from '@/api/permission/dept.js';
import * as api from '@/api/permission/employee.js'; import * as api from '@/api/permission/employee.js';
import * as systemAPI from '@/api/permission/system.js';
import { ElMessage, ElMessageBox } from '@/plugins/element-plus'; import { ElMessage, ElMessageBox } from '@/plugins/element-plus';
const state = () => ({ const state = () => ({
code: 'EmployeeManagement', code: 'EmployeeManagement',
@ -8,6 +9,7 @@ const state = () => ({
total: 0, total: 0,
opts: { opts: {
init: false, init: false,
system: [],
dept: [], dept: [],
}, },
}); });
@ -36,6 +38,7 @@ const actions = {
...state.opts, ...state.opts,
init: true, init: true,
dept: await deptAPI.search({ hiddenDisable: true }), dept: await deptAPI.search({ hiddenDisable: true }),
system: await systemAPI.search(),
}); });
}, },
detail: async (context, id) => { detail: async (context, id) => {
@ -45,12 +48,27 @@ const actions = {
} }
return res; return res;
}, },
permission: async (context, id) => {
let res = await api.searchPermission(id);
if (!res) {
ElMessage.error('加载权限列表失败');
}
return res;
},
save: async ({ dispatch }, data) => { save: async ({ dispatch }, data) => {
let save = data.id ? api.update : api.create; let save = data.id ? api.update : api.create;
let res = await save(data); let res = await save(data);
if (res) { if (res) {
ElMessage.success('保存成功'); if (!data.id) {
dispatch('search'); data.id = res;
}
res = await api.savePermission(data.id, { roleIds: data.roleIds });
if (res) {
ElMessage.success('保存成功');
dispatch('search');
} else {
ElMessage.error('保存角色失败');
}
} else { } else {
ElMessage.error('保存失败'); ElMessage.error('保存失败');
} }

@ -43,6 +43,49 @@
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" /> <el-input v-model="form.remark" type="textarea" />
</el-form-item> </el-form-item>
<el-form-item label="账号角色" prop="roleIds">
<div class="role-list">
<div v-for="(item, index) in opts.system" :key="index" class="system">
<h3 class="system-header">
{{ item.systemName }}
</h3>
<div class="flex">
<el-tag
v-for="(role, j) in handleSystemRole(item.id)"
:key="index + '' + j"
closable
size="large"
@close="handleDelRole(role.id)"
>
{{ role.roleName }}
</el-tag>
<el-button @click="handleAddRole(item.id)"></el-button>
</div>
</div>
</div>
<el-dialog v-model="roleVisible" title="添加角色">
<el-form v-loading="loading2">
<el-form-item>
<el-select
v-model="checkedRole"
:config="{
label: 'roleName',
value: 'id',
disabled: (item) =>
handleSystemRole(currentSystemId).findIndex((role) => role.id === item.id) !==
-1,
}"
multiple
:opts="systemRoleList"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="roleVisible = false">取消</el-button>
<el-button :loading="loading2" type="primary" @click="handleSaveRole"></el-button>
</template>
</el-dialog>
</el-form-item>
</el-form> </el-form>
<div class="form-footer"> <div class="form-footer">
<el-button @click="handleCancel"></el-button> <el-button @click="handleCancel"></el-button>
@ -71,13 +114,17 @@
phone: '', phone: '',
remark: '', remark: '',
userName: '', userName: '',
roleIds: [],
}); });
const permissionList = reactive([]);
const handleSystemRole = (systemId) => permissionList.filter((item) => item.systemId === systemId);
const rules = reactive({ const rules = reactive({
departmentId: [{ required: unref(computed(() => !form.id)), message: '所在组织不能为空' }], departmentId: [{ required: unref(computed(() => !form.id)), message: '所在组织不能为空' }],
userName: [{ required: true, message: '用户名不能为空' }], userName: [{ required: true, message: '用户名不能为空' }],
phone: [{ required: true, message: '手机号码不能为空' }], phone: [{ required: true, message: '手机号码不能为空' }],
email: [{ required: true, message: '邮箱地址不能为空' }], email: [{ required: true, message: '邮箱地址不能为空' }],
employeeName: [{ required: true, message: '员工姓名不能为空' }], employeeName: [{ required: true, message: '员工姓名不能为空' }],
roleIds: [{ required: true, message: '账号角色不能为空' }],
}); });
const opts = computed(() => store.state.employee.opts); const opts = computed(() => store.state.employee.opts);
if (!unref(opts).init) { if (!unref(opts).init) {
@ -91,6 +138,9 @@
let res = await store.dispatch('employee/detail', id); let res = await store.dispatch('employee/detail', id);
Object.assign(form, res); Object.assign(form, res);
} }
permissionList.splice(0);
permissionList.push(...(await store.dispatch('employee/permission', id)));
form.roleIds = permissionList.map((item) => item.id);
} }
}; };
onActivated(handleLoad); onActivated(handleLoad);
@ -125,6 +175,50 @@
const handleClose = () => { const handleClose = () => {
router.push({ name: 'EmployeeManagement' }); router.push({ name: 'EmployeeManagement' });
}; };
const loading2 = ref(false);
const roleVisible = ref(false);
const currentSystemId = ref(null);
const checkedRole = ref([]);
const systemRoleList = ref([]);
const handleAddRole = async (id) => {
loading2.value = true;
currentSystemId.value = id;
checkedRole.value = [];
roleVisible.value = true;
systemRoleList.value = await store.dispatch('deptRole/role', id);
loading2.value = false;
};
const handleDelRole = (id) => {
form.roleIds.splice(form.roleIds.findIndex(id), 1);
permissionList.splice(
permissionList.findIndex((item) => item.id === id),
1
);
};
const handleSaveRole = async () => {
form.roleIds.push(...unref(checkedRole));
permissionList.push(...unref(systemRoleList).filter((item) => unref(checkedRole).indexOf(item.id) !== -1));
roleVisible.value = false;
};
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped>
.role-list {
.system {
& + .system {
margin-top: @layout-space;
}
.system-header {
margin-bottom: @layout-space;
}
.flex {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.el-tag {
margin: @layout-space-small @layout-space @layout-space-small 0;
}
}
}
</style>

@ -23,7 +23,7 @@
</div> </div>
</div> </div>
</template> </template>
<div v-loading="loading" class="card-body"> <el-scrollbar v-loading="loading" class="card-body">
<el-tree <el-tree
:data="list" :data="list"
default-expand-all default-expand-all
@ -56,7 +56,7 @@
</div> </div>
</template> </template>
</el-tree> </el-tree>
</div> </el-scrollbar>
</el-card> </el-card>
<el-card class="feature"> <el-card class="feature">
<template #header> <template #header>
@ -67,7 +67,7 @@
</div> </div>
</div> </div>
</template> </template>
<div v-loading="loading2" class="card-body"> <el-scrollbar v-loading="loading2" class="card-body">
<el-tree <el-tree
:data="featureList" :data="featureList"
default-expand-all default-expand-all
@ -95,7 +95,7 @@
</div> </div>
</template> </template>
</el-tree> </el-tree>
</div> </el-scrollbar>
</el-card> </el-card>
<el-card v-show="menuState.formVisible" class="form"> <el-card v-show="menuState.formVisible" class="form">
<template #header> <template #header>
@ -104,59 +104,61 @@
<div class="action"></div> <div class="action"></div>
</div> </div>
</template> </template>
<el-form <el-scrollbar v-loading="loading2" class="card-body">
ref="refsMenuForm" <el-form
v-loading="menuState.submitting" ref="refsMenuForm"
label-width="100px" v-loading="menuState.submitting"
:model="menuState.form" label-width="100px"
:rules="menuState.rules" :model="menuState.form"
> :rules="menuState.rules"
<el-form-item label="所属系统" prop="systemId"> >
<el-select <el-form-item label="所属系统" prop="systemId">
v-model="menuState.form.systemId" <el-select
:config="{ label: 'systemName', value: 'id' }" v-model="menuState.form.systemId"
:opts="opts.system" :config="{ label: 'systemName', value: 'id' }"
/> :opts="opts.system"
</el-form-item> />
<el-form-item label="上级菜单" prop="parentId"> </el-form-item>
<el-cascader <el-form-item label="上级菜单" prop="parentId">
v-model="menuState.form.parentId" <el-cascader
:options="list" v-model="menuState.form.parentId"
:props="{ :options="list"
label: 'title', :props="{
value: 'id', label: 'title',
children: 'menuChild', value: 'id',
checkStrictly: true, children: 'menuChild',
expandTrigger: 'hover', checkStrictly: true,
emitPath: false, expandTrigger: 'hover',
}" emitPath: false,
/> }"
</el-form-item> />
<el-form-item label="菜单类型" prop="type"> </el-form-item>
<el-radio-group v-model="menuState.form.type" :opts="opts.type" /> <el-form-item label="菜单类型" prop="type">
</el-form-item> <el-radio-group v-model="menuState.form.type" :opts="opts.type" />
<el-form-item label="菜单名称" prop="title"> </el-form-item>
<el-input v-model="menuState.form.title" /> <el-form-item label="菜单名称" prop="title">
</el-form-item> <el-input v-model="menuState.form.title" />
<el-form-item label="权限标识" prop="permission"> </el-form-item>
<el-input v-model="menuState.form.permission" /> <el-form-item label="权限标识" prop="permission">
</el-form-item> <el-input v-model="menuState.form.permission" />
<el-form-item label="路由路径" prop="path"> </el-form-item>
<el-input v-model="menuState.form.path" /> <el-form-item label="路由路径" prop="path">
</el-form-item> <el-input v-model="menuState.form.path" />
<el-form-item label="前端页面" prop="page"> </el-form-item>
<el-input v-model="menuState.form.page" /> <el-form-item label="前端页面" prop="page">
</el-form-item> <el-input v-model="menuState.form.page" />
<el-form-item label="菜单图标" prop="icon"> </el-form-item>
<el-input v-model="menuState.form.icon" /> <el-form-item label="菜单图标" prop="icon">
</el-form-item> <el-input v-model="menuState.form.icon" />
<el-form-item label="菜单排序" prop="sort"> </el-form-item>
<el-input-number v-model="menuState.form.sort" /> <el-form-item label="菜单排序" prop="sort">
</el-form-item> <el-input-number v-model="menuState.form.sort" />
<el-form-item> </el-form-item>
<el-button type="primary" @click="handleSaveMenu"></el-button> <el-form-item>
</el-form-item> <el-button type="primary" @click="handleSaveMenu"></el-button>
</el-form> </el-form-item>
</el-form>
</el-scrollbar>
</el-card> </el-card>
<el-card v-show="featureState.formVisible" class="form"> <el-card v-show="featureState.formVisible" class="form">
<template #header> <template #header>
@ -165,51 +167,53 @@
<div class="action"></div> <div class="action"></div>
</div> </div>
</template> </template>
<el-form <el-scrollbar v-loading="loading2" class="card-body">
ref="refsFeatureForm" <el-form
v-loading="featureState.submitting" ref="refsFeatureForm"
label-width="100px" v-loading="featureState.submitting"
:model="featureState.form" label-width="100px"
:rules="featureState.rules" :model="featureState.form"
> :rules="featureState.rules"
<el-form-item label="所属系统" prop="systemId"> >
<el-select <el-form-item label="所属系统" prop="systemId">
v-model="featureState.form.systemId" <el-select
:config="{ label: 'systemName', value: 'id' }" v-model="featureState.form.systemId"
:opts="opts.system" :config="{ label: 'systemName', value: 'id' }"
@change="state.condition.systemId = $event" :opts="opts.system"
/> @change="state.condition.systemId = $event"
</el-form-item> />
<el-form-item label="所属菜单" prop="menuId"> </el-form-item>
<el-cascader <el-form-item label="所属菜单" prop="menuId">
v-model="featureState.form.menuId" <el-cascader
:options="list" v-model="featureState.form.menuId"
:props="{ :options="list"
label: 'title', :props="{
value: 'id', label: 'title',
children: 'menuChild', value: 'id',
checkStrictly: true, children: 'menuChild',
expandTrigger: 'hover', checkStrictly: true,
emitPath: false, expandTrigger: 'hover',
}" emitPath: false,
/> }"
</el-form-item> />
<el-form-item label="功能名称" prop="name"> </el-form-item>
<el-input v-model="featureState.form.name" /> <el-form-item label="功能名称" prop="name">
</el-form-item> <el-input v-model="featureState.form.name" />
<el-form-item label="请求方式" prop="method"> </el-form-item>
<el-select v-model="featureState.form.method" :opts="opts.method" /> <el-form-item label="请求方式" prop="method">
</el-form-item> <el-select v-model="featureState.form.method" :opts="opts.method" />
<el-form-item label="接口路径" prop="uri"> </el-form-item>
<el-input v-model="featureState.form.uri" /> <el-form-item label="接口路径" prop="uri">
</el-form-item> <el-input v-model="featureState.form.uri" />
<el-form-item label="是否启用" prop="isEnable"> </el-form-item>
<el-switch v-model="featureState.form.isEnable" /> <el-form-item label="是否启用" prop="isEnable">
</el-form-item> <el-switch v-model="featureState.form.isEnable" />
<el-form-item> </el-form-item>
<el-button type="primary" @click="handleSaveFeature"></el-button> <el-form-item>
</el-form-item> <el-button type="primary" @click="handleSaveFeature"></el-button>
</el-form> </el-form-item>
</el-form>
</el-scrollbar>
</el-card> </el-card>
</div> </div>
</div> </div>
@ -396,6 +400,7 @@
flex-direction: column; flex-direction: column;
.body { .body {
flex: 1; flex: 1;
overflow: hidden;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
> * { > * {
@ -404,6 +409,17 @@
margin-left: @layout-space; margin-left: @layout-space;
} }
} }
.el-card {
display: flex;
flex-direction: column;
:deep(.el-card__body) {
flex: 1;
overflow: hidden;
.card-body {
padding-right: @layout-space;
}
}
}
:deep(.el-tree) { :deep(.el-tree) {
.flex { .flex {
width: 100%; width: 100%;

@ -203,7 +203,7 @@
const menuList = ref([]); const menuList = ref([]);
const permissionList = ref([]); const permissionList = ref([]);
const formState = reactive({ const formState = reactive({
currentTab: '1', currentTab: '0',
formVisible: false, formVisible: false,
submitting: false, submitting: false,
form: { form: {
@ -230,31 +230,6 @@
departmentList: [{ required: true, trigger: 'change', message: '绑定组织不能为空' }], departmentList: [{ required: true, trigger: 'change', message: '绑定组织不能为空' }],
}, },
}); });
watch(
() => formState.currentTab,
async (value) => {
let res = await store.dispatch('role/detail', formState.form.id);
res.menuIds = [];
res.permissionIds = [];
const deep = (arr) => {
(arr || []).forEach((item) => {
if (item.isHave) {
res.menuIds.push(item.id);
}
res.permissionIds.push(
...(item.permissionChild || []).filter((item) => item.isHave).map((item) => item.id)
);
deep(item.menuChild);
});
};
deep(res.roleMenuTree);
delete res.roleMenuTree;
Object.assign(formState.form, res);
if (value === '2') {
menuList.value = await store.dispatch('role/loadMenu', formState.form.systemId);
}
}
);
const refsTree = ref(null); const refsTree = ref(null);
const checkAll = ref(false); const checkAll = ref(false);
watch(checkAll, (value) => { watch(checkAll, (value) => {
@ -301,8 +276,34 @@
} }
}); });
}; };
const handleDetail = async () => {
formState.submitting = true;
if (formState.currentTab === '1') {
let res = await store.dispatch('role/detail', formState.form.id);
res.role.menuIds = [];
res.role.permissionIds = [];
const deep = (arr) => {
(arr || []).forEach((item) => {
if (item.isHave) {
res.role.menuIds.push(item.id);
}
res.role.permissionIds.push(
...(item.permissionChild || []).filter((item) => item.isHave).map((item) => item.id)
);
deep(item.menuChild);
});
};
deep(res.roleMenuTree);
Object.assign(formState.form, res.role);
} else if (formState.currentTab === '2') {
menuList.value = await store.dispatch('role/loadMenu', formState.form.systemId);
}
formState.submitting = false;
};
watch(() => formState.currentTab, handleDetail);
const handleCreate = (row) => { const handleCreate = (row) => {
formState.formVisible = true; formState.formVisible = true;
formState.currentTab = '1';
Object.assign( Object.assign(
formState.form, formState.form,
_.cloneDeep( _.cloneDeep(
@ -330,7 +331,7 @@
); );
if (formState.currentTab === '3') { if (formState.currentTab === '3') {
formState.formVisible = false; formState.formVisible = false;
formState.currentTab = '1'; formState.currentTab = '0';
handleSearch(); handleSearch();
} else { } else {
let data = _.cloneDeep(formState.form); let data = _.cloneDeep(formState.form);
@ -342,7 +343,7 @@
: 'role/updateDept', : 'role/updateDept',
data data
); );
if (res && formState.currentTab === '1') { if (res && formState.currentTab === '1' && !formState.form.id) {
formState.form.id = res.id; formState.form.id = res.id;
} }
formState.currentTab = +formState.currentTab + 1 + ''; formState.currentTab = +formState.currentTab + 1 + '';

Loading…
Cancel
Save