首页 > 代码库 > 代码“小白”的温故而知新(一)-----OA管理系统

代码“小白”的温故而知新(一)-----OA管理系统

      古人云:温故而知新。这是极好的,近来,作为一个小白,利用点空闲时间把之前几个月自己写过的一个作为练手的一个OA系统又重新拿来温习一番,希望在巩固基础之上能得到新的启示。现在回想起来,之前一个人,写写停停,不觉感叹,平时工作中团队的重要性以及个人力量的渺小。因为是练手的项目,整个系统从数据库到前端都是自己设计,所以不免显得有点寒碜,不喜勿喷,但该有的重点还是有的,至于美工,哈哈,简洁也是一种美不是吗,只能这样安慰自己了。

     准备工作:

     1.进行初步的需求分析(有四大板块:我的桌面,人力资源管理,考勤管理,工作流管理)

     2.每个大板块下又分小块

     (我的桌面---》每日考勤,提交申请,我的审批【高级员工】,我的申请;

        人力资源----》员工管理,部门管理,职位管理,角色管理;

       考勤管理----》工作日设置,工作时间设置,考勤记录查询;

       工作流管理----》流程管理)

    3.技术实现:ASP.NET  MVC,EF,Jquery,T4,log4Net,MD5,Jquery-easy-uI,Sqlser2008,Membercache,后期用到spring.net

 

先看看前期大概的一个页面展示图:

主页面:

技术分享

员工信息页面:

技术分享

添加员工:

技术分享

编辑员工:

技术分享

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------

正文:

好了,闲话不多说,先设计数据库吧,在设计数据库之前,有几点我们也需要注意,

1.对于表的命名一定要规范;

2.表的设计原则是一张表只记录一件事,如果表与表有关系的,通过外键关联。

在这里面,建表需要注意的是对菜单表ActionInfo的设计,因为它分级别,有一级菜单,二级菜单,对于这种表的设计,

ActionId     标识列  主键---》(渲染到前端的是id)

Title   标题   nvarchar(20)---》(text)                    

Leval  1  2 int   决定将来显示的层级图标(1代表菜单,2代表菜单项)

URL:允许为空,一级没有,二级有【通过这个url访问】

PrentId  int   not null  对于一级菜单,取值为0【重要】

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

接下来就是搭建框架了,采用简单抽象工厂三层的项目结构

技术分享

框架搭完,先做主页面,Home/Index    Home控制下的Index的html代码  主页面

技术分享
  1 @using Model.Models
  2 @{
  3     Layout = null;
  4     EmployeeInfo emp = ViewData["user"] as EmployeeInfo;
  5    
  6 }
  7 
  8 <!DOCTYPE html>
  9 
 10 <html>
 11 <head>
 12     <meta name="viewport" content="width=device-width" />
 13     <title>通达OA</title>
 14     <script src=http://www.mamicode.com/"~/Scripts/jquery-1.7.1.js"></script>
 15     <script src=http://www.mamicode.com/"~/Scripts/MyAjaxForm.js"></script>
 16     <script src=http://www.mamicode.com/"~/Scripts/jquery.easyui.min.js"></script>
 17     <script src=http://www.mamicode.com/"~/Scripts/easyui-lang-zh_CN.js"></script>
 18     <link href=http://www.mamicode.com/"~/Content/easyui.css" rel="stylesheet" />
 19     <link href=http://www.mamicode.com/"~/Content/icon.css" rel="stylesheet" />
 20    <style type="text/css">
 21        a
 22        {
 23            text-decoration:none;
 24        }
 25        #emp
 26        {
 27            position:absolute;
 28            color:red;
 29            bottom:5px;
 30            left:5px;
 31 
 32        }
 33      
 34    </style>
 35 </head>
 36     
 37 <body class="easyui-layout" onselectstart=" return false;">
 38     <div data-options="region:‘north‘,split:false" style="height: 110px; background: url(/Content/Images/OA2.png) no-repeat 0px -52px ;position:relative">
 39        <p id="emp">欢迎您的登录:@emp.EmpName <a  href=http://www.mamicode.com/"/User/Login?state=false">[注销用户]</a></p>
 40     </div>
 41 
 42     <div data-options="region:‘west‘,title:‘导航菜单‘,split:false" style="width: 150px;  background: url(/Content/Images/OA.jpg) no-repeat -20px ">
 43         <ul id="tt">
 44         </ul>
 45     </div>
 46 
 47     <div data-options="region:‘center‘,title:‘主页面‘" style="padding: 5px; background: url(/Content/Images/OA3.jpg) no-repeat; opacity:0.88">
 48         <div id="p" style="padding: 10px;">
 49                      
 50         </div>  
 51     </div>
 52 
 53     @* 弹出的独立窗口 *@
 54     <div id="editwin">
 55         <iframe id="editframe" width="100%" frameborder="0" scrolling="no">
 56             
 57         </iframe>
 58     </div>  
 59 
 60 
 61     <script type="text/javascript">
 62 
 63         //刷新页面
 64         function afterSave() {
 65             $("#editwin").window("close");
 66             $("#editframe").attr("src", "null");
 67             $("#dg").datagrid("reload");
 68         };
 69 
 70 
 71         $(#tt).tree({
 72             url: "/Action/LoadData",
 73             checkbox: true,
 74             lines: true,
 75             dnd: false,
 76             animate: true,
 77             formatter: function (node) {
 78                 return ("[" + node.text + "]");
 79             },
 80             onClick: function (node) {
 81                 $(#p).panel({
 82                     fit:true,
 83                     title: node.text,
 84                     href:node.url
 85                    
 86                 });
 87             }
 88            
 89         });
 90    
 91         //弹窗
 92         function popEditWindow(caption,width,src)
 93         {    
 94                 $("#editwin").css("display", "block");
 95                 $(#editwin).window({
 96                     title: caption,
 97                     width: width,                    
 98                     resizable: false,
 99                     shadow:false,
100                     modal: true
101                 });
102              
103                 $("#editframe").attr("src", src);
104                 $("#editframe").load(function () {
105                     var mainheight = $(this).contents().find("body").height() + 30;
106                     $(this).height(mainheight);
107                 });
108          
109         }
110      
111 
112 
113     </script>
114 </body>
115 </html>
View Code

我整体的页面布局用的是Easy-UI,首页内容使用的是panel组件,菜单栏使用的是tree组件。

需要注意的是:

1.panel组件可以通过设置href属性从远程加载页面,但只会加载页面的body内容,可是像添加员工,编辑员工这样的,我们需要额外进行一些css样式的改变时,他却变得无效了,所以在面板之内,我添加了一个Iframe框架,Iframe  框架  有一个src属性,这个属性可以请求一个远程界面(完整的,独立的页面),你可以在里面做上你自己的css样式进行改变。

2.iframe框架如何自适应高度?

解决方案:

 $("#editframe").load(function () {

    var mainheight = $(this).contents().find("body").height() + 30;

      $(this).height(mainheight);

                    });

3.如何在iframe框架内嵌的网页中去访问他所在的主页面的资源?

解决方案:

在主页面定义要使用的资源方法,然后再包含iframe的子页面中调用window.parent.方法名()。

 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Action/Index   ||菜单栏代码

技术分享
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using BLL;
using Model.Models;

namespace UI.Controllers
{
    public class ActionController :BaseController
    {
        //
        // GET: /Action/

        public ActionResult Index()
        {
            return View();
        }
        /// <summary>
        /// 一次性加载菜单数据
        /// </summary>
        /// 
        /// <returns>
        /// 符合tree树形控件的json格式的对象
        /// </returns>
        public ActionResult LoadData()
        {
            //没有进行权限分配,默认登录后加载所有菜单列表
            List<ActionInfo> actionList = new ActionService().GetActionList(a => true);

            //调用存储过程进行过滤
           // List<ActionInfo> actionList = new ActionService().GetActionListByEmp(this.user.EmpId);

            //采用EF查询进行过滤
            //List<ActionInfo> actionList = new ActionService().GetActionByEmpId(this.user.EmpId);

            //构造符合tree树形控件的json格式的对象
            List<MenuItem> menulist = new List<MenuItem>();
            foreach (var item in actionList.Where(a=>a.Leval==1))
            {
                //第一级菜单
                MenuItem first = new MenuItem { id = item.ActionId, text = item.Title, state = "closed", url = null };
                List<MenuItem> second = new List<MenuItem>();
                List<ActionInfo> secondActionList = actionList.Where(a=>a.PrentId==item.ActionId).ToList();
                foreach (var i in secondActionList)
                {
                    second.Add(new MenuItem { id = i.ActionId, text = i.Title,state="open",url = i.URL });
                }
                first.children = second;
                menulist.Add(first);
            }
            //JSON序列化
            JavaScriptSerializer jss = new JavaScriptSerializer();
            string result = jss.Serialize(menulist);
            return Content(result);
        }


    }

    //构造符合tree组件的实体类
    public class MenuItem
    {
        public int id { get; set; }
        public string  text { get; set; }
        public string state { get; set; }
        public string  url { get; set; }
        public List<MenuItem>  children { get; set; }
    }
}
View Code

Employee     ||控制器下代码

技术分享
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Model.Models;
using BLL;
using UI.Models;
using System.Web.Script.Serialization;
using Newtonsoft.Json;

namespace UI.Controllers
{
    public class EmployeeController : BaseController
    {
        //
        // GET: /Employee/

        public ActionResult List()
        {
            return View();
        }

        public ActionResult LoadData(int page, int rows)
        {

            int totalCount = 0;
            List<EmployeeInfo> emplist = new EmployeeService().GetEmpListByPage(page, rows, ref totalCount);
            //解决方案二:使用Newtonsoft程序集
            var result = JsonConvert.SerializeObject(new { total = totalCount, rows = emplist });          
            return Content(result);

        }

        [HttpGet]
        public ActionResult AddEmp(int? id)
        {
            string url = "/Employee/AddEmp";
            List<DepartmentInfo> depList = new DepartmentService().GetDepList(d => true);
            List<PositionInfo> posList = new PositionService().GetPosList(p => true);
            EmployeeInfo emp;
            ViewEmpModel model = new ViewEmpModel();
            if (id != null)
            {
                url = "/Employee/Update";
                emp = new EmployeeService().GetDepByEmp(e => e.EmpId == id).SingleOrDefault();
                model = new ViewEmpModel { EmpName = emp.EmpName, EmpBirthday = emp.EmpBirthday.ToString(), EmpEmail = emp.EmpEmail, EmpTelephone = emp.EmpTelephone, EmpUrl = url, LoginId = emp.LoginId, EmpGender = emp.EmpGender, DepId = emp.DepId, EmpId = emp.EmpId, PosId = emp.PosId, LoginPwd = emp.LoginPwd, DelFlag = emp.DelFlag };
                ViewData["DepId"] = new SelectList(depList, "DepId", "DepName", emp.DepId);
                ViewData["PosId"] = new SelectList(posList, "PosId", "PosName", emp.PosId);
            }
            else
            {
                ViewData["DepId"] = new SelectList(depList, "DepId", "DepName");
                ViewData["PosId"] = new SelectList(posList, "PosId", "PosName");
                ViewData["deplist"] = depList;
                ViewData["poslist"] = posList;
            }
            ViewData.Model = model;
            return View();
        }

        [HttpPost]
        public ActionResult AddEmp(EmployeeInfo emp)
        {
            emp.DelFlag = false;
            emp.LoginPwd = "888888";
            bool flag = new EmployeeService().AddEmp(emp);
            return flag ? Content("ok") : Content("fail");
        }

        //展示员工详细信息
        public ActionResult ShowEmp(int id)
        {
            EmployeeInfo emp = new EmployeeService().GetDepByEmp(e => e.EmpId == id).SingleOrDefault();

          List<AdjustPosition> adplist = new AdjustPositionService().GetAdpList(a => a.EmpId == emp.EmpId);
          List<AdjustDepartment> addlist = new AdjustDepartmentService().GetAddList(a => a.EmpId == emp.EmpId);


            string gender = emp.EmpGender ? "" : "";
            ViewData["gender"] = gender;
            ViewData["adp"] = adplist;
            ViewData["add"]=addlist;
            return View(emp);
        }

        //修改员工
        [HttpPost]
        public ActionResult Update(EmployeeInfo emp)
        {
            bool falg = new EmployeeService().UpdateEmp(emp);
            return falg ? Content("ok") : Content("fail");
        }
        /// <summary>
        /// 删除员工
        /// </summary>
        /// <param name="idlist"></param>
        /// <returns></returns>
        public ActionResult Delete(string idlist)
        {
            bool falg = new EmployeeService().DeleteEmpList(idlist);
            return falg ? Content("ok") : Content("fail");
        }

        //员工调整
        [HttpGet]
        public ActionResult AdjustEmp(int id)
        {           
            List<DepartmentInfo> depList = new DepartmentService().GetDepList(d => true);
            List<PositionInfo> posList = new PositionService().GetPosList(p => true);
            EmployeeInfo emp = new EmployeeInfo();
            emp = new EmployeeService().GetDepByEmp(e => e.EmpId == id).SingleOrDefault();
            //如何将查询到的数据绑定到视图中的下拉列表框,第四个参数是选中的值
            ViewData["DepId"] = new SelectList(depList, "DepId", "DepName", emp.DepId);
            ViewData["PosId"] = new SelectList(posList, "PosId", "PosName", emp.PosId);
            ViewData["deplist"] = depList;
            ViewData["poslist"] = posList;
            ViewData.Model = emp;

            ViewData["EmpId"]=emp.EmpId;
            ViewData["OldDepartmentId"]=emp.DepId;
            ViewData["OldPositionId"] = emp.PosId;
            return View();
        }

        [HttpPost]
        public ActionResult Adjust(EmployeeInfo emp,AdjustDepartment add,AdjustPosition adp)
        {
            //接收原来部门的编号
            int OldDepartmentId = Convert.ToInt32(Request["OldDepartmentId"]);
            //接收原来职位的编号
            int OldPositionId = Convert.ToInt32(Request["OldPositionId"]);

            AdjustManagerService am = new AdjustManagerService();
            adp.NewPositionId = emp.PosId;
            add.NewDepartmentId = emp.DepId;
            adp.AdjustTime = DateTime.Now;
            add.AdjustTime = DateTime.Now;
            bool falg;
            //职位调整并且部门没调整
            if (add.NewDepartmentId == add.OldDepartmentId&&adp.NewPositionId != adp.OldPositionId)
            {
              
                falg = am.Add(adp);
            }
            //部门调整并且职位没调整
            else if (add.NewDepartmentId != add.OldDepartmentId && adp.NewPositionId == adp.OldPositionId)
            {
                falg = am.Add(add);
            }
             //部门和职位都调整了
            else if (add.NewDepartmentId != add.OldDepartmentId && adp.NewPositionId != adp.OldPositionId)
            {
                falg = am.Add(add,adp);
            }                        
            falg = new EmployeeService().UpdateEmp(emp);       
            return falg ? Content("ok") : Content("fail");


        }
    }
}
View Code

给出Employee的List的视图代码,后面部门类似参考

技术分享
  1 @{
  2     Layout = null;
  3 }
  4 <!DOCTYPE html>
  5 <html>
  6 <head>
  7     <meta name="viewport" content="width=device-width" />
  8     <title>员工界面</title>
  9 </head>
 10 <body>
 11     <table id="dg">
 12     </table>
 13     <script type="text/javascript">
 14         var fieldName;
 15         $("#editwin").css("display", "none");
 16         $(#dg).datagrid({
 17             url: /Employee/LoadData,
 18             pagination: true,//page=1&rows=10
 19             pageList: [10, 15, 20],
 20             columns: [[
 21                 { field: check, checkbox: true, width: 50 },
 22                 { field: EmpId, title: 员工编号, width: 50 },
 23                 { field: EmpName, title: 员工姓名, width: 100 },
 24                 {
 25                     field: EmpGender, title: 员工性别, width: 100, formatter: function (value, row, index) {
 26                         return value ? "" : "";
 27                     }
 28                 },
 29                 { field: EmpBirthday, title: 员工生日, width: 100 },
 30                 { field: EmpTelephone, title: 员工电话, width: 100 },
 31                 { field: EmpEmail, title: 邮件地址, width: 200 },
 32                 {
 33                     field: Operator, title: 员工操作, width: 300,
 34                     formatter: function () {
 35                         return "<a href=http://www.mamicode.com/‘#‘ class=‘editemp‘>编辑员工 |  详细信息 |员工调整 |分配权限  ";
 36                     }
 37                 }
 38 
 39             ]],
 40             toolbar: [{
 41                 iconCls: icon-add,
 42                 text: 添加员工,
 43                 handler: function () {
 44                     //调用在主页面Index中封装的弹窗函数
 45                     popEditWindow("添加员工", 400, "/Employee/AddEmp");                  
 46                 }
 47             }, -, {
 48                 iconCls: icon-cancel,
 49                 text: 删除员工,
 50                 handler: function () {
 51                     var rows = $("#dg").datagrid(getSelections);
 52                     if (rows.length == 0) {
 53                         $.messager.alert("提示", "请选择删除行!");
 54                         return;
 55                     }
 56                     $.messager.confirm(确认, 确定删除吗?, function (r) {
 57                         if (r) {
 58                             //获取编号id,并以一定的规则做成字符串
 59                             var idlist = "";
 60                             for (var i = 0; i < rows.length; i++) {
 61                                 idlist = idlist + rows[i]["EmpId"] + ",";
 62                             }
 63                             //截取
 64                             idlist = idlist.substr(0, idlist.length - 1);
 65                             //异步请求发送要删除的字符串
 66                             $.ajax({
 67                                 url: "/Employee/Delete",
 68                                 type: "post",
 69                                 data: { "idlist": idlist },
 70                                 dataType: "text",
 71                                 success: function (res) {
 72                                     if (res == "ok") {
 73                                         $("#dg").datagrid("reload");
 74                                     }
 75                                 }
 76                             })
 77                         }
 78                     });
 79                 }
 80             }],
 81             onClickCell: function (rowIndex, field, value) {
 82                 fieldName = field;
 83             },
 84             onSelect: function (rowIndex, rowData) {
 85                 if (fieldName == "Operator") {
 86                     $("#dg").datagrid("unselectRow", rowIndex);
 87                 }
 88             },
 89             onl oadSuccess: function () {
 90                 $(".editemp").click(function () {             
 91                     var empid = $(this).parents("tr").children("td").eq(1).text();
 92                     popEditWindow("编辑员工", 400, "/Employee/AddEmp/"+empid);           
 93                 })
 94             }
 95         });
 96 
 97         //展示员工详细信息
 98         function showEmp(node) {
 99             $(function(){
100                 var empid = $(node).parents("tr").children().eq(1).text();
101                 popEditWindow("员工详细信息", 500, "/Employee/ShowEmp/" + empid);
102             })   
103         }
104 
105         //员工调整弹窗
106         function AdjustEmp(node) {
107             $(function () {
108                 var empid = $(node).parents("tr").children().eq(1).text();
109                 popEditWindow("员工调整", 400, "/Employee/AdjustEmp/" + empid);
110             })
111         }
112         //分配权限
113         function SetAction(node) {
114             $(function () {
115                 var empid = $(node).parents("tr").children().eq(1).text();
116                 popEditWindow("分配权限", 400, "/Role/SetRole/" + empid);
117             })
118         }
119     </script>
120 
121 </body>
122 
123 </html>
View Code

 【注】:

常见错误:检测到序列化循环引用

解决方案一:创建一个VO模型对象,不包含导航属性;

解决方法二:推荐使用牛顿JSON程序集

 

好了,今天的复习就到这。期待下一节的“温故而知新(二)”。

 

代码“小白”的温故而知新(一)-----OA管理系统