Ancient Cloud: Reviewing the Past and Knowing the New. This is excellent. Recently, as a little white man, I have used my spare time to revisit an OA system I wrote as a trainer in the past few months. I hope I can get some new inspiration on the basis of consolidation. Now, in retrospect, the previous person, writing stop, do not feel exclamation, the importance of the team in peacetime work and the insignificance of personal strength. Because it's a hands-on project, the whole system is designed by itself from the database to the front end, so it seems a bit shabby, not like spraying, but there are still some key points, as for artists, haha, conciseness is also a kind of beauty, can we only comfort ourselves in this way.
Preparations:
1. Conduct preliminary needs analysis (there are four sections: my desktop, human resources management, attendance management, workflow management)
2. Divide under each large plate into small pieces.
(My desktop -) Daily attendance, application submission, my approval [senior staff], my application;
Human resources - --"employee management, Department management, position management, role management;
Attendance Management - --- Workday Settings, Working Hours Settings, Attendance Records Query;
Workflow Management--Process Management
3. Technical realization: ASP.NET MVC, EF, Jquery, T4, log4Net, MD5, Jquery-easy-uI, Sqlser2008, Membercache, later spring.net
Let's first look at an earlier page presentation.
Home page:
Employee Information Page:
Add staff:
Editorial staff:
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Text:
Well, not much gossip. Let's design the database first. Before designing the database, we need to pay attention to a few points.
1. Naming tables must be standardized.
2. The design principle of a table is that only one thing is recorded in a table. If the table is related to the table, it is related by a foreign key.
In this regard, the design of menu table ActionInfo should be paid attention to when building tables, because it has different levels, one level menu and two level menu.
ActionId Identifies Column Primary Key - (rendered to the front end is id)
Title
Leval 1 2 int Determines the hierarchical icons to be displayed in the future (1 for menus, 2 for menu items)
URLs: Allow empty, level 1 is not, Level 2 has [access through this url]
PrentId int not null for the first-level menu, the value is 0 [important]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The next step is to build a framework, using a simple abstract factory three-tier project structure.
After the frame is built, make the main page first, the html code of Index under the control of Home/Index Home
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>Tongda OA</title> 14 <script src="~/Scripts/jquery-1.7.1.js"></script> 15 <script src="~/Scripts/MyAjaxForm.js"></script> 16 <script src="~/Scripts/jquery.easyui.min.js"></script> 17 <script src="~/Scripts/easyui-lang-zh_CN.js"></script> 18 <link href="~/Content/easyui.css" rel="stylesheet" /> 19 <link href="~/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">Welcome to login:@emp.EmpName <a href="/User/Login?state=false">[logoff]</a></p> 40 </div> 41 42 <div data-options="region:'west',title:'Navigation menu',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:'Home page'" 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 @* Pop-up independent window *@ 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 //Refresh 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 //Popup 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>
My overall page layout uses Easy-UI, the home page content uses panel components, and the menu bar uses tree components.
It should be noted that:
1.panel components can load pages remotely by setting href attributes, but only by loading the body content of the page. But when we need to make some additional changes in the style of css, such as adding employees and editing employees, panel components become invalid. So in the panel, I added an Iframe framework, which has an src attribute, which can be requested. A remote interface (complete, independent pages) where you can make your own CSS style changes.
2. How does the iframe framework adapt to height?
Solution:
$("#editframe").load(function () {
var mainheight = $(this).contents().find("body").height() + 30;
$(this).height(mainheight);
});
3. How to access the resources of his home page in the web pages embedded in the iframe framework?
Solution:
Define the resource method to be used on the main page, and then call window.parent. method name () on the sub-page containing iframe.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Action/Index | | Menu Bar Code
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> /// One-time loading menu data /// </summary> /// /// <returns> /// accord with tree Tree control json Objects in Format /// </returns> public ActionResult LoadData() { //There is no permission allocation, all menu lists are loaded after default login. List<ActionInfo> actionList = new ActionService().GetActionList(a => true); //Call stored procedures for filtering // List<ActionInfo> actionList = new ActionService().GetActionListByEmp(this.user.EmpId); //Use EF Query filtering //List<ActionInfo> actionList = new ActionService().GetActionByEmpId(this.user.EmpId); //Structural coincidence tree Tree control json Objects in Format List<MenuItem> menulist = new List<MenuItem>(); foreach (var item in actionList.Where(a=>a.Leval==1)) { //Level 1 menu 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 serialize JavaScriptSerializer jss = new JavaScriptSerializer(); string result = jss.Serialize(menulist); return Content(result); } } //Structural coincidence tree Entity classes of components 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 | | Code under Controller
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); //Solution 2: Use Newtonsoft Assembly 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"); } //Show employee details 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 ? "female" : "male"; ViewData["gender"] = gender; ViewData["adp"] = adplist; ViewData["add"]=addlist; return View(emp); } //Modification of Employees [HttpPost] public ActionResult Update(EmployeeInfo emp) { bool falg = new EmployeeService().UpdateEmp(emp); return falg ? Content("ok") : Content("fail"); } /// <summary> /// Delete employees /// </summary> /// <param name="idlist"></param> /// <returns></returns> public ActionResult Delete(string idlist) { bool falg = new EmployeeService().DeleteEmpList(idlist); return falg ? Content("ok") : Content("fail"); } //Staff adjustment [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(); //How to bind the queried data to the drop-down list box in the view,The fourth parameter is the selected value 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) { //Receive the number of the original department int OldDepartmentId = Convert.ToInt32(Request["OldDepartmentId"]); //Receive the number of the original position 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; //Job adjustment and no departmental adjustment if (add.NewDepartmentId == add.OldDepartmentId&&adp.NewPositionId != adp.OldPositionId) { falg = am.Add(adp); } //Departmental adjustment and no job adjustment else if (add.NewDepartmentId != add.OldDepartmentId && adp.NewPositionId == adp.OldPositionId) { falg = am.Add(add); } //Departments and positions have been adjusted. 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"); } } }
Give Employee List's view code, similar reference to the latter Department
1 @{ 2 Layout = null; 3 } 4 <!DOCTYPE html> 5 <html> 6 <head> 7 <meta name="viewport" content="width=device-width" /> 8 <title>Employee Interface</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: 'Employee Number', width: 50 }, 23 { field: 'EmpName', title: 'Name of Employee', width: 100 }, 24 { 25 field: 'EmpGender', title: 'Employee Gender', width: 100, formatter: function (value, row, index) { 26 return value ? "female" : "male"; 27 } 28 }, 29 { field: 'EmpBirthday', title: 'Birthdays of Employees', width: 100 }, 30 { field: 'EmpTelephone', title: 'Employee Telephone', width: 100 }, 31 { field: 'EmpEmail', title: 'mailing address', width: 200 }, 32 { 33 field: 'Operator', title: 'Employee Operation', width: 300, 34 formatter: function () { 35 return "<a href='#' class='editemp'>Editorial staff</a> | <a href='#' class='detail' onclick='showEmp(this);'>detailed information</a> |<a href='#' class='adjustemp' onclick='AdjustEmp(this)'>Staff adjustment</a> |<a href='#' class='setAction' onclick='SetAction(this)'>Allocation of permissions</a> "; 36 } 37 } 38 39 ]], 40 toolbar: [{ 41 iconCls: 'icon-add', 42 text: 'Adding Employees', 43 handler: function () { 44 //Call on the main page Index Bullet Window Function in Medium Package 45 popEditWindow("Adding Employees", 400, "/Employee/AddEmp"); 46 } 47 }, '-', { 48 iconCls: 'icon-cancel', 49 text: 'Delete employees', 50 handler: function () { 51 var rows = $("#dg").datagrid('getSelections'); 52 if (rows.length == 0) { 53 $.messager.alert("Tips", "Please select Delete line!"); 54 return; 55 } 56 $.messager.confirm('confirm', 'Are you sure you want to delete it?', function (r) { 57 if (r) { 58 //Get Number id,And make strings with certain rules 59 var idlist = ""; 60 for (var i = 0; i < rows.length; i++) { 61 idlist = idlist + rows[i]["EmpId"] + ","; 62 } 63 //Intercept 64 idlist = idlist.substr(0, idlist.length - 1); 65 //Asynchronous request to send a string to be deleted 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 onLoadSuccess: function () { 90 $(".editemp").click(function () { 91 var empid = $(this).parents("tr").children("td").eq(1).text(); 92 popEditWindow("Editorial staff", 400, "/Employee/AddEmp/"+empid); 93 }) 94 } 95 }); 96 97 //Show employee details 98 function showEmp(node) { 99 $(function(){ 100 var empid = $(node).parents("tr").children().eq(1).text(); 101 popEditWindow("Employee Details", 500, "/Employee/ShowEmp/" + empid); 102 }) 103 } 104 105 //Employee Adjustment Bullet Window 106 function AdjustEmp(node) { 107 $(function () { 108 var empid = $(node).parents("tr").children().eq(1).text(); 109 popEditWindow("Staff adjustment", 400, "/Employee/AdjustEmp/" + empid); 110 }) 111 } 112 //Allocation of permissions 113 function SetAction(node) { 114 $(function () { 115 var empid = $(node).parents("tr").children().eq(1).text(); 116 popEditWindow("Allocation of permissions", 400, "/Role/SetRole/" + empid); 117 }) 118 } 119 </script> 120 121 </body> 122 123 </html>
[Note]
Common Error: Serialized Loop Reference Detected
Solution 1: Create a VO model object without navigation attributes.
Solution 2: Recommend Newton JSON assemblies
Okay, that's all for today's review. Looking forward to the next section of "learning from the past and learning from the new" (2).