古人云:温故而知新。这是极好的,近来,作为一个小白,利用点空闲时间把之前几个月自己写过的一个作为练手的一个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代码  主页面

 @using Model.Models
@{
Layout = null;
EmployeeInfo emp = ViewData["user"] as EmployeeInfo; } <!DOCTYPE html> <html>
<head>
<meta name="viewport" content="width=device-width" />
<title>通达OA</title>
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script src="~/Scripts/MyAjaxForm.js"></script>
<script src="~/Scripts/jquery.easyui.min.js"></script>
<script src="~/Scripts/easyui-lang-zh_CN.js"></script>
<link href="~/Content/easyui.css" rel="stylesheet" />
<link href="~/Content/icon.css" rel="stylesheet" />
<style type="text/css">
a
{
text-decoration:none;
}
#emp
{
position:absolute;
color:red;
bottom:5px;
left:5px; } </style>
</head> <body class="easyui-layout" onselectstart=" return false;">
<div data-options="region:'north',split:false" style="height: 110px; background: url(/Content/Images/OA2.png) no-repeat 0px -52px ;position:relative">
<p id="emp">欢迎您的登录:@emp.EmpName <a href="/User/Login?state=false">[注销用户]</a></p>
</div> <div data-options="region:'west',title:'导航菜单',split:false" style="width: 150px; background: url(/Content/Images/OA.jpg) no-repeat -20px ">
<ul id="tt">
</ul>
</div> <div data-options="region:'center',title:'主页面'" style="padding: 5px; background: url(/Content/Images/OA3.jpg) no-repeat; opacity:0.88">
<div id="p" style="padding: 10px;"> </div>
</div> @* 弹出的独立窗口 *@
<div id="editwin">
<iframe id="editframe" width="100%" frameborder="" scrolling="no"> </iframe>
</div> <script type="text/javascript"> //刷新页面
function afterSave() {
$("#editwin").window("close");
$("#editframe").attr("src", "null");
$("#dg").datagrid("reload");
}; $('#tt').tree({
url: "/Action/LoadData",
checkbox: 'true',
lines: 'true',
dnd: 'false',
animate: 'true',
formatter: function (node) {
return ("[" + node.text + "]");
},
onClick: function (node) {
$('#p').panel({
fit:true,
title: node.text,
href:node.url });
} }); //弹窗
function popEditWindow(caption,width,src)
{
$("#editwin").css("display", "block");
$('#editwin').window({
title: caption,
width: width,
resizable: false,
shadow:false,
modal: true
}); $("#editframe").attr("src", src);
$("#editframe").load(function () {
var mainheight = $(this).contents().find("body").height() + ;
$(this).height(mainheight);
}); } </script>
</body>
</html>

我整体的页面布局用的是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==))
{
//第一级菜单
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; }
}
}

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 = ;
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 = "";
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"); }
}
}

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

 @{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>员工界面</title>
</head>
<body>
<table id="dg">
</table>
<script type="text/javascript">
var fieldName;
$("#editwin").css("display", "none");
$('#dg').datagrid({
url: '/Employee/LoadData',
pagination: true,//page=1&rows=10
pageList: [, , ],
columns: [[
{ field: 'check', checkbox: true, width: },
{ field: 'EmpId', title: '员工编号', width: },
{ field: 'EmpName', title: '员工姓名', width: },
{
field: 'EmpGender', title: '员工性别', width: , formatter: function (value, row, index) {
return value ? "女" : "男";
}
},
{ field: 'EmpBirthday', title: '员工生日', width: },
{ field: 'EmpTelephone', title: '员工电话', width: },
{ field: 'EmpEmail', title: '邮件地址', width: },
{
field: 'Operator', title: '员工操作', width: ,
formatter: function () {
return "<a href='#' class='editemp'>编辑员工</a> | <a href='#' class='detail' onclick='showEmp(this);'>详细信息</a> |<a href='#' class='adjustemp' onclick='AdjustEmp(this)'>员工调整</a> |<a href='#' class='setAction' onclick='SetAction(this)'>分配权限</a> ";
}
} ]],
toolbar: [{
iconCls: 'icon-add',
text: '添加员工',
handler: function () {
//调用在主页面Index中封装的弹窗函数
popEditWindow("添加员工", , "/Employee/AddEmp");
}
}, '-', {
iconCls: 'icon-cancel',
text: '删除员工',
handler: function () {
var rows = $("#dg").datagrid('getSelections');
if (rows.length == ) {
$.messager.alert("提示", "请选择删除行!");
return;
}
$.messager.confirm('确认', '确定删除吗?', function (r) {
if (r) {
//获取编号id,并以一定的规则做成字符串
var idlist = "";
for (var i = ; i < rows.length; i++) {
idlist = idlist + rows[i]["EmpId"] + ",";
}
//截取
idlist = idlist.substr(, idlist.length - );
//异步请求发送要删除的字符串
$.ajax({
url: "/Employee/Delete",
type: "post",
data: { "idlist": idlist },
dataType: "text",
success: function (res) {
if (res == "ok") {
$("#dg").datagrid("reload");
}
}
})
}
});
}
}],
onClickCell: function (rowIndex, field, value) {
fieldName = field;
},
onSelect: function (rowIndex, rowData) {
if (fieldName == "Operator") {
$("#dg").datagrid("unselectRow", rowIndex);
}
},
onLoadSuccess: function () {
$(".editemp").click(function () {
var empid = $(this).parents("tr").children("td").eq().text();
popEditWindow("编辑员工", , "/Employee/AddEmp/"+empid);
})
}
}); //展示员工详细信息
function showEmp(node) {
$(function(){
var empid = $(node).parents("tr").children().eq().text();
popEditWindow("员工详细信息", , "/Employee/ShowEmp/" + empid);
})
} //员工调整弹窗
function AdjustEmp(node) {
$(function () {
var empid = $(node).parents("tr").children().eq().text();
popEditWindow("员工调整", , "/Employee/AdjustEmp/" + empid);
})
}
//分配权限
function SetAction(node) {
$(function () {
var empid = $(node).parents("tr").children().eq().text();
popEditWindow("分配权限", , "/Role/SetRole/" + empid);
})
}
</script> </body> </html>

【注】:

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

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

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

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

代码“小白”的温故而知新(一)-----OA管理系统的更多相关文章

  1. 一只代码小白git托管路上的二三事

    [经验]一只代码小白git托管路上的二三事 写在前面的话 寒假的时候,娄老师给我们布置了代码托管的作业,并要求把托管地址发给学委.因假期的时候没有带电脑回家,所以只是在手机上草草注册了,也稀里糊涂就将 ...

  2. 当.Net成为大厂门槛代码小白该何去何从?

    掌握.Net已成为进入大厂的通行牌.越来越多的互联网软件公司开始使用.Net Core,根据去年数据显示腾讯.网易.顺丰.携程.中通.申通.同程艺龙.微医.233网校.问卷星.金蝶等关键业务已经在往. ...

  3. 程序小白如何快速开发OA办公系统

    对于企业开发oa办公系统,成本高,周期长.有些企业花高价购买,购买后受制于软件商,很多功能只能按原来设计需求走,无法升级或者升级慢.这些由于软件商的开发效率低难以及时地响应企业的需求变化,所以就有可能 ...

  4. 用servlet设计OA管理系统时遇到问题

    如果不加单引号会使得除变量和int类型的值不能传递 转发和重定向的区别 转发需要填写完整路径,重定向只需要写相对路径.原因是重定向是一次请求之内已经定位到了服务器端,转发则需要两次请求每次都需要完整的 ...

  5. Java学生管理系统(详解)

    相信大部分人都有接触过这个 Java 小项目--学生管理系统,下面会分享我在做这个项目时的一些方法以及程序代码供大家参考(最后附上完整的项目代码). 首本人只是个初学Java的小白,可能项目中有许多地 ...

  6. c#实现每隔规定时间自动执行程序代码

    c#实现每隔规定时间自动执行程序代码  在一般的项目中我们很少用到c#实现每隔规定时间自动执行程序代码,但是如果你经历的项目多,或者应用程序做的比较多的话,c#实现每隔规定时间自动执行程序代码就用的比 ...

  7. bootstrap瀑布流代码

    <extend name="Base/common" /> <block name="search-cate"> <include ...

  8. PHP基础示例:用PHP+Mysql编写简易新闻管理系统

    实现目标:使用php和mysql操作函数实现一个新闻信息的发布.浏览.修改和删除操作 实现步骤: 一.创建数据库和表 1.创建数据库和表:newsdb 2.创建表格:news 字段:新闻id,标题,关 ...

  9. 8人/天,小记一次 JAVA(APP后台) 项目改造 .NET 过程(后台代码已完整开源于 Github)

    Github: https://github.com/iccb1013/Jade.Net 我们只消耗了8人/天的时间,完成了全部工作,基于我们 Jade.Net 的开源后台代码,任何小规模的后台管理系 ...

随机推荐

  1. VirtualBox 5.0(虚拟机软件)里,安装Fedora遇到的问题!!

    问题一: 安装完毕后,重新启动竟然还是进入了Fedora安装过程里. 问题原因:Fedora,并没有处理安装时候加载的ISO文件,依旧让VirtualBox 5.0运行它. 解决方法:在运行Fedor ...

  2. multiset的应用

    multiset 和set差不多 ,但是可以存储多个一样的元素

  3. C语言数据结构-顺序线性表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作

    1.数据结构-顺序线性表的实现-C语言 #define MAXSIZE 100 //结构体定义 typedef struct { int *elem; //基地址 int length; //结构体当 ...

  4. luogu2723 丑数

    提供一种单调队列做法(非正解) 显然每一个丑数能够由一个质数乘以另一个丑数得到 所以我们开k个单调递增队列,每次从这些队列顶部找到一个最小的元素把他捞出来,然后枚举所有质数,用这个元素乘以质数,放入相 ...

  5. 2018第九届蓝桥杯决赛(C++ B组)

    逛了大半个北京还是挺好玩de 第一题 标题:换零钞 x星球的钞票的面额只有:100元,5元,2元,1元,共4种. 小明去x星旅游,他手里只有2张100元的x星币,太不方便,恰好路过x星银行就去换零钱. ...

  6. 分布式通信框架RMI

    1.RPC概念: Remote procedure call protocal,远程过程调用协议,一般用来实现部署在不同机器上的系统之间的方法调用, 使得程序能够像访问本地系统资源一样,通过网络传输去 ...

  7. Qt 学习之路 2(12):菜单栏、工具栏和状态栏

    Home / Qt 学习之路 2 / Qt 学习之路 2(12):菜单栏.工具栏和状态栏 Qt 学习之路 2(12):菜单栏.工具栏和状态栏  豆子  2012年9月10日  Qt 学习之路 2  2 ...

  8. C语言使用指针表示数组的注意事项

    1)数组名是指针常量 如对指针变量可以进行++运算,但是对数组名却不允许,另外,对数组名的赋值运算也是错误的 2)注意指针变量的当前值 指针变量的值在程序运行过程中可能经常改变,要对此注意 3)数组越 ...

  9. php返回数据格式

    PHP返回HTML代码:     header('Content-type:text/html; charset=utf-8'); PHP返回xml代码:header('content-type: t ...

  10. 搭建一个wordpress网站需要做哪些工作

    今天做了自己的个人网站:二飞日志 之前因为服务器的问题,因为备案的原因辛辛苦苦做的站点数据没了.还好的是没有多少数据.没关系,重新来.有了上一次的经验,这次搭建起来比较顺手.但是也出现了几个问题.下面 ...