本系列文章目录:
      1、 业务系统设计之一:系统菜单设计 
      2、 业务系统设计之二:系统主控设计(上)
     系统主控简单的理解就是一个系统的操作控制或者也可以叫住系统操作平台。一个良好的系统主控可以让系统更加灵活操作、应用。至于技术上的实现我们可以有很多中选择,所以这里不谈论什么技术好等话题。本文将接着上一篇《 业务系统设计之一:系统菜单设计 》介绍业务系统里的主控设计方法,以及怎么将系统的各部分(系统菜单、系统主控、业务操作等等)衔接在一起。 或许我这样说还所以很多朋友不能理解什么是系统主控,那好就请你仔细看看下图:
 
      上图是我在126邮箱中的截图,它的这种主控方式我个人感觉就是很爽的一种方式。收件箱、百宝箱、写信等操作都以一个新的操作界面打开,然后将其挂在主控的菜单工具拦上,多任务之间可以相互切换操作,实现了多任务可以并行处理,每项功能操作都有自己的状态(比如写信提交了不会影响其他的界面),至于其他好处吧我这里就不多废话。
      通过上面的分析与了解,下面我们就来看看像这样的系统主控是怎么实现的。以上一篇文章《业务系统设计之系统菜单设计》为基础,通过点击菜单项目则打开菜单项对应的页面,菜单运行效果如下: 系统主控的开发其实和其他功能一样简单,只要弄清楚了功能需求就OK。
       功能需求大致如下:
      1、系统入口点(这肯定就是系统菜单--下拉菜单、树型菜单等)
      2、全局显示容器(既显示内嵌页面的容器)
      3、点击菜单项可以在容器上创建页签选项,如果当前菜单项所对应的页面已经打开则选中该项。
      4、在容器中选择页签项,被选择项突出显示。
      5、每一个页签下对应一个页面,可相互独立操作互不影响其他页签项。
      5、每一个页签带有关闭功能,点击指定关闭区域或图标既可实现关闭当前页签。
      6、双击可实现关闭页签。
      7、其他界面效果控制等。
      本文中的数据库结构借鉴于市场上主流ERP系统的菜单表结构,程序运行效果同上图一样,对菜单表有不清楚的朋友可留言提问,这里我不做详细解释。SQL代码如下:
SET  ANSI_NULLS  ON
GO
SET  QUOTED_IDENTIFIER  ON
GO
IF   NOT   EXISTS  ( SELECT   *   FROM  sys.objects  WHERE   object_id   =   OBJECT_ID (N ' [dbo].[Menu] ' AND  type  in  (N ' U ' ))
BEGIN
CREATE   TABLE   [ dbo ] . [ Menu ] (
    
[ AutoID ]   [ uniqueidentifier ]   ROWGUIDCOL    NOT   NULL   CONSTRAINT   [ DF_Menu_AutoID ]    DEFAULT  ( newid ()),
    
[ Code ]   [ varchar ] ( 50 NULL ,
    
[ Name ]   [ varchar ] ( 50 NULL ,
    
[ Grade ]   [ int ]   NULL ,
    
[ HasSub ]   [ bit ]   NULL ,
    
[ SupMenuCode ]   [ varchar ] ( 50 NULL ,
    
[ EndGrade ]   [ bit ]   NULL ,
    
[ Order ]   [ int ]   NULL ,
    
[ ReqeustUrl ]   [ varchar ] ( 100 NULL ,
    
[ IsItemGroup ]   [ bit ]   NULL ,
    
[ IsControl ]   [ bit ]   NULL ,
 
CONSTRAINT   [ PK_Menu ]   PRIMARY   KEY   CLUSTERED  
(
    
[ AutoID ]   ASC
)
WITH  (PAD_INDEX   =   OFF , STATISTICS_NORECOMPUTE   =   OFF , IGNORE_DUP_KEY  =   OFF , ALLOW_ROW_LOCKS   =   ON , ALLOW_PAGE_LOCKS   =   ON ON   [ PRIMARY ]
ON   [ PRIMARY ]
END
 
      建立好ASP.NET WEB应用程序,并将相关的资源(本文里的资源包括图片、样式、第三方控件等)整理好。数据操作使用Linq To Sql完成,整理好的解决方案如下图示:
            
      本文中系统主控的核心在于RadContrls控件RadMenu和RadTabstrip的组合,导航由RedMenu完成,主控端主要由RadTabstrip完成。要实现一个完美的系统主控,页面的控制和布局都很重要,这里我采用母版页技术将公共的部分放在母版页,通过该母版页建立的内容页来作为系统的主控页面。母版页完整html编码
 
<% @ Master Language = " C# "  AutoEventWireup = " true "  CodeBehind = " MasterPage.master.cs "  Inherits = " Web.MasterPage "   %>
<% @ Register Assembly = " RadMenu.Net2 "  Namespace = " Telerik.WebControls "  TagPrefix = " radM "   %>

< html  xmlns ="http://www.w3.org/1999/xhtml"   >
< head  runat ="server" >
    
< title > 系统主控母版 </ title >
    
< style  type ="text/css" >
        a,body,div,input,li,p,span,td 
{  font-size : 12px ; }
        #headDIV 
{ height : 60px ; width : 100% ; text-align : center ; }
        #contentCenter 
{ width : 100% ; height : 400px ; }
        #stateDIV 
{ width : 100% ; height : 20px ; background-p_w_picpath : url('Images/stateBg.gif') ; bottom : 0px ; }
    
</ style >
    
    
< script  type ="text/javascript" >
    
/*
    * 应用程序加载时根据用户浏览器初始化窗体大小
    
*/
    window.onload 
=   function ()
    {
       
if  (window.screen) 
       { 
          
var  aw  =  screen.width; 
          
var  ah  =  screen.height; 
          window.moveTo(
0 0 ); 
          window.resizeTo(aw, ah); 
       }
    }
    
</ script >
</ head >
< body  id ="Master"  style ="margin: 0px;margin-top:0px;margin-left:20px;margin-right:0px;" >
    
< form  id ="form1"  runat ="server" >
    
< br  />
    
<% -- 头部导航开始 -- %>
    
< div  id ="headDIV" >
        
< span  style ="line-height:30px;" >
            
< radM:RadMenu  ID ="ERPMenu"  runat ="server"
                OnClientMouseOver
="OnMouseOver"  
                OnClientItemClicked
="OnClientClick"  
                Skin
="Web20"  
                ExpandDelay
="100"  
                EnableAutoScroll
="True"   >
                
< CollapseAnimation  Duration ="100"  Type ="InQuint"   />
                
< ExpandAnimation  Duration ="250"   />
            
</ radM:RadMenu >
        
</ span >
    
</ div >
    
<% -- 头部导航结束 -- %>
    
    
<% -- 内容部分开始 -- %>
    
< div  id ="contentCenter" >
        
< div  id ="rightDIV"  style ="height:100%;width:98%;vertical-align:top;float:left;" >
            
< asp:ContentPlaceHolder  ID ="CPHERP"  runat ="server" >
            
</ asp:ContentPlaceHolder >
        
</ div >
    
</ div >
    
<% -- 内容部分结束 -- %>
    
    
<% -- 系统状态栏开始 -- %>
    
< div  id ="stateDIV" >
        
< span  id ="NowTime"  runat ="server"  style ="float:left;margin-left:20px;" ></ span >
        
< span  style ="float:right;margin-right:20px;" >
            当前操作员:admin 
&nbsp;&nbsp; | &nbsp;&nbsp;
            登录系统时间:
<%   =  DateTime.Now.ToString()  %>
        
</ span >
    
</ div >
    
<% -- 系统状态栏结束 -- %>
    
</ form >
</ body >
</ html >
< script  type ="text/javascript" >
// 设置主页的高度和宽度
SetContentHeight();  
SetContentWidth(); 
</ script >
 
      从上面代码中可以发现,里面调用了4个JavaScript方法:两个针对于RadMenu控件的OnMouseOver,OnClientClick,另外两个是设置页面布局效果的方法:SetContentHeight(), SetContentWidth()。他们的作用分别是设置鼠标移动的效果、点击菜单项时所触发的客户端方法,后面两个则是做页面的效果收缩用的,代码如下:
* 程序功能:RadMenu客户端单击事件
* 开发日期: 2008 - 11 - 08  Beniao
* 参数说明:
*           sender:执行请求的当前对象
*           eventArgs:当前对象的事件
*------------------------------------------------
*>>>>> 直接使用硬参数,Url值为相对路径(不加任何前缀修饰)
*/
function  OnClientClick(sender, eventArgs)
{
    
var  value  =  eventArgs.Item.Value;   // 隐藏Url
     var  text  =  eventArgs.Item.Text;      // 显示文本

    
// 设置容器高度
    SetContentHeight();
    
// 关闭菜单项
    CloseItem(sender, eventArgs);
    
    
// 是否为首节点
     if (IsFirstTab(value))
    {
        
// 显示当前页签    
        DisplayCurrentTab(text);
        
return ;
    }
    
    
if (value  !=   ' # ' )
    {
        
// 存在则直接显示(即实现选中)
         if (IsExsitTab(value))
        {
            DisplayCurrentTab(text);
            eventArgs.Item.Blur();
        }
        
else
        {
            
// 是否为动态创建的第一个Tab
            
            
// 不存在,创建新的
            CreateTabPage(value,text);
            eventArgs.Item.Blur();
        }
    }
}

/*
*程序功能:鼠标移入
*开发日期:2008-11-08 13:20 Beniao
*参数说明:
*          sender:执行请求的当前对象
*          eventArgs:当前对象的事件
*/
function  OnMouseOver(sender, eventArgs)
{
    
var  tabStrip  =   <%= RadTabStripMain.ClientID  %> ;
    
var  selectTab  =  tabStrip.SelectedTab;
    
    
// var id = eventArgs.Tab.ID;
     var  id  =  selectTab.ID;
    
var  className  =  document.getElementById(id).className;
    
if (className  ==   " selected " )
    {
        
//
    }
    
else
    {
        document.getElementById(id).firstChild.style.color
= ' #ffffff ' ;
        
// document.getElementById(id).firstChild.style.font-weight='bold';
    }
}
 
// Add by Beniao at 2008-11-07 16:05
//
判断屏幕的高度,然后设置内容的高度
function  SetContentHeight()
{
    
var  screenHeight  =  document.body.clientHeight  +  window.screenTop;
    
    
// 浏览器所支持的屏幕高度
     var  maxh  =  document.body.clientHeight;
    
    
// 获取页面上iframe,主页内容
     var  frame  =  document.getElementById( " frm0 " );
    
// 内容容器(包含页签)
     var  contentDiv  =  document.getElementById( " contentCenter " ); 
    
// 不包含页签
     var  divMain  =  document.getElementById( " divMain " );
    
// 头块
     var  headDiv  =  document.getElementById( " headDIV " );
    
    contentDiv.style.height 
=  maxh;
    
    
if (divMain)
    {
        divMain.style.height 
=  maxh;    
    }
    
    
if (headDiv.style.display  ==   "" )
    {
        divMain.style.height 
=  maxh;
    }
    
else
    {
        
// 隐藏块后,内容快高度增加
        divMain.style.height  =  maxh  +  headDiv.clientHeight;
    }
}

// Add by Beniao at 2008-11-07 16:05
//
判断屏幕的宽度,然后设置内容的宽度
function  SetContentWidth()
{
    
// 屏幕宽度
     var  scrrenWidth  =  document.body.offsetWidth  +  window.screenLeft;
    
var  maxWidth  =  document.body.clientWidth;
    
    
var  frame  =  document.getElementById( " frm0 " );
    
var  contentDiv  =  document.getElementById( " contentCenter " );
    
var  headDiv  =  document.getElementById( " headDIV " ); 
    
var  contentTab  =  document.getElementById( " ContentTab " );
    
    frame.style.width 
=  maxWidth;
    contentDiv.style.width 
=  maxWidth;
}
 
      本文就简单介绍这些,在后续文章里在做详细介绍如何去实现系统主控开发。主控设计最终效果如下图(数据库菜单配置和运行效果图)所示:            
      
      
 
      注:系统主控示例代码在后续文章里提供下载,有需要的朋友可关注后续文章。