很久没写文章了前几天有几个朋友问了我很多关于业务系统(ERPDRPCRM等)设计里很多概念性东西花了很长时间给他解释最后他门还是知其然不知其所以然这对于刚跨出学校大门的朋友来说理解起确实有点枯燥这里我以以前参与的用友ERPDRP产品项目里的部分设计为参考通过几篇文章来和大家分享业务系统里的部门平台通用部分的设计应用 本文主要介绍业务系统设计里的菜单设计关注我博客的朋友或许以前见过一篇我写的关于菜单的文章文章连接使用RadControls的RadMenu控件开发系统菜单这篇文章主要是介绍了RadControls的RadMenu控件的基本使用没有详细介绍到菜单如何设计为什么要那么设计本文就以这片文章为基础同样通过此文章的示例程序和示例数据库结合业务系统设计的相关术语介绍业务系统的菜单设计 首先看看上面的数据库设计结构其中ID为自动编号的主键字段Code为菜单编码(也称业务编码)Name为菜单名称Url为单击菜单所导航的路径ImageUrl为菜单上显示的图片地址ShortCut为快捷键Order为菜单项显示顺序Grade为菜单级限EndGrade为是否为末级菜单(既最后一菜单项)SupMenuCode为当前菜单项的父级菜单编码(对应于Code字段)完整的还应该包括是否受权限控制等字段这里不一一列出 上面的数据库设计其实很简单需要主要的字段有Code菜单编码(也称业务编码)在业务系统里通常设计为每一菜单项都可以认为是一个业务操作这里的Code非常重要业务系统的后续工作都是从这里开始通常与权限设计结合使用得最多 系统菜单应该是多层次结构的比如常见的Windows菜单业务系统里的菜单设计同样如此通过SupMenuCode字段来标记该菜单项属于那一项菜单的子菜单如果没有父级菜单(系统顶层菜单)则标记为 既然菜单有层次结构那就一定有层次标识通过Grade来标记EndGrade则表示当前菜单项在该层次级别上的菜单项上是否为末级 分析清楚了需求和菜单设计方案下面我们着手代码开发下图为项目解决方案截图 如上图Menucs里封装了数据库查询功能App_Data下存放的Access数据库RadControls为RadMenu控件所需要的相关文件Defaultaspx则为菜单UI界面 首先需要配置数据库连串如下 privatestaticstringconnectionString=Provider=MicrosoftjetOLEDB;dataSource= +HttpContextCurrentServerMapPath(@App_Data\MenuDBmdb); 接着我们需要一个执行SQL的方法如下代码块 privateDataTableExecuteQuery(stringcmdText) { using(OleDbConnectionconn=newOleDbConnection(connectionString)) { using(OleDbDataAdapteroda=newOleDbDataAdapter(cmdTextconn)) { DataSetds=newDataSet(); odaFill(ds); returndsTables[]; } } } 最后我们还需要写两个方法一个是查询顶层菜单的方法一个则是实现查询菜单下的子菜单方法(做法有很多种我个人建议把所有的数据查询出然后在操作内存数据这里为了方便理解我故采用多次查询数据库的方式来实现) publicDataTableGetMenu() { stringsql=select*frommenuwheregrade=; returnExecuteQuery(sql); }
publicDataTableGetMenuBySupCode(stringsupMenuCode) { stringsql=select*frommenuwheresupmenucode=+supMenuCode+; returnExecuteQuery(sql); } OK准备工作做好后现在就是需要到UI层上去做菜单的展现工作了菜单的展现我通过RadContrls的RadMenu控件来实现此控件相对ASPNET的标准Menu控件功能强大要使用RadMenu则需要注册控件的引用如果你是通过RadContrls控件库安装包安装的则会自动注册到VS工具箱和标准控件使用方法一样 <%@RegisterAssembly=RadMenuNetNamespace=TelerikWebControlsTagPrefix=rad%> <%菜单开始%> <rad:RadMenuID=SystemMenurunat=serverSkin=Vista> </rad:RadMenu> <%菜单结束%> 上面准备好了顶层菜单的查询方法直接通过该方法查询出顶层 菜单项对菜单进行初始化 protectedvoidPage_Load(objectsenderEventArgse) { if(!IsPostBack) { InitMenu(); } }
Menumenu=newMenu(); privatevoidInitMenu() { //查询出菜单配置信息 DataTabledtMenu=menuGetMenu();
for(inti=;i<dtMenuRowsCount;i++) { //Rad菜单项 RadMenuItemitem=newRadMenuItem();
itemID=dtMenuRows[i][Code]ToString(); itemText=dtMenuRows[i][Name]ToString(); itemValue=dtMenuRows[i][Url]ToString(); itemAccessKey=dtMenuRows[i][ShortCut]ToString();
thisSystemMenuItemsAdd(item);
//菜建子菜单 InitSubMenu(itemdtMenuRows[i][Code]ToString()); } } 我们设计为多层次菜单结构那么在初始化顶层菜单的时候就应该判断该菜单项是否有子菜单如果有则也初始化子菜单如果是多级层次的结构通过递归算法来完成多层次的初始化如下代码块
privatevoidInitSubMenu(RadMenuItemitemstringsupMenuCode) { //根据父菜单编码查询出子菜单配置项 DataTabledtMenu=menuGetMenuBySupCode(supMenuCode);
if(dtMenu!=null) { foreach(DataRowdataRowindtMenuRows) { RadMenuItemsubItem=newRadMenuItem();
subItemID=dataRow[ID]ToString(); subItemText=dataRow[Name]ToString(); subItemValue=dataRow[Url]ToString(); subItemAccessKey=dataRow[ShortCut]ToString();
itemItemsAdd(subItem);
if(ConvertToInt(dataRow[EndGrade])!=) { InitSubMenu(subItemConvertToString(dataRow[Code])); } } } } 如上就完成了系统的菜单设计实际项目开发中的设计与这样的设计几乎都大同小异主要是了解设计思想或许看完了本文你还是没有明白为什么要这样设计如果是这样那请你关注下一篇文章下一篇文章中就用到了菜单中的业务编码应该可以给一个满意的答案 |