|
|
<script setup>import { nextTick, onMounted, reactive, ref } from 'vue'import { ElMessage } from 'element-plus'import _ from 'lodash'import request from '@/util/http'import API from '@/util/http'import { useAdminStore } from "@/store/index.js"import { storeToRefs } from "pinia"const adminStore = useAdminStore();const { adminData, menuTree } = storeToRefs(adminStore);import { permissionMapping, findMenuById } from "@/utils/menuTreePermission.js"import { tr } from 'element-plus/es/locales.mjs'
// 表单验证ref
const Ref = ref(null)const roleData = ref([])const roleTotal = ref(100)const treeRef = ref(null)const admin = ref({ account: '', market: '', postiton: ''})const role = ref({ name: ''})const getRoleObj = ref({ pageNum: 1, pageSize: 10})const permissionAddVisible = ref(false)const addRole = ref({ roleName: '', parentId: null, checkedKeys: [], market: ''})const addRoleMarket = ref([])const channelList = ref(['美股', '港股', 'hc第一频道'])const getRoleList = async function (val) { if (!findMenuById(menuTree.value, permissionMapping.view_role_information)) { ElMessage.error('无此权限') return } try { if (typeof val === 'number') { getRoleObj.value.pageNum = val } console.log('搜索参数', getRoleObj.value, role.value) const result = await request({ url: '/role/selectBy', data: { ...getRoleObj.value, roleVo: { roleName: role.value.name } } }) roleData.value = result.data.list console.log('roleData', roleData.value) roleTotal.value = result.data.total } catch (error) { console.log('请求失败', error) }}// 试试D老师的方法
const formatPermissions = (tree) => { if (!tree || tree.length === 0) return '';
return tree.map(menu => { const mainMenu = menu.menuName; const subMenus = menu.children?.map(child => child.menuName) || [];
// 如果有子菜单,显示前2个子菜单名称
if (subMenus.length > 0) { const maxSub = Math.min(2, subMenus.length); const subText = subMenus.slice(0, maxSub).join('、'); const moreText = subMenus.length > maxSub ? '...' : ''; return `${mainMenu}+${subText}${moreText}`; }
// 没有子菜单时只显示主菜单
return mainMenu; }).join('+');};const trimJwCode = () => { if (admin.value.account) { admin.value.account = admin.value.account.replace(/\s/g, ''); }}const searchRole = function () { trimJwCode(); getRoleObj.value.pageNum = 1 getRoleList()}// 重置
const reset = function () { admin.value = {} role.value.name = '' // 重置页码
getRoleObj.value.pageNum = 1 getRoleList()}const RoleArea = ref([])const getRoleArea = async function () { try { const result = await request({ url: '/general/allRoleMarket', data: {} }) RoleArea.value = result.data } catch (error) { console.log('请求失败', error) }}// 新增角色弹窗
const openPermissionAddVisible = function () { permissionAddVisible.value = true getRoles() getLists()}
const closePermissionAddVisible = function () { permissionAddVisible.value = false Ref.value.resetFields(); getRoleList()}
// 新增角色初始化
const permissionAddInit = function () { openPermissionAddVisible()}const handleDialogClose = function () { closePermissionAddVisible() console.log('hhh');}// 权限类别
const permissionList = ref([])const getRoles = async function () { try { const res = await API({ url: '/role/selectAll' }) permissionList.value = res.data.map(item => ({ label: item.roleName, value: item.id }))
console.log('权限列表:', permissionList.value) } catch (error) { console.error('获取权限列表失败:', error) }}
const collectIds = (tree) => { let ids = []; tree.forEach((node) => { ids.push(node.id); if (node.children && node.children.length > 0) { ids = ids.concat(collectIds(node.children)); } }); return ids;}
//给data数据加上disabled属性,控制是否禁用
function processTreeData(data) { return data.map(item => ({ ...item, disabled: item.id != null || item.menuName.includes("敏感权限"), //控制权限显示的条件
children: item.children ? processTreeData(item.children) : [] }));}
const handleAddRole = async function () { if (!findMenuById(menuTree.value, permissionMapping.add_role_information)) { ElMessage.error('无此权限') return } try { await new Promise((resolve, reject) => { Ref.value.validate((valid) => { if (valid) { resolve(); // 验证通过,继续执行后续代码
} else { reject(new Error('请检查并完善表单信息')); // 验证失败,抛出错误
} }); }); addRole.value.roleName = addRole.value.roleName.replace(/\s+/g, ''); console.log('去除角色名空格:', addRole.value.roleName);
// 确保提交时包含所有选中的权限ID(包括父节点)
const finalCheckedKeys = addRole.value.checkedKeys || [];
const res = await API({ url: '/role/add', data: { "roleName": addRole.value.roleName, "menuIds": finalCheckedKeys, "fatherId": addRole.value.parentId, "market": addRole.value.market } }) if (res.code === 200) { ElMessage.success('角色' + addRole.value.roleName + '添加成功') console.log('成功了,看看addRole', addRole.value) console.log('提交的权限ID列表:', finalCheckedKeys) closePermissionAddVisible() } else { ElMessage.error(res.msg) } } catch (error) { console.log('请求失败', error) console.log('失败,看看addRole', addRole.value) }}
const handleRolePageSizeChange = (val) => { getRoleObj.value.pageSize = val getRoleList() // 调用角色管理的查询
}
// 角色管理分页 - 当前页变化
const handleRoleCurrentChange = (val) => { getRoleObj.value.pageNum = val getRoleList() // 调用角色管理的查询
}
const data = ref([])const getLists = async function () { try { console.log('addRole.value.roleId', addRole.value.roleId);
let roleId = addRole.value.parentId if (addRole.value.parentId === null || addRole.value.parentId === undefined) { roleId = 2 } const res = await API({ url: '/menu/tree', data: { id: roleId } }) data.value = res.data data.value = filterPermission(data.value) console.log('看看data', data.value) console.log('parentID:', addRole.value.parentId, 'roleId:', roleId)
if (addRole.value.parentId && addRole.value.parentId !== 2) { const result = await API({ url: '/general/roleMarket', data: { id: addRole.value.parentId } }) if (result.code === 200) { if (typeof result.data === 'string' && result.data) { addRoleMarket.value = result.data.split(',') addRole.value.market = '' } else if (Array.isArray(result.data)) { addRoleMarket.value = result.data addRole.value.market = '' } else { addRoleMarket.value = [] addRole.value.market = '' } } else { ElMessage.error('该上级角色无归属地区') console.log('该上级角色无归属地区')
} console.log('addRoleMarket.value', addRoleMarket.value) } else { addRoleMarket.value = RoleArea.value console.log('elseRoleArea', RoleArea); } } catch (error) { console.log('请求失败', error) }}
//金豆过滤
const goldenBeanMenuIds = new Set([ permissionMapping.gold_bean_audit, permissionMapping.gold_bean_recharge, permissionMapping.gold_bean_consumption, permissionMapping.gold_bean_customer_details])// 15,43,44,45,46,47,// 金豆审核
// 18,52,53,54,// 金豆充值
// 20,57,58,59,60,// 金豆消耗
// 23// 金豆客户账户明细
const filterGoldenBeanMenus = (tree) => { return tree .filter(item => { // 排除金豆相关的顶层菜单
if (goldenBeanMenuIds.has(item.id)) { return false } // 递归处理子菜单
if (item.children && item.children.length > 0) { item.children = filterGoldenBeanMenus(item.children) } return true })}// 过滤权限模块(????????)俺不会
const filterPermission = (tree) => { return tree.filter(item => { if (item.id === permissionMapping.permission_management) { return false } else if (item.children && item.children.length > 0) { item.children = filterPermission(item.children) } return true })}// 处理编辑角色权限时的勾选事件
const handleEditRolePermissionCheck = (checkedNodes, checkedInfo) => { const { checkedKeys, checkedNodes: allCheckedNodes } = checkedInfo
// 判断是否有选中的节点
if (allCheckedNodes.length === 0) { permissionEditRoleObj.value.checkedKeys = [] ifHasChannel.value = false return }
// 由于设置了 check-strictly="false",Element Plus 会自动处理父子节点联动
// 我们只需要使用 checkedKeys,它已经包含了所有必要的节点ID
permissionEditRoleObj.value.checkedKeys = checkedKeys
console.log('编辑角色选中的权限ID:', checkedKeys) console.log('选中的节点数量:', allCheckedNodes.length) if (checkedKeys.includes(124)||checkedKeys.includes(125)||checkedKeys.includes(126)||checkedKeys.includes(127)) { ifHasChannel.value = true } else { ifHasChannel.value = false }};
//用于标记是否勾选频道管理
const ifHasChannel = ref(false)const handleCheckChange = async (checkedNodes, checkedInfo) => { const { checkedKeys, checkedNodes: allCheckedNodes } = checkedInfo
// 判断是否有选中的节点
if (allCheckedNodes.length === 0) { addRole.value.checkedKeys = [] ifHasChannel.value = false return }
// 创建一个Set存储所有需要选中的ID(包括父级)
const allKeys = new Set(checkedKeys)
// 遍历所有选中的节点,为每个节点添加其父级
allCheckedNodes.forEach(node => { // 为每个选中的节点单独查找父级
selectParentNodes(data.value, node.id, allKeys) });
// 将Set转换为数组并更新
addRole.value.checkedKeys = Array.from(allKeys) console.log('新增角色包含所有父级的选中项:', addRole.value.checkedKeys) if (addRole.value.checkedKeys.includes(124)) { ifHasChannel.value = true console.log('勾选了频道'); } else { ifHasChannel.value = false }}const selectParentNodes = (treeData, nodeId, checkedKeys) => { if (!Array.isArray(treeData)) return false
for (const item of treeData) { // 先检查子节点
if (item.children && item.children.length > 0) { const foundInChildren = selectParentNodes(item.children, nodeId, checkedKeys); if (foundInChildren) { // 找到子节点后添加当前节点(父节点)
checkedKeys.add(item.id); return true } }
// 检查当前节点是否为目标节点
if (item.id === nodeId) { return true } }
return false};//点击角色权限菜单树点击展示逻辑
const menuTreeVisible = ref(false)const currentRoleMenuTree = ref([])const currentRoleName = ref('')const Rolecheckedkeys = ref([])const showMenuTree = (treeData, roleName) => { currentRoleMenuTree.value = processTreeData(treeData) || []; console.log('currentRoleMenuTree.value', currentRoleMenuTree.value) Rolecheckedkeys.value = collectIds(treeData) console.log('Rolecheckedkeys', Rolecheckedkeys.value)
currentRoleName.value = roleName || '权限详情' menuTreeVisible.value = true;}
// 编辑角色对象
const permissionEditRoleObj = ref({ id: null, roleName: '', market: '', parentId: null, parentName: '', checkedKeys: []})
// 编辑角色弹窗
const permissionEditRoleVisible = ref(false)
const collectIds2 = (tree) => { let ids = [] tree.forEach((node) => { // 如果当前节点没有 children 或 children 为空,说明是叶子节点
if (!node.children || node.children.length === 0) { ids.push(node.id) } else { // 如果有 children,递归收集子节点的叶子节点
ids = ids.concat(collectIds2(node.children)) } }) return ids}
// 编辑角色初始化
const permissionEditRoleInit = async function (row) { console.log('row', row) console.log('row.tree', row.tree) permissionEditRoleObj.value = {} permissionEditRoleObj.value.id = row.id permissionEditRoleObj.value.roleName = row.roleName permissionEditRoleObj.value.market = row.market permissionEditRoleObj.value.parentId = row.fatherId permissionEditRoleObj.value.parentName = row.fatherName
try { let roleId = permissionEditRoleObj.value.parentId; // 如果没有上级角色,设置为管理员的id
if (permissionEditRoleObj.value.parentId === null || permissionEditRoleObj.value.parentId === undefined) { roleId = 2; } // 调用 /tree 接口,使用上级角色 ID 获取权限列表
const res = await API({ url: '/menu/tree', data: { id: roleId } }); data.value = res.data; data.value = filterPermission(data.value) //data.value = filterGoldenBeanMenus(data.value);
// 收集当前行权限树的叶子节点id(只收集实际选中的叶子节点)
if (row.tree && row.tree.length > 0) { const leafIds = collectIds2(row.tree); permissionEditRoleObj.value.checkedKeys = leafIds; console.log('编辑角色初始化时的权限列表', permissionEditRoleObj.value.checkedKeys); } else { permissionEditRoleObj.value.checkedKeys = []; } } catch (error) { console.log('根据上级角色获取权限列表失败', error); data.value = []; permissionEditRoleObj.value.checkedKeys = []; } console.log('编辑角色', permissionEditRoleObj.value); permissionEditRoleVisible.value = true;
// 等待DOM更新后手动设置树的选中状态
await nextTick(); if (treeRef.value && permissionEditRoleObj.value.checkedKeys.length > 0) { treeRef.value.setCheckedKeys(permissionEditRoleObj.value.checkedKeys); console.log('手动设置树的选中状态:', permissionEditRoleObj.value.checkedKeys); }};
// 编辑角色提交
const permissionEditRole = async function () { if (!findMenuById(menuTree.value, permissionMapping.edit_role_information)) { ElMessage.error('无此权限') return } try { await new Promise((resolve, reject) => { Ref.value.validate((valid) => { if (valid) { resolve(); } else { reject(new Error('请检查并完善表单信息')); } }); });
// 确保提交时包含所有选中的权限ID(包括父节点)
let finalCheckedKeys = permissionEditRoleObj.value.checkedKeys || [];
// 为所有选中的节点添加其父节点ID
const allKeys = new Set(finalCheckedKeys); finalCheckedKeys.forEach(nodeId => { selectParentNodesForSubmit(data.value, nodeId, allKeys); });
finalCheckedKeys = Array.from(allKeys);
const res = await API({ url: '/menu/update', data: { "id": permissionEditRoleObj.value.id, "roleName": permissionEditRoleObj.value.roleName, "menuIds": finalCheckedKeys, "fatherId": permissionEditRoleObj.value.parentId, "market": permissionEditRoleObj.value.market } }); if (res.code === 200) { console.log('编辑角色成功', permissionEditRoleObj.value); console.log('提交的权限ID列表:', finalCheckedKeys); permissionEditRoleVisible.value = false; getRoleList(); ElMessage.success('编辑角色成功'); } else if (res.code === 0) { console.log('角色名重复', permissionEditRoleObj.value); ElMessage.error('角色名重复'); } else { console.log('编辑角色失败', res); ElMessage.error('编辑角色失败'); } } catch (error) { console.log('编辑角色失败', error); console.log('失败,看看permissionEditRoleObj', permissionEditRoleObj.value); }};
// 为提交时查找父节点的辅助函数
const selectParentNodesForSubmit = (treeData, nodeId, checkedKeys) => { if (!Array.isArray(treeData)) return false;
for (const item of treeData) { // 先检查子节点
if (item.children && item.children.length > 0) { const foundInChildren = selectParentNodesForSubmit(item.children, nodeId, checkedKeys); if (foundInChildren) { // 找到子节点后添加当前节点(父节点)
checkedKeys.add(item.id); return true; } }
// 检查当前节点是否为目标节点
if (item.id === nodeId) { return true; } }
return false;};
const Rolerules = reactive({ roleName: [ { required: true, message: '请输入角色名称', trigger: 'blur' }, { min: 2, max: 20, message: '角色名称长度应在2-20个字符之间', trigger: 'blur' } ], market: [ { required: true, message: '请选择归属地区', trigger: 'change' } ], checkedKeys: [ { required: true, message: '请选择权限列表', trigger: 'change', // 选框变化或提交时触发,可根据实际调整
validator: (rule, value, callback) => { if (value && value.length > 0) { callback(); // 有选中项,校验通过
} else { callback(new Error('请选择权限列表')); // 未选中,抛出错误提示
} } } ]});
const throttledHandleAddRole = _.throttle(handleAddRole, 5000, { trailing: false})const canLook = findMenuById(menuTree.value, permissionMapping.view_role_information)const canAdd = findMenuById(menuTree.value, permissionMapping.add_role_information)const canEdit = findMenuById(menuTree.value, permissionMapping.edit_role_information)// 挂载
onMounted(async function () { await getRoleList() await getRoleArea()})
</script><template> <div> <el-card class="card1" style="margin-bottom: 1vh;"> <div style="display: flex;"> <el-text size="large">角色名称:</el-text> <el-input v-model="role.name" style="width: 240px" placeholder="请输入角色名称" clearable /> <div style="margin-left: auto;"> <el-button type="primary" @click="searchRole()" :disabled="!canLook" v-if="canLook">查询</el-button> <el-button type="success" @click="reset()">重置</el-button> </div> </div> </el-card>
<el-card class="card2"> <div class="add-item"> <el-button style="color: #048efb; border: 1px solid #048efb" @click="permissionAddInit()" :disabled="!canAdd" v-if="canAdd">新增角色</el-button> </div> <div> <el-table :data="roleData" style="width: 82vw;height:62.3vh" show-overflow-tooltip :row-style="{ height: '56px' }"> <el-table-column type="index" label="序号" width="100px" fixed="left"> <template #default="scope"> <span>{{ scope.$index + 1 + (getRoleObj.pageNum - 1) * getRoleObj.pageSize }}</span> </template> </el-table-column>
<el-table-column prop="roleName" label="角色名称" /> <el-table-column prop="fatherName" label="上级角色"> <template #default="scope"> {{ scope.row.fatherName || '-' }} </template> </el-table-column> <el-table-column label="权限范围" show-overflow-tooltip> <template #default="scope"> <div class="permission-cell" @click="showMenuTree(scope.row.tree, scope.row.roleName)"> {{ formatPermissions(scope.row.tree) }} </div> </template> </el-table-column> <el-table-column prop="operation" label="操作" width="200px"> <template #default="scope"> <el-button type="warning" text @click="permissionEditRoleInit(scope.row)" :disabled="(scope.row.id === 2) || (scope.row.id === 1) || !canEdit" v-if="canEdit"> 编辑 </el-button> </template> </el-table-column> </el-table> </div>
<div style="margin-top: 20px;display: flex;"> <el-pagination background :current-page="getRoleObj.pageNum" :page-size="getRoleObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="roleTotal" @size-change="handleRolePageSizeChange" @current-change="handleRoleCurrentChange"></el-pagination> </div> </el-card> </div>
<!-- 角色菜单树展示 --> <el-dialog v-model="menuTreeVisible" :title='`权限详情:${currentRoleName}`' width="600px"> <el-tree :data="currentRoleMenuTree" node-key="id" :props="{ label: 'menuName', children: 'children' }" show-checkbox check-strictly :expand-on-click-node="false" :default-expanded-keys="currentRoleMenuTree.map(item => item.id)" :default-checked-keys="Rolecheckedkeys" /> <template #footer> <el-button @click="menuTreeVisible = false" type="primary">关闭</el-button> </template> </el-dialog>
<!-- 新增角色 --> <el-dialog v-model="permissionAddVisible" title="新增角色" width="800px" :close-on-click-modal="false" @close="handleDialogClose"> <template #footer> <el-form ref="Ref" :rules="Rolerules" :model="addRole" label-width="auto" style="max-width: 600px; align-items: center"> <el-form-item prop="roleName" label="角色名称:" required> <el-input v-model="addRole.roleName" placeholder="请输入角色名称" style="width: 220px" /> </el-form-item> <el-form-item prop="parentName" label="上级角色:"> <el-select v-model="addRole.parentId" placeholder="请选择上级角色" style="width: 220px" @change="getLists" clearable> <el-option v-for="item in permissionList" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-form-item> <el-form-item prop="market" label="归属地区:" required> <el-select v-model="addRole.market" placeholder="请选择归属地区" style="width: 220px" clearable> <el-option v-for="item in addRoleMarket" :key="item" :label="item" :value="item" /> </el-select> <text>(此地区无实际意义,仅用于各分部负责人查看其地区角色)</text> </el-form-item> <el-form-item prop="checkedKeys" label="权限列表:" required> <el-tree v-if="data.length > 0" :data="data" show-checkbox node-key="id" :props="{ label: 'menuName', children: 'children' }" :checked-keys="addRole.checkedKeys" :check-strictly="false" @check="handleCheckChange"> <template #default="{ node }"> <span>{{ node.label }}</span> </template> </el-tree> <div v-else style="display: flex; align-items: center; gap: 8px;"> <span style="color: #999;">暂无数据</span> </div> </el-form-item> <el-form-item v-show="ifHasChannel" prop="channel" label="频道名称:" required> <el-select v-model="addRole.channel" placeholder="请选择频道" style="width: 220px" clearable> <el-option v-for="item in channelList" :key="item" :label="item" :value="item" /> </el-select> </el-form-item> </el-form>
<div> <el-button @click="closePermissionAddVisible()">取消</el-button> <el-button type="primary" @click="throttledHandleAddRole"> 提交 </el-button> </div> </template> </el-dialog>
<!-- 編輯角色彈窗 --> <el-dialog v-model="permissionEditRoleVisible" title="编辑角色" width="800px" :close-on-click-modal="false"> <template #footer> <el-form ref="Ref" :rules="Rolerules" :model="permissionEditRoleObj" label-width="auto" style="max-width: 600px; align-items: center"> <el-form-item prop="roleName" label="角色名称:" required> <el-input v-model="permissionEditRoleObj.roleName" placeholder="请输入角色名称" style="width: 220px" /> </el-form-item> <el-form-item prop="parentName" label="上级角色:"> <el-input v-model="permissionEditRoleObj.parentName" placeholder="无上级角色" disabled style="width: 220px"> <el-option v-for="item in permissionList" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-input> </el-form-item> <el-form-item prop="market" label="归属地区" required> <el-input v-model="permissionEditRoleObj.market" placeholder="请输入归属地区" style="width: 220px" disabled /> <text>(此地区无实际意义,仅用于各分部负责人查看其地区角色)</text> </el-form-item> <el-form-item prop="checkedKeys" label="权限列表:" required> <el-tree v-if="data.length > 0" :data="data" show-checkbox node-key="id" ref="treeRef" :props="{ label: 'menuName', children: 'children' }" :default-checked-keys="permissionEditRoleObj.checkedKeys" :check-strictly="false" @check="handleEditRolePermissionCheck"> <!-- <template #default="{ node, data }"> data删掉了,不影响功能 --> <template #default="{ node }"> <span>{{ node.label }}</span> </template> </el-tree> <div v-else style="display: flex; align-items: center; gap: 8px;"> <span style="color: #999;">暂无数据</span> </div> </el-form-item>
<el-form-item v-show="ifHasChannel" prop="channel" label="频道名称:" required> <el-select v-model="permissionEditRoleObj.channel" placeholder="请选择频道" style="width: 220px" clearable> <el-option v-for="item in channelList" :key="item" :label="item" :value="item" /> </el-select> </el-form-item> </el-form>
<div> <el-button @click="permissionEditRoleVisible = false">取消</el-button> <el-button type="primary" @click="permissionEditRole"> 提交 </el-button> </div> </template> </el-dialog></template>
<style scoped lang="scss">// 新增用户按钮
.add-item { margin-bottom: 1vh;}
// 搜索的卡片样式
.card1 { background: #F3FAFE;}
// 表单的卡片样式
.card2 { background: #E7F4FD;}
// 表头背景等
:deep(.el-table__header-wrapper),:deep(.el-table__body-wrapper),:deep(.el-table__cell),/* 表格 */:deep(.el-table__body td) { background-color: #F3FAFE !important;}
/* 表头 */:deep(.el-table__header th) { background-color: #F3FAFE !important;}
/* 鼠标悬停 */:deep(.el-table__row:hover > .el-table__cell) { background-color: #E5EBFE !important;}
.head-card { display: flex;}
.permission-cell { cursor: pointer; color: #409eff; /* 蓝色文字,提示可点击 */}</style>
|