如何在dxTreeList中展示菜单控件并绑定权限复选框
dxTreeList主菜单控件未显示及权限绑定问题
问题说明
我是ASP和jQuery新手,要在dxTreeList中展示页面及对应控件,同时将复选框与权限数据绑定。目前主菜单的控件无法正常显示,原因是当前的扁平化函数仅处理数组类型的Controls字段,未处理主菜单里对象类型的controls字段,导致主菜单控件丢失,也没法按预期设置权限值和展示格式。
原始JSON数据
[ { "allowedPages": [], "controls": {"Apple": false,"Banana": false,"Orange": false,"Grape": false}, "hasAccess": true, "Action": "Index", "menuName": "FruitBasket", "submenus": [] }, { "allowedPages": [], "controls": {}, "pageAccess": true, "pageAction": "#", "pageName": "TropicalFruits", "submenus": [ { "action": "tropicalUser", "Controls": ["Mango", "Pineapple"], "allowedControls": null, "controller": "admin", "hasAccess": true, "roles": {"TropicalAdmin1": ["Mango", "Pineapple"],"TropicalAdmin2": ["Mango"]}, "subchildMenu": [], "submenu": "ExoticFruits" } ] } ]
目标格式数据
[ {"id": "Dashboard","parentId": 0,"pageName": "Dashboard","action": "Index","pageAccess": true}, {"id": "FruitBasket","parentId": 0,"pageName": "FruitBasket","action": "#","pageAccess": true}, {"id": "TropicalFruits","parentId": "FruitBasket","pageName": "TropicalFruits","action": "","pageAccess": true}, {"id": "Mango","parentId": "TropicalFruits","pageName": "Mango","action": "","pageAccess": true}, {"id": "Pineapple","parentId": "TropicalFruits","pageName": "Pineapple","action": "","pageAccess": true} ]
当前扁平化函数
function flattenControlsData(pages, parentId = 0) { let flatControlsTreeData = []; pages.forEach(page => { if (!page) return; const id = page.pageName || 'No ID'; const transformedPage = { id: id, parentId: parentId, pageName: page.pageName || 'Unnamed Page', hasAccess: page.hasAccess, controller: page.controller || '', roles: page.roles || {}, allowedControls: page.allowedControls || [], allControls: Object.keys(page.controls || {}), isAccess: page.isAccess || false }; if (transformedPage.pageAccess) { flatControlsTreeData.push(transformedPage); } // Add controls if they exist if (Array.isArray(page.Controls)) { page.Controls.forEach(control => { flatControlsTreeData.push({ id: control, parentId: id, pageName: control, action: '', pageAccess: true, controller: '', roles: {}, allowedControls: [], roleControlMappingDetail: null, allControls: [] }); }); } // Add submenus if (Array.isArray(page.submenus)) { flatControlsTreeData = flatControlsTreeData.concat(flattenControlsData(page.submenus, id)); } // Add subchildMenu if (Array.isArray(page.subchildMenu)) { flatControlsTreeData = flatControlsTreeData.concat(flattenControlsData(page.subchildMenu, id)); } }); console.log(flatControlsTreeData); return flatControlsTreeData; }
解决办法
修改扁平化函数,新增处理对象类型controls的逻辑,同时保留权限状态,这样主菜单的控件就能正常生成,后续也能绑定复选框:
function flattenControlsData(pages, parentId = 0) { let flatControlsTreeData = []; pages.forEach(page => { if (!page) return; // 处理页面节点:优先用pageName,没有则用menuName(适配原始数据的字段差异) const pageId = page.pageName || page.menuName || 'No ID'; const transformedPage = { id: pageId, parentId: parentId, pageName: page.pageName || page.menuName || 'Unnamed Page', action: page.action || page.Action || page.pageAction || '', pageAccess: page.pageAccess ?? page.hasAccess ?? true, // 统一权限字段 hasAccess: page.hasAccess, controller: page.controller || '', roles: page.roles || {}, allowedControls: page.allowedControls || [], isPage: true // 标记是页面节点,方便后续区分 }; flatControlsTreeData.push(transformedPage); // 1. 处理对象类型的controls(主菜单的控件) if (typeof page.controls === 'object' && page.controls !== null) { Object.entries(page.controls).forEach(([controlName, isAllowed]) => { flatControlsTreeData.push({ id: `${pageId}_${controlName}`, // 生成唯一ID,避免冲突 parentId: pageId, pageName: controlName, action: '', controlAccess: isAllowed, // 绑定控件的权限状态,用于复选框 isPage: false, // 标记是控件节点 controller: '', roles: {}, allowedControls: [] }); }); } // 2. 处理数组类型的Controls(子菜单的控件) if (Array.isArray(page.Controls)) { page.Controls.forEach(control => { // 从roles里获取当前控件的权限(如果有) let controlAccess = true; if (page.roles) { // 这里可以根据当前登录角色调整,示例默认取第一个角色的权限 const firstRole = Object.values(page.roles)[0]; controlAccess = firstRole.includes(control); } flatControlsTreeData.push({ id: `${pageId}_${control}`, parentId: pageId, pageName: control, action: '', controlAccess: controlAccess, isPage: false, controller: '', roles: page.roles || {}, allowedControls: page.allowedControls || [] }); }); } // 处理子菜单 if (Array.isArray(page.submenus)) { flatControlsTreeData = flatControlsTreeData.concat(flattenControlsData(page.submenus, pageId)); } // 处理子子菜单 if (Array.isArray(page.subchildMenu)) { flatControlsTreeData = flatControlsTreeData.concat(flattenControlsData(page.subchildMenu, pageId)); } }); console.log(flatControlsTreeData); return flatControlsTreeData; }
关键修改点
- 适配原始数据的字段差异:比如有的用
menuName,有的用pageName;有的用Action,有的用action/pageAction - 新增对象类型
controls的处理逻辑,遍历键值对生成控件节点,同时保留controlAccess字段存储权限状态 - 给节点添加
isPage标记,方便在dxTreeList里区分页面和控件,配置不同的列展示 - 给控件生成唯一ID(
pageId_controlName),避免不同页面下同名控件ID冲突 - 子菜单的数组类型
Controls也同步添加权限状态绑定,从roles里获取对应权限
dxTreeList绑定示例
配置dxTreeList时,通过isPage区分页面和控件,给控件节点添加复选框:
$("#treeList").dxTreeList({ dataSource: flattenControlsData(yourOriginalData), keyExpr: "id", parentIdExpr: "parentId", columns: [ { dataField: "pageName", caption: "名称" }, { caption: "权限", cellTemplate: function(container, options) { // 页面节点可以显示总权限,控件节点显示复选框 if (options.data.isPage) { $("<div>").text(options.data.pageAccess ? "已授权" : "未授权").appendTo(container); } else { $("<div>").dxCheckBox({ value: options.data.controlAccess, onValueChanged: function(e) { // 这里处理权限变更逻辑,比如更新原始数据或提交到后台 options.data.controlAccess = e.value; } }).appendTo(container); } } } ], expandedRowKeys: [0], // 默认展开根节点 showRowLines: true, showBorders: true });
内容的提问来源于stack exchange,提问作者Guhan Srinivasan
相关产品推荐
相关产品推荐

