根据讲师下发的实践项目需求,做了一个人员管理系统,其中用到知识颇多,思来想去决定发布上来,一是为自己以后的开发做一个参考,避免忘记。二是希望能得到互联网上各位大佬的评鉴。

xx人员管理系统

xx人员管理系统是为员工提供从入职到离职全面管理的系统软件。

主要功能:追踪员工工作时数并按项目、客户或任务进行排序,支持添加员工,查询员工,显示所有员工,修改员工信息以及删除员工;提供智能化人力统计报表与分析,轻松访问统计数据,记录并分析工时表并检查每位员工的出勤情况,提供实时的数据;根据收录的信息自动生成员工简历,全面覆盖员工个人信息、合同信息、薪酬福利信息、考勤班表信息、绩效考核信息、培训经历等各类信息,为领导决策提供客观及时的数据支持。

开发目的:通过信息化减轻HR日常事务工作,提升企业整体人事运作效率。

面向领域 / 行业:人员管理

页面:
主要包含7个功能页面和一个主页面以及一个登录界面

#mermaid-svg-GwabsuzIth98Vjtp .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-GwabsuzIth98Vjtp .label text{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .node rect,#mermaid-svg-GwabsuzIth98Vjtp .node circle,#mermaid-svg-GwabsuzIth98Vjtp .node ellipse,#mermaid-svg-GwabsuzIth98Vjtp .node polygon,#mermaid-svg-GwabsuzIth98Vjtp .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-GwabsuzIth98Vjtp .node .label{text-align:center;fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .node.clickable{cursor:pointer}#mermaid-svg-GwabsuzIth98Vjtp .arrowheadPath{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-GwabsuzIth98Vjtp .flowchart-link{stroke:#333;fill:none}#mermaid-svg-GwabsuzIth98Vjtp .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-GwabsuzIth98Vjtp .edgeLabel rect{opacity:0.9}#mermaid-svg-GwabsuzIth98Vjtp .edgeLabel span{color:#333}#mermaid-svg-GwabsuzIth98Vjtp .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-GwabsuzIth98Vjtp .cluster text{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-GwabsuzIth98Vjtp .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-GwabsuzIth98Vjtp text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-GwabsuzIth98Vjtp .actor-line{stroke:grey}#mermaid-svg-GwabsuzIth98Vjtp .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-GwabsuzIth98Vjtp .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-GwabsuzIth98Vjtp #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-GwabsuzIth98Vjtp .sequenceNumber{fill:#fff}#mermaid-svg-GwabsuzIth98Vjtp #sequencenumber{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp #crosshead path{fill:#333;stroke:#333}#mermaid-svg-GwabsuzIth98Vjtp .messageText{fill:#333;stroke:#333}#mermaid-svg-GwabsuzIth98Vjtp .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-GwabsuzIth98Vjtp .labelText,#mermaid-svg-GwabsuzIth98Vjtp .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-GwabsuzIth98Vjtp .loopText,#mermaid-svg-GwabsuzIth98Vjtp .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-GwabsuzIth98Vjtp .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-GwabsuzIth98Vjtp .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-GwabsuzIth98Vjtp .noteText,#mermaid-svg-GwabsuzIth98Vjtp .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-GwabsuzIth98Vjtp .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-GwabsuzIth98Vjtp .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-GwabsuzIth98Vjtp .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-GwabsuzIth98Vjtp .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .section{stroke:none;opacity:0.2}#mermaid-svg-GwabsuzIth98Vjtp .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-GwabsuzIth98Vjtp .section2{fill:#fff400}#mermaid-svg-GwabsuzIth98Vjtp .section1,#mermaid-svg-GwabsuzIth98Vjtp .section3{fill:#fff;opacity:0.2}#mermaid-svg-GwabsuzIth98Vjtp .sectionTitle0{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .sectionTitle1{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .sectionTitle2{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .sectionTitle3{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-GwabsuzIth98Vjtp .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .grid path{stroke-width:0}#mermaid-svg-GwabsuzIth98Vjtp .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-GwabsuzIth98Vjtp .task{stroke-width:2}#mermaid-svg-GwabsuzIth98Vjtp .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .taskText:not([font-size]){font-size:11px}#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-GwabsuzIth98Vjtp .task.clickable{cursor:pointer}#mermaid-svg-GwabsuzIth98Vjtp .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-GwabsuzIth98Vjtp .taskText0,#mermaid-svg-GwabsuzIth98Vjtp .taskText1,#mermaid-svg-GwabsuzIth98Vjtp .taskText2,#mermaid-svg-GwabsuzIth98Vjtp .taskText3{fill:#fff}#mermaid-svg-GwabsuzIth98Vjtp .task0,#mermaid-svg-GwabsuzIth98Vjtp .task1,#mermaid-svg-GwabsuzIth98Vjtp .task2,#mermaid-svg-GwabsuzIth98Vjtp .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutside0,#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutside2{fill:#000}#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutside1,#mermaid-svg-GwabsuzIth98Vjtp .taskTextOutside3{fill:#000}#mermaid-svg-GwabsuzIth98Vjtp .active0,#mermaid-svg-GwabsuzIth98Vjtp .active1,#mermaid-svg-GwabsuzIth98Vjtp .active2,#mermaid-svg-GwabsuzIth98Vjtp .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-GwabsuzIth98Vjtp .activeText0,#mermaid-svg-GwabsuzIth98Vjtp .activeText1,#mermaid-svg-GwabsuzIth98Vjtp .activeText2,#mermaid-svg-GwabsuzIth98Vjtp .activeText3{fill:#000 !important}#mermaid-svg-GwabsuzIth98Vjtp .done0,#mermaid-svg-GwabsuzIth98Vjtp .done1,#mermaid-svg-GwabsuzIth98Vjtp .done2,#mermaid-svg-GwabsuzIth98Vjtp .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-GwabsuzIth98Vjtp .doneText0,#mermaid-svg-GwabsuzIth98Vjtp .doneText1,#mermaid-svg-GwabsuzIth98Vjtp .doneText2,#mermaid-svg-GwabsuzIth98Vjtp .doneText3{fill:#000 !important}#mermaid-svg-GwabsuzIth98Vjtp .crit0,#mermaid-svg-GwabsuzIth98Vjtp .crit1,#mermaid-svg-GwabsuzIth98Vjtp .crit2,#mermaid-svg-GwabsuzIth98Vjtp .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-GwabsuzIth98Vjtp .activeCrit0,#mermaid-svg-GwabsuzIth98Vjtp .activeCrit1,#mermaid-svg-GwabsuzIth98Vjtp .activeCrit2,#mermaid-svg-GwabsuzIth98Vjtp .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-GwabsuzIth98Vjtp .doneCrit0,#mermaid-svg-GwabsuzIth98Vjtp .doneCrit1,#mermaid-svg-GwabsuzIth98Vjtp .doneCrit2,#mermaid-svg-GwabsuzIth98Vjtp .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-GwabsuzIth98Vjtp .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-GwabsuzIth98Vjtp .milestoneText{font-style:italic}#mermaid-svg-GwabsuzIth98Vjtp .doneCritText0,#mermaid-svg-GwabsuzIth98Vjtp .doneCritText1,#mermaid-svg-GwabsuzIth98Vjtp .doneCritText2,#mermaid-svg-GwabsuzIth98Vjtp .doneCritText3{fill:#000 !important}#mermaid-svg-GwabsuzIth98Vjtp .activeCritText0,#mermaid-svg-GwabsuzIth98Vjtp .activeCritText1,#mermaid-svg-GwabsuzIth98Vjtp .activeCritText2,#mermaid-svg-GwabsuzIth98Vjtp .activeCritText3{fill:#000 !important}#mermaid-svg-GwabsuzIth98Vjtp .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-GwabsuzIth98Vjtp g.classGroup text .title{font-weight:bolder}#mermaid-svg-GwabsuzIth98Vjtp g.clickable{cursor:pointer}#mermaid-svg-GwabsuzIth98Vjtp g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-GwabsuzIth98Vjtp g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-GwabsuzIth98Vjtp .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-GwabsuzIth98Vjtp .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-GwabsuzIth98Vjtp .dashed-line{stroke-dasharray:3}#mermaid-svg-GwabsuzIth98Vjtp #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp .commit-id,#mermaid-svg-GwabsuzIth98Vjtp .commit-msg,#mermaid-svg-GwabsuzIth98Vjtp .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-GwabsuzIth98Vjtp g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-GwabsuzIth98Vjtp g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-GwabsuzIth98Vjtp g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-GwabsuzIth98Vjtp .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-GwabsuzIth98Vjtp .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-GwabsuzIth98Vjtp .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-GwabsuzIth98Vjtp .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-GwabsuzIth98Vjtp .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-GwabsuzIth98Vjtp .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-GwabsuzIth98Vjtp .edgeLabel text{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-GwabsuzIth98Vjtp .node circle.state-start{fill:black;stroke:black}#mermaid-svg-GwabsuzIth98Vjtp .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-GwabsuzIth98Vjtp #statediagram-barbEnd{fill:#9370db}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-state .divider{stroke:#9370db}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-GwabsuzIth98Vjtp .note-edge{stroke-dasharray:5}#mermaid-svg-GwabsuzIth98Vjtp .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-GwabsuzIth98Vjtp .error-icon{fill:#522}#mermaid-svg-GwabsuzIth98Vjtp .error-text{fill:#522;stroke:#522}#mermaid-svg-GwabsuzIth98Vjtp .edge-thickness-normal{stroke-width:2px}#mermaid-svg-GwabsuzIth98Vjtp .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-GwabsuzIth98Vjtp .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-GwabsuzIth98Vjtp .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-GwabsuzIth98Vjtp .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-GwabsuzIth98Vjtp .marker{fill:#333}#mermaid-svg-GwabsuzIth98Vjtp .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}#mermaid-svg-GwabsuzIth98Vjtp {color: rgba(0, 0, 0, 0.75);font: ;}

登录
普通界面
人事部门页面
考勤管理
人员管理
信息添加
考勤查询
人员福利
普通界面
人员查询

普通员工登录与签到签出
人事部门员工的员工管理

数据库设计

*****员工表Staffs
员工编号StaffId(主) 员工编码Number 姓名Name 性别Sex 年龄Age 政治面貌Political 身高Height 体重Weight 毕业院校School 毕业专业Specialty 毕业日期GraDate 通信地址Address 联系电话Phone 招聘来源Source 相片Photo 职位编码PostNum(外) 其他Other 是否启用Enable 是否同步考勤Sync 考勤机编号MachineId(外) 录入日期EntDate 是否转正Positive
*****员工账号表StaffAccounts
账号编号AccountId(主) 员工编号StaffId(外) 账号Account 密码Password
*****考勤表Attendances
考勤编号AttendanceId(主) 员工编号StaffId(外) 签到时间SignTime 是否正常上班Work 签出时间OutTime 是否正常下班OffWork 工作时间WorkTime 签到状态SignStatus
*****职位表Posts
职位编号PostId 职位编码PostNum(主) 部门Department 职位Post
*****考勤机表AttMachines
考勤机编号MachineId(主) 考勤机名称MachineName 考勤机人员编码MStaffID 考勤人员名称MStaffName
*****公示表Formulas
公式编号FormulaId(主) 职位编码PostNum(外) 工资项名称SalaryItem 公式Formula

我设计了六个表
员工表包含所有员工基本信息及所对应的职位编码,是否是启用状态,是否同步在考勤机上,以及考勤机编号和是否已经转正
员工账号表和员工表一对一关系,保存着每个员工的账号密码
考勤表包含每个员工每天的工作状态签到签出及是否正常上班
职位表保存着公司现有的部门职位信息,根据员工职位编码进行配对职位
考勤机表包含所有考勤机和考勤机所有人员
公示表包含公司福利信息,以供计算薪资
关系

账号表,职位表,考勤表和考勤机表通过对应主从关系围绕着员工表,公式表仅用于计算薪资

每个表插入多个信息以供测验

页面及代码设计

首先创建DBHelper类以用于连接数据库

using System.Data.SqlClient;
using System.Data;
        //定义连接字符串public static string connstr = "server=.;database=PersonnelDB;uid=sa;pwd=123456";//声明数据库连接对象public static SqlConnection conn = null;public static void Initialization()//初始化连接{if (conn == null)//判断是否为空{//赋值连接对象conn = new SqlConnection(connstr);}if (conn.State == ConnectionState.Closed)//判断是否关闭{//打开连接conn.Open();}if (conn.State == ConnectionState.Broken)//判断是否中断{//重启连接conn.Close();conn.Open();}}/// <summary>/// 查询获取datareader/// </summary>/// <param name="sql"></param>/// <returns></returns>public static SqlDataReader GetDataReader(string sql){try{Initialization();//声明操作对象SqlCommand com = new SqlCommand(sql, conn);//返回并定义连接关闭return com.ExecuteReader(CommandBehavior.CloseConnection);}catch (Exception){throw;}}/// <summary>/// 断开查询/// </summary>/// <param name="sql"></param>/// <returns></returns>public static DataTable GetDataTable(string sql){try{Initialization();//声明datatableDataTable dt = new DataTable();//声明断开式连接对象SqlDataAdapter da = new SqlDataAdapter(sql, conn);//赋值给datatableda.Fill(dt);//关闭连接conn.Close();//返回return dt;}catch (Exception){throw;}}/// <summary>/// 增删改/// </summary>/// <param name="sql"></param>/// <returns></returns>public static bool GetExecuteNonQuery(string sql){try{Initialization();//声明连接对象SqlCommand com = new SqlCommand(sql, conn);//接收返回值int temp = com.ExecuteNonQuery();//关闭连接conn.Close();//返回判断return temp > 0;}catch (Exception){throw;}}/// <summary>/// 聚合函数/// </summary>/// <param name="sql"></param>/// <returns></returns>public static Object GetExecuteScalar(string sql){try{Initialization();//声明连接对象SqlCommand com = new SqlCommand(sql, conn);//接收返回值Object temp = com.ExecuteScalar();//关闭连接conn.Close();//返回return temp;}catch (Exception){throw;}}

然后为了方便整理sql语句,我就单独创建了一个dal类,用于存放SQL语句

首先是登录界面

我使用的是无边框窗口,设定了窗口初始显示位置
页面阴影和可拖动参考我的另一篇文章c#页面初步美化

这个界面主要就是非空验证和判断账号密码是否正确
非空验证就不多说了
判断账号密码是否正确就需要查询数据库
因此首先添加sql语句

        /// <summary>/// 根据账号密码查询用户信息/// </summary>/// <param name="acc"></param>/// <param name="pass"></param>/// <returns></returns>public static DataTable SelectByAcc(string acc,string pass){string sql = $"SELECT * from Staffs s,StaffAccounts a,Posts p WHERE s.StaffId = a.StaffId and s.PostNum = p.PostNum and a.Account = '{acc}' and a.Password = '{pass}'";return DBHelper.GetDataTable(sql);}

并且建立user用户类,用以保存登录上的用户信息
代码如下

         DataTable user = DAL.SelectByAcc(textBox1.Text, textBox2.Text);if (user.Rows.Count>0){MessageBox.Show("登陆成功!","登录成功!",MessageBoxButtons.OK);User.id = Convert.ToInt32(user.Rows[0]["StaffId"]);User.name = user.Rows[0]["Name"].ToString();User.photo = user.Rows[0]["Photo"].ToString();User.post = user.Rows[0]["Post"].ToString();if (user.Rows[0]["Department"].ToString().Equals("人事部")){//人事部门Home home = new Home(this);home.Show();this.Hide();}else{//其他部门Staff staff = new Staff(this);staff.Show();this.Hide();}}else{MessageBox.Show("账号或密码错误!", "登录失败!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);}

再有一个就是密码输入栏的小眼睛

            //判断是否是默认字符显示if (textBox2.UseSystemPasswordChar){textBox2.UseSystemPasswordChar = false;}else{textBox2.UseSystemPasswordChar = true;}

登录界面没什么东西
然后下一个主页面

首先就是七个功能页面的跳转

            Attendance attendance = new Attendance(this);attendance.Show();this.Hide();

退出系统按钮

            if (DialogResult.OK == MessageBox.Show("您确定要退出吗?", "提示", MessageBoxButtons.OKCancel)){Application.Exit();}

退回登录界面

            login.Visible = true;this.Close();

修改密码按钮

            UpPass upPass = new UpPass();upPass.Show();

及页面初始化代码

            //首先显示登录人信息label3.Text = User.post;label4.Text = User.name;string file = "../../images/" + User.photo;pictureBox1.Image = Image.FromFile(file);//图片圆角DAL.PicRounded(pictureBox1);

图片圆角参考我另一个文章c#初步美化-圆角
图片框主要是通过获取当前运行文档的运行地址+用户类的存储的图片名在转换为image进行显示

其中涉及到密码修改界面

包含多个验证和根据id查询用户信息以及修改密码
页面初始化

添加SQL语句

        /// <summary>/// 根据id获取账号密码/// </summary>/// <param name="id"></param>/// <returns></returns>public static DataTable SelectByPass(int id){string sql = "SELECT * FROM StaffAccounts WHERE StaffId = " + id;return DBHelper.GetDataTable(sql);}
        string account = null;string password = null;private void UpPass_Load(object sender, EventArgs e){DataTable dt = DAL.SelectByPass(User.id);account = dt.Rows[0]["Account"].ToString();password = dt.Rows[0]["Password"].ToString();label2.Text = account;}

主要就是显示信息
然后就是修改密码
添加SQL语句

        /// <summary>/// 修改密码/// </summary>/// <param name="id"></param>/// <param name="pass"></param>/// <returns></returns>public static bool UpdateByPass(int id,string pass){string sql = $"UPDATE StaffAccounts SET Password = {pass} WHERE StaffId = {id}";return DBHelper.GetExecuteNonQuery(sql);}
            if (DAL.UpdateByPass(User.id, pass2)){MessageBox.Show("修改成功!", "提示", MessageBoxButtons.OK);this.Close();}else{MessageBox.Show("修改失败!", "提示", MessageBoxButtons.OK);}

接下来就是主菜了
考勤管理界面

此界面用于管理人员的考勤匹配
首先就是菜单栏和工具栏的设置
菜单栏单纯的写文字
工具栏要添加按钮模式,同时设置为图片按钮并存,用以显示图标
在一个就是datagridview的设置,一共五项
整行选中模式,不可多选单元格,可见列自动调整大小模式为fill,不允许用户添加行以及不自动添加列(代码设置,dataGridView1.AutoGenerateColumns = false)
列名设置就不多说
由于每行首列要以复选框形式显示,所以要设置列类型为DataGridViewCheckBoxColumn
但是标题栏全选复选框笔者没有实现出来,所以就在固定位置放了一个复选框,用于全选

然后就是窗口构造方法,用于通过构造方法显示上一个界面,关闭此页面,通俗来说就是返回上一页
这里使用构造方法重载,方便测试

        Form home = null;public Attendance(Form f){InitializeComponent();home = f;}

接下来就是页面初始化显示
新建刷新两个视图的方法

建立全局表,用于保存数据,方便调用

        //人员表DataTable sa = new DataTable();//考勤机表DataTable am = new DataTable();

SQL语句

        /// <summary>/// 根据姓名查询所有同步到考勤机的人员/// </summary>/// <returns></returns>public static DataTable SelectByAttMac(string name){string sql = $"SELECT * FROM Staffs s,Posts p,AttMachines m WHERE s.PostNum = p.PostNum AND s.MachineId = m.MachineId AND s.Sync = 1 AND Name LIKE '%{name}%'";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 根据姓名查询全部用户信息及账号信息/// </summary>/// <param name="id"></param>/// <returns></returns>public static DataTable SelectBySA(string name){string sql = $"SELECT * FROM StaffAccounts sa,Staffs s,Posts p WHERE s.StaffId = sa.StaffId AND s.PostNum = p.PostNum AND Name LIKE '%{name}%'";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 初始化加载/// </summary>/// <param name="name"></param>public void DGVInit(string name){am = DAL.SelectByAttMac(name);//table2 = am.Rows.Count;dataGridView2.DataSource = am;}
        //刷新人员表public void InitStaff(string dt){sa = DAL.SelectBySA(dt);DataSourceBind(sa);}

以及格式化显示数据

        /// <summary>/// 判断数据/// </summary>/// <param name="dt"></param>public void DataSourceBind(DataTable dt){dataGridView1.DataSource = dt;for (int i = 0; i < dt.Rows.Count; i++){if (int.Parse(dt.Rows[i]["Sync"].ToString())==0){dataGridView1.Rows[i].Cells[5].Value = "未同步";dataGridView1.Rows[i].Cells[5].Style.BackColor = Color.Tomato;}else{dataGridView1.Rows[i].Cells[5].Value = "已同步";dataGridView1.Rows[i].Cells[5].Style.BackColor = Color.Chartreuse;}if (int.Parse(dt.Rows[i]["Enable"].ToString())==0){dataGridView1.Rows[i].Cells[6].Value = "未启用";dataGridView1.Rows[i].Cells[6].Style.BackColor = Color.Tomato;}else{dataGridView1.Rows[i].Cells[6].Value = "已启用";dataGridView1.Rows[i].Cells[6].Style.BackColor = Color.Chartreuse;}}}

初始化显示数据调用

            dataGridView1.AutoGenerateColumns = false;dataGridView2.AutoGenerateColumns = false;InitStaff("");DGVInit("");

首列的全选及取消全选
大概思路就是点击全选按钮遍历所有复选框并选中,再次点击全部取消。点击某一个复选框遍历全部复选框,根据选中状态查看是否有选中的及未选中的,实现全选按钮的是否选中显示
但是这种仅适用于小数量的全选,数量较多的情况下就会运行缓慢,还有一个思路就是计数实现全选按钮的是否选中显示,点击某一个复选框计数加或计数减,判断是否等于总数,但是笔者实现时存在bug,为了更好显示就未采用,但理论上是可行的

        private void checkBox1_Click(object sender, EventArgs e){if (checkBox1.Checked){for (int i = 0; i < dataGridView1.Rows.Count; i++){dataGridView1.Rows[i].Cells[0].Value = true;}}else{for (int i = 0; i < dataGridView1.Rows.Count; i++){dataGridView1.Rows[i].Cells[0].Value = false;}}}

以及每个单独复选框选中

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e){//列索引if (e.ColumnIndex == 0){//行索引if (Convert.ToBoolean(dataGridView1.Rows[e.RowIndex].Cells[0].EditedFormattedValue)){for (int i = 0; i < dataGridView1.Rows.Count; i++){if (!Convert.ToBoolean(dataGridView1.Rows[i].Cells[0].EditedFormattedValue)){return;}}checkBox1.Checked = true;}else if(!Convert.ToBoolean(dataGridView1.Rows[e.RowIndex].Cells[0].EditedFormattedValue)){checkBox1.Checked = false;}}}

在接着说菜单栏和工具栏
菜单栏也具有二级菜单,不过其功能都是实现了和工具栏相同的功能
所以这里相同代码这里就不过多介绍,只来说说工具栏
第一个按钮高级因为需求不清楚所以未能实现
第二个人员数据初始化
其主要是将所有人员的考勤机初始化,就是清空考勤机,所有人回到初始状态
修改数据库,将所有人都改成未同步

        /// <summary>/// 全部人员置不同步or单独置不同步/// </summary>/// <returns></returns>public static bool UpdateByAttMac(){string sql = "UPDATE Staffs SET Sync = 0";return DBHelper.GetExecuteNonQuery(sql);}
            if (DAL.UpdateByAttMac()){MessageBox.Show("初始化成功!", "提示", MessageBoxButtons.OK);InitStaff("");DGVInit("");}else{MessageBox.Show("初始化失败!", "提示", MessageBoxButtons.OK);}

第三四个按钮均是刷新,也就是调用两个显示数据的方法就行了,这里就不过多介绍了
然后是自动映射
笔者给他的功能是将所有人员全都自动同步到默认考勤机
也是修改数据库

        /// <summary>/// 自动映射or手动映射/// </summary>/// <returns></returns>public static bool UpdateBySyncMac(){string sql = "UPDATE Staffs SET Sync = 1,MachineId = 1";return DBHelper.GetExecuteNonQuery(sql);}
            if (DAL.UpdateBySyncMac()){MessageBox.Show("自动映射成功!", "提示", MessageBoxButtons.OK);InitStaff("");}else{MessageBox.Show("自动映射失败!", "提示", MessageBoxButtons.OK);}

然后就是手动映射和删除映射,笔者给它设定的功能是将人员表选中的数据同步到考勤机和考勤表选中的数据置不同步
手动映射

        public static bool UpdateBySyncMac(int id){string sql = "UPDATE Staffs SET Sync = 1,MachineId = 1 WHERE StaffId = "+id;return DBHelper.GetExecuteNonQuery(sql);}
            for (int i = 0; i < dataGridView1.Rows.Count; i++){if (Convert.ToBoolean(dataGridView1.Rows[i].Cells[0].EditedFormattedValue)){if (!DAL.UpdateBySyncMac(Convert.ToInt32(sa.Rows[i]["StaffId"]))){MessageBox.Show("映射出错!", "提示", MessageBoxButtons.OK);return;}}}MessageBox.Show("映射成功!", "提示", MessageBoxButtons.OK);DGVInit("");InitStaff("");

其原理就是循环遍历选中的复选框,然后根据全局表的id行列进行改变数据
这里之所以使用判断映射出错跳出,主要是为了避免更大的数据出错吧
删除映射

        public static bool UpdateByAttMac(int id){string sql = "UPDATE Staffs SET Sync = 0 WHERE StaffId = " + id;return DBHelper.GetExecuteNonQuery(sql);}
            for (int i = 0; i < dataGridView2.Rows.Count; i++){if (Convert.ToBoolean(dataGridView2.Rows[i].Cells[0].EditedFormattedValue)){if (!DAL.UpdateByAttMac(Convert.ToInt32(am.Rows[i]["StaffId"]))){MessageBox.Show("删除出错!", "提示", MessageBoxButtons.OK);return;}}}MessageBox.Show("删除成功!", "提示", MessageBoxButtons.OK);DGVInit("");InitStaff("");

原理同上,操作也差不多

接下来就是后边三个控件,一个是下拉框,用来选择将要搜索的表,设定为仅能选择不能输入,在一个是输入框,用来接收条件,最后一个就是搜索按钮
这里给搜索按钮添加事件执行搜索功能
搜索原理就是调用刚刚写的初始化显示数据的方法,相信有注意到那两个方法是需要参数的,它使用的sql语句也是模糊查询,模糊查询空值就是查询全部,到这里给到值,通过模糊查询显示数据
非空验证就不多说

            if (toolStripTextBox1.Text=="人员表"){InitStaff(toolStripTextBox2.Text);}else if (toolStripTextBox1.Text == "映射表"){DGVInit(toolStripTextBox2.Text);}else{MessageBox.Show("查询条件错误!", "提示", MessageBoxButtons.OK);}

考勤页面主要就是这些功能
人员部门页面

此页面用于管理人员的部门信息,包括人员统计及管理等
首先就是页面的初始化显示
构造方法同上个页面
datagirdview的初始设置就不多说了
这里设置三个全局表,分别用于表示最近七天录入,全部,和未转正

        DataTable t7 = new DataTable();DataTable tall = new DataTable();DataTable tposi = new DataTable();

初始化数据

            //获取数据t7 = DAL.SelectByTime7();tall = DAL.SelectByPost("");tposi = DAL.SelectByPositive();
        /// <summary>/// 最近七天职位数据/// </summary>/// <param name="dt"></param>/// <returns></returns>public static DataTable SelectByTime7(){DateTime dt = DateTime.Today.AddDays(-7);string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND EntDate > '{dt}'";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 根据姓名查询全部职位信息--1/// </summary>/// <returns></returns>public static DataTable SelectByPost(string name){string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Name LIKE '%{name}%'";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 查询未转正职位信息/// </summary>/// <returns></returns>public static DataTable SelectByPositive(){string sql = "SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Positive = 0";return DBHelper.GetDataTable(sql);}

设置上方六个部门的数据统计

            //统计人数count1.Text = DAL.StatsDep("财务部").ToString();count2.Text = DAL.StatsDep("管理部").ToString();count3.Text = DAL.StatsDep("客服部").ToString();count4.Text = DAL.StatsDep("人事部").ToString();count5.Text = DAL.StatsDep("设计部").ToString();count6.Text = DAL.StatsDep("销售部").ToString();
        /// <summary>/// 部门人数统计/// </summary>/// <param name="dep"></param>/// <returns></returns>public static int StatsDep(string dep){string sql = $"SELECT COUNT(*) FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Department = '{dep}'";return Convert.ToInt32(DBHelper.GetExecuteScalar(sql));}

然后就是datagirdview的数据显示,这里有个问题,因为涉及到人员头像的一个列,需要显示人员头像
因为数据库使用的是头像名字,所以这里不能直接绑定到数据,不能直接显示,所以就需要加载的时候在获取数据单独的加载头像
建立一个头像文件夹images
头像保存方法稍后再说
所以这里我单独新建了数据绑定方法

        /// <summary>/// 绑定数据/// </summary>/// <param name="dt"></param>public void DataSourceBind(DataTable dt){dataGridView1.DataSource = dt;for (int i = 0; i < dt.Rows.Count; i++){string file = "../../images/" + dt.Rows[i]["Photo"].ToString();Image img = Image.FromFile(file);Image imgb = new Bitmap(img);dataGridView1.Rows[i].Cells[0].Value = imgb;img.Dispose();}}

先绑定,然后遍历传过来的表获取地址挨个绑定,这里因为是图片流的方式,所以这里会造成内存溢出,这就涉及到图片加载的问题了,这就造成在低性能机子上会报错,笔者因为实力有限这个问题未能解决。
接下来是单击统计数值显示这个部门的信息

            DataSourceBind(DAL.SelectByDepPost("财务部"));txt1.ForeColor = Color.Black;txt2.ForeColor = Color.Red;txt3.ForeColor = Color.Black;
        /// <summary>/// 根据部门查询职位信息---2/// </summary>/// <param name="dep"></param>/// <returns></returns>public static DataTable SelectByDepPost(string dep){string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Department LIKE '%{dep}%'";return DBHelper.GetDataTable(sql);}

还有就是单击全部,最近和未转正标签切换对应显示数据的功能

            DataSourceBind(t7);txt1.ForeColor = Color.Red;txt2.ForeColor = Color.Black;txt3.ForeColor = Color.Black;

需要什么直接传表就行
然后就是工具栏搜索功能

            if (toolStripTextBox1.Text != ""){DataSourceBind(DAL.SelectByPost(toolStripTextBox1.Text));}else{DataSourceBind(tall);}txt1.ForeColor = Color.Black;txt2.ForeColor = Color.Red;txt3.ForeColor = Color.Black;

根据名字模糊搜索

        /// <summary>/// 根据姓名查询全部职位信息--1/// </summary>/// <returns></returns>public static DataTable SelectByPost(string name){string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Name LIKE '%{name}%'";return DBHelper.GetDataTable(sql);}

如果输入框为空就直接显示全部数据
单击新建档案就直接跳转到第三个功能界面

            AddStaff addStaff = new AddStaff(this,1);addStaff.Show();this.Hide();

人员添加界面

此页面主要用于添加人员信息
因为有多个界面需要跳转到这个界面,所以这里出了单纯传页面有多个构造方法的重载

        public AddStaff(Form f,int s){InitializeComponent();home = f;button2.Text = "退回上页";}

这个主要是设置返回主页的按钮显示

        int Id = -1;public AddStaff(Form f, int s,int id){InitializeComponent();home = f;button2.Text = "退回上页";Id = id;if (s==0){button7.Enabled = false;}else{button6.Enabled = false;button7.Enabled = false;}}

这个创建了一个全局int值,用于保存id值,接受这个id值用于显示数据,以及保存和重置按钮的是否可用
然后就是初始化显示
首先获取部门信息添加到下拉框

            DataTable dt = DAL.SelectByDepartment();for (int i = 0; i < dt.Rows.Count; i++){comboBox2.Items.Add(dt.Rows[i][0]);}
        /// <summary>/// 查询所有不重复部门/// </summary>/// <returns></returns>public static DataTable SelectByDepartment(){string sql = "SELECT DISTINCT Department FROM Posts";return DBHelper.GetDataTable(sql);}

然后因为这个界面有富文本编辑框,有个字体设置

            //添加系统字体foreach (FontFamily f in FontFamily.Families){toolStripComboBox1.Items.Add(f.Name);}

还有就是当id有值的时候,也就是不等于初始值的时候,就显示当前id所有的用户信息以供查看和修改

            //用户编辑if (Id != -1){//内容省略,主要就是给每个输入框赋值}

这里说下用户头像的保存方式
点击选择头像按钮

        //头像路径string imagefile = "";private void button5_Click(object sender, EventArgs e){if (DialogResult.OK == openFileDialog1.ShowDialog()){imagefile = openFileDialog1.FileName;pictureBox1.ImageLocation = openFileDialog1.FileName;}}

这里保存下来当先头像的物理路径,以供保存,同时显示图片预选
当点击了保存之后再进行保存操作
然后就是富文本框的设置
第一个字体
就是赋值一个新的字体

        //字体private void toolStripComboBox1_SelectedIndexChanged(object sender, EventArgs e){richTextBox1.Font = new Font(FontFamily.Families[toolStripComboBox1.SelectedIndex], richTextBox1.Font.Size, richTextBox1.Font.Style);}

加粗

        //富文本应用Font oldFont;Font newFont;//加粗private void toolStripButton2_Click(object sender, EventArgs e){oldFont = richTextBox1.SelectionFont;if (oldFont.Bold){newFont = new Font(oldFont, oldFont.Style & ~FontStyle.Bold);//交集}else{newFont = new Font(oldFont, oldFont.Style | FontStyle.Bold);//并集}richTextBox1.SelectionFont = newFont;}

这里要解释下,判断是否是加粗状态,如果是则取当前字体样式&除了加粗字体(即倾斜下划线)的并集,取消加粗,并保留原来的字体样式。如果否则取当前字体样式和加粗的并集,即加粗
倾斜

        //倾斜private void toolStripButton3_Click(object sender, EventArgs e){oldFont = richTextBox1.SelectionFont;if (oldFont.Italic){newFont = new Font(oldFont, oldFont.Style & ~FontStyle.Italic);//交集}else{newFont = new Font(oldFont, oldFont.Style | FontStyle.Italic);//并集}richTextBox1.SelectionFont = newFont;}

下划线

        //下划线private void toolStripButton4_Click(object sender, EventArgs e){oldFont = richTextBox1.SelectionFont;if (oldFont.Underline){newFont = new Font(oldFont, oldFont.Style & ~FontStyle.Underline);//交集}else{newFont = new Font(oldFont, oldFont.Style | FontStyle.Underline);//并集}richTextBox1.SelectionFont = newFont;}

倾斜和下划线原理相同
字号加减

        //字号加private void toolStripButton5_Click(object sender, EventArgs e){richTextBox1.Font = new Font(richTextBox1.Font.FontFamily,richTextBox1.Font.Size + 1, richTextBox1.Font.Style);}//字号减private void toolStripButton6_Click(object sender, EventArgs e){richTextBox1.Font = new Font(richTextBox1.Font.FontFamily, richTextBox1.Font.Size - 1, richTextBox1.Font.Style);}

前后景色

        //前景色/字体private void toolStripButton7_Click(object sender, EventArgs e){if (DialogResult.OK == colorDialog1.ShowDialog()){richTextBox1.ForeColor = colorDialog1.Color;}}//背景色private void toolStripButton8_Click(object sender, EventArgs e){if (DialogResult.OK == colorDialog1.ShowDialog()){richTextBox1.BackColor = colorDialog1.Color;}}

左中右对齐

        //左中右对其private void toolStripButton9_Click(object sender, EventArgs e){richTextBox1.SelectionAlignment = HorizontalAlignment.Left;}private void toolStripButton10_Click(object sender, EventArgs e){richTextBox1.SelectionAlignment = HorizontalAlignment.Center;}private void toolStripButton11_Click(object sender, EventArgs e){richTextBox1.SelectionAlignment = HorizontalAlignment.Right;}

添加个链接

        //连接private void toolStripButton14_Click(object sender, EventArgs e){richTextBox1.SelectedText = "http://";}

有序和无序添加

        //有序private void toolStripButton12_Click(object sender, EventArgs e){string[] strs = richTextBox1.SelectedText.Split(new char[2] {'\n', '\r'});string txt = "";for (int i = 0; i < strs.Length; i++){txt += (i + 1) + "." + strs[i] + "\n";}richTextBox1.SelectedText = txt;}//无序private void toolStripButton13_Click(object sender, EventArgs e){string[] strs = richTextBox1.SelectedText.Split(new char[2] { '\n', '\r' });string txt = "";for (int i = 0; i < strs.Length; i++){txt += "*." + strs[i] + "\n";}richTextBox1.SelectedText = txt;}

这里因为时间问题仅实现了添加没有实现取消,但其实原理相同,获取当前选中的数据,并根据回车符分成string数组,遍历在每个string的前面添加符号就行了。
取消的话原理也类似,只是判断下是否有符号,有的话切掉就行了
最后在添加到所选位置

然后是重置按钮

        //重置private void button7_Click(object sender, EventArgs e){Init();}/// <summary>/// 重置/// </summary>public void Init(){foreach (Control c in this.panel1.Controls){if (c is TextBox){((TextBox)c).Text = "";}}comboBox1.Text = "";comboBox2.Text = "";comboBox3.Text = "";richTextBox1.Text = "";pictureBox1.Image = null;}

这里新建了个方法,方便保存数据后重置
遍历所有控件,如果为输入框就清空
以及下拉框和富文本以及图片框清空
接下来就是保存
非空验证就不说了
这里我还加了个进度条显示保存进度

            //保存图片progressBar1.Value = 0;string name = DateTime.Now.Ticks.ToString();string enttime = DateTime.Now.ToString();progressBar1.Value = 10;if (imagefile != ""){File.Copy(imagefile, "../../images/" + name + ".jpg");}progressBar1.Value = 20;

以当前时间为基础取周期值为图片名称,防止图片重复,然后复制过图片来
乱入的enttime用于保存保存时间的

string imagename = name + ".jpg";progressBar1.Value = 30;string postID = "";switch (comboBox2.Text){case "财务部":postID += "C";break;case "管理部":postID += "G";break;case "客服部":postID += "K";break;case "人事部":postID += "R";break;case "销售部":postID += "X";break;case "设计部":postID += "S";break;default:break;}progressBar1.Value = 40;switch (comboBox3.Text){case "主管":postID += "zg";break;case "助理":postID += "zl";break;case "员工":postID += "yg";break;default:break;}progressBar1.Value = 50;string source = "";if (radioButton3.Checked){source = "招聘会";}else if (radioButton4.Checked){source = "智联招聘";}else if (radioButton5.Checked){source = "前程无忧";}else if (radioButton6.Checked){source = "中华英才";}else if (radioButton7.Checked){source = "其他";}

保存信息
然后中间穿插了修改信息,也就是id不为初始值时

            //修改if (Id != -1){progressBar1.Value = 60;if (!DAL.UpdateStaff(textBox1.Text, radioButton1.Checked ? "男" : "女", int.Parse(textBox7.Text), comboBox1.Text, int.Parse(textBox4.Text), int.Parse(textBox8.Text), textBox2.Text, textBox5.Text, textBox9.Text + " " + textBox10.Text + " " + textBox11.Text, textBox3.Text, textBox6.Text, source, imagename, richTextBox1.Text, postID,Id)){MessageBox.Show("保存出错!", "提示:用户信息出错", MessageBoxButtons.OK);return;}//删除原来的图片if (imagefile != ""){File.Delete(oldimage);}progressBar1.Value = 80;if (!DAL.UpdateStaffAcc(textBox13.Text, textBox12.Text,Id)){MessageBox.Show("保存出错!", "提示:账号信息出错", MessageBoxButtons.OK);return;}progressBar1.Value = 100;MessageBox.Show("保存成功!", "提示", MessageBoxButtons.OK);progressBar1.Value = 0;Init();return;}
        //修改用户public static bool UpdateStaff(string Name,string Sex, int Age, string Political, int Height, int Weight, string School, string Specialty, string GraDate, string Address, string Phone, string Source, string Photo, string Other,string PostNum, int id){string sql = $"UPDATE Staffs SET Name = '{Name}',Sex = '{Sex}',Age = {Age},Political = '{Political}',Height = {Height},Weight = {Weight},School = '{School}',Specialty = '{Specialty}',GraDate = '{GraDate}',Address = '{Address}',Phone = '{Phone}',Source = '{Source}',Photo = '{Photo}',Other = '{Other}',PostNum = '{PostNum}' WHERE StaffId = {id}";return DBHelper.GetExecuteNonQuery(sql);}
        /// <summary>/// 修改账号/// </summary>/// <param name="Account"></param>/// <param name="Password"></param>/// <param name="id"></param>/// <returns></returns>public static bool UpdateStaffAcc(string Account,string Password,int id){string sql = $"UPDATE StaffAccounts SET Account = '{Account}',Password = '{Password}' WHERE StaffId = {id}";return DBHelper.GetExecuteNonQuery(sql);}

用以修改信息,以及删除原来保存的头像和修改账号
如果是修改信息的话到这一步就return返回了
最后就是保存信息

            progressBar1.Value = 60;if (!DAL.InsertStaff(name,textBox1.Text,radioButton1.Checked?"男":"女",int.Parse(textBox7.Text),comboBox1.Text, int.Parse(textBox4.Text), int.Parse(textBox8.Text),textBox2.Text,textBox5.Text,textBox9.Text+" "+textBox10.Text+" "+textBox11.Text,textBox3.Text,textBox6.Text,source,imagename,postID,richTextBox1.Text,enttime)){MessageBox.Show("保存出错!","提示:用户信息出错",MessageBoxButtons.OK);return;}progressBar1.Value = 80;//查询idint id = DAL.SelectByNumber(name);if (!DAL.InsertStaffAcc(id,textBox13.Text,textBox12.Text)){MessageBox.Show("保存出错!", "提示:账号信息出错", MessageBoxButtons.OK);return;}progressBar1.Value = 100;MessageBox.Show("保存成功!", "提示",MessageBoxButtons.OK);progressBar1.Value = 0;Init();

首先是保存人员信息

        //添加用户public static bool InsertStaff(string Number,string Name,string Sex,int Age,string Political,int Height,int Weight,string School,string Specialty,string GraDate,string Address,string Phone,string Source,string Photo,string PostNum,string Other,string EntDate){string sql = $"INSERT INTO Staffs(Number,Name,Sex,Age,Political,Height,Weight,School,Specialty,GraDate,Address,Phone,Source,Photo,PostNum,Other,Enable,Sync,MachineId,EntDate,Positive) VALUES('{Number}','{Name}','{Sex}',{Age},'{Political}',{Height},{Weight},'{School}','{Specialty}','{GraDate}','{Address}','{Phone}','{Source}','{Photo}','{PostNum}','{Other}',1,0,1,'{EntDate}',0)";return DBHelper.GetExecuteNonQuery(sql);}

然后根据用户编码查询id

        /// <summary>/// 根据编号查询id/// </summary>/// <param name="num"></param>/// <returns></returns>public static int SelectByNumber(string num){string sql = $"SELECT StaffId FROM Staffs WHERE Number = '{num}'";return Convert.ToInt32(DBHelper.GetDataTable(sql).Rows[0][0]);}

最后保存账号

        /// <summary>/// 添加账号/// </summary>/// <param name="id"></param>/// <param name="acc"></param>/// <param name="pass"></param>/// <returns></returns>public static bool InsertStaffAcc(int id,string acc,string pass){string sql = $"INSERT INTO StaffAccounts(StaffId,Account,Password) VALUES({id},'{acc}','{pass}')";return DBHelper.GetExecuteNonQuery(sql);}

大概功能就这些
人员考勤界面

此页面就是显示数据,和界面的排序
页面初始化

        DataTable dt = new DataTable();
         dt = DAL.SelectByPost("");dt.Columns.Add("countWork");dt.Columns.Add("countOffWork");dt.Columns.Add("countLate");dt.Columns.Add("countLeave");dt.Columns.Add("countClock");for (int i = 0; i < dt.Rows.Count; i++){DataRow dr = DAL.SelectCountAtt(Convert.ToInt32(dt.Rows[i]["StaffId"]));dt.Rows[i]["countWork"] = dr[0];dt.Rows[i]["countOffWork"] = dr[1];dt.Rows[i]["countLate"] = dr[2];dt.Rows[i]["countLeave"] = dr[3];dt.Rows[i]["countClock"] = dr[4];}DisplayData(dt);

添加五列,分别用于记录正常上下班迟到早退和正常上班次数
再遍历数据表给每个数据赋值

        /// <summary>/// 根据姓名查询全部职位信息--1/// </summary>/// <returns></returns>public static DataTable SelectByPost(string name){string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Name LIKE '%{name}%'";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 统计考勤次数/// </summary>/// <param name="id"></param>/// <returns></returns>public static DataRow SelectCountAtt(int id){DataTable dt = new DataTable();dt.Columns.Add();dt.Columns.Add();dt.Columns.Add();dt.Columns.Add();dt.Columns.Add();DataRow dr = dt.NewRow();string sql1 = "SELECT COUNT(*) FROM Staffs s,Attendances a WHERE s.StaffId = a.StaffId AND s.StaffId = "+id;int count = Convert.ToInt32(DBHelper.GetDataTable(sql1).Rows[0][0]);string sql2 = "SELECT COUNT(*) FROM Staffs s,Attendances a WHERE s.StaffId = a.StaffId AND a.[Work] = 1 AND s.StaffId = "+id;int work = Convert.ToInt32(DBHelper.GetDataTable(sql2).Rows[0][0]);string sql3 = "SELECT COUNT(*) FROM Staffs s,Attendances a WHERE s.StaffId = a.StaffId AND a.OffWork = 1 AND s.StaffId = " + id;int offwork = Convert.ToInt32(DBHelper.GetDataTable(sql3).Rows[0][0]);string sql4 = "SELECT COUNT(*) FROM Staffs s,Attendances a WHERE s.StaffId = a.StaffId AND a.SignStatus = 1 AND s.StaffId = " + id;int SignStatus = Convert.ToInt32(DBHelper.GetDataTable(sql4).Rows[0][0]);dr[0] = work;dr[1] = offwork;dr[2] = count - work;dr[3] = count - offwork;dr[4] = count - SignStatus;return dr;}

分别查找次数并返回

这里涉及到一个分页
讲一下分页类,我单独创建了分页类,用于对页面进行分类,并且可用于多界面
分页
界面

分页类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;namespace PersonnelSySt
{public class Pagination{public DataTable dt = new DataTable();//数据public int rowcount;//表行数public int pagerowcount;//每页行数public int pagecount;//页数public int lastrowcount;//最后页行数public Pagination(){}/// <summary>/// 数据初始化/// </summary>/// <param name="t"></param>/// <param name="prc"></param>public void Init(DataTable t, int prc){dt = t;rowcount = dt.Rows.Count;pagerowcount = prc;pagecount = (rowcount / pagerowcount)+1;lastrowcount = rowcount % pagerowcount;}/// <summary>/// 获取当前页数据/// </summary>/// <param name="page"></param>/// <returns></returns>public DataTable GetData(int page){int up = (page - 1) * pagerowcount;if (up>rowcount){return new DataTable();}int last = 0;if (page == pagecount){last = up + lastrowcount;}else{last = up + pagerowcount;}//复制表数据DataTable newdt = dt.Copy();//清除行newdt.Rows.Clear();for (int i = up; i < last; i++){//将行添加到表newdt.ImportRow(dt.Rows[i]);}return newdt;}/// <summary>/// 获取页数/// </summary>/// <returns></returns>public int GetPageCount(){return pagecount;}/// <summary>/// 修改每页行数/// </summary>/// <param name="pc"></param>public void UpdatePageCount(int prc){pagerowcount = prc;pagecount = (rowcount / pagerowcount) + 1;lastrowcount = rowcount % pagerowcount;}}
}

主要是根据初始化方法传入初始值,包括表和每页行数
又根据传入的值计算行数页数及最后页行数
GetData方法是根据接受的页码返回对应的分段数据
再加上获取页数和修改每页行数代码完善分页类
创建全局分页

        Pagination p = new Pagination();

再回到界面,需要分类就要单独创建一个数据绑定方法用于分段显示

        //分页public void DisplayData(DataTable newdt){p.Init(newdt, 10);dataGridView1.DataSource = p.GetData(1);btnEna(1);}

因为涉及到上一页下一页的按钮是否可用,所有又创建了一个根据页数显示页面的方法,用于设置上一页下一页的是否可用和当前页值的显示

        public void btnEna(int page){txtpage.Text = page.ToString();txtJump.Text = page.ToString();int count = p.GetPageCount();if (page == 1){Previous.Enabled = false;}else{Previous.Enabled = true;}if (page == count){Next.Enabled = false;}else{Next.Enabled = true;}}

单击上一页

            int page = int.Parse(txtpage.Text) - 1;dataGridView1.DataSource = p.GetData(page);btnEna(page);

下一页

            int page = int.Parse(txtpage.Text) + 1;dataGridView1.DataSource = p.GetData(page);btnEna(page);

首页

            dataGridView1.DataSource = p.GetData(1);btnEna(1);

尾页

            dataGridView1.DataSource = p.GetData(p.GetPageCount());btnEna(p.GetPageCount());

设置每页页数

            p.UpdatePageCount(int.Parse(txtpagecount.Text));dataGridView1.DataSource = p.GetData(1);btnEna(1);

跳转到某页

            int n = int.Parse(txtJump.Text);if (n > 0 && n <= p.GetPageCount()){dataGridView1.DataSource = p.GetData(n);btnEna(n);}

这就是分页的全部内容
然后是工具栏的各种排序,这个思路简单,设置datagirdview的列排序就行
上班排序

        //上班排序bool work = true;private void toolStripMenuItem1_Click(object sender, EventArgs e){if (work){dataGridView1.Sort(dataGridView1.Columns[3], ListSortDirection.Ascending);work = false;}else{dataGridView1.Sort(dataGridView1.Columns[3], ListSortDirection.Descending);work = true;}}

下班排序

        //下班排序bool offwork = true;private void 正常下班次数排序ToolStripMenuItem_Click(object sender, EventArgs e){if (offwork){dataGridView1.Sort(dataGridView1.Columns[4], ListSortDirection.Ascending);offwork = false;}else{dataGridView1.Sort(dataGridView1.Columns[4], ListSortDirection.Descending);offwork = true;}}

迟到排序

        //迟到排序bool late = true;private void 迟到次数排序ToolStripMenuItem_Click(object sender, EventArgs e){if (late){dataGridView1.Sort(dataGridView1.Columns[5], ListSortDirection.Ascending);late = false;}else{dataGridView1.Sort(dataGridView1.Columns[5], ListSortDirection.Descending);late = true;}}

早退排序

        //早退排序bool leave = true;private void 早退次数排序ToolStripMenuItem_Click(object sender, EventArgs e){if (leave){dataGridView1.Sort(dataGridView1.Columns[6], ListSortDirection.Ascending);leave = false;}else{dataGridView1.Sort(dataGridView1.Columns[6], ListSortDirection.Descending);leave = true;}}

不正常打卡排序

        //不正常打卡排序bool clock = true;private void 不正常打卡次数排序ToolStripMenuItem_Click(object sender, EventArgs e){if (clock){dataGridView1.Sort(dataGridView1.Columns[7], ListSortDirection.Ascending);clock = false;}else{dataGridView1.Sort(dataGridView1.Columns[7], ListSortDirection.Descending);clock = true;}}

此页功能大概就这些
人员福利界面

这个界面主要就是对于员工福利的查询和添加的小功能
顶多附加分页,分页功能就不说了,参考上页
初始显示

            DisplayData(DAL.SelectBySalary(""));DataTable dt = DAL.SelectByDepartment();for (int i = 0; i < dt.Rows.Count; i++){comboBox1.Items.Add(dt.Rows[i][0]);}

获取数据

        /// <summary>/// 根据名称查询福利/// </summary>/// <param name="sal"></param>/// <returns></returns>public static DataTable SelectBySalary(string sal){string sql = $"SELECT Department,SalaryItem,Formula FROM Formulas f,Posts p WHERE f.PostNum = p.PostNum AND SalaryItem LIKE '%{sal}%'";return DBHelper.GetDataTable(sql);}

获取所有部门

        /// <summary>/// 查询所有不重复部门/// </summary>/// <returns></returns>public static DataTable SelectByDepartment(){string sql = "SELECT DISTINCT Department FROM Posts";return DBHelper.GetDataTable(sql);}

根据名称模糊查询

            if (textBox1.Text != ""){DisplayData(DAL.SelectBySalary(textBox1.Text));}else{DisplayData(DAL.SelectBySalary(""));}
        /// <summary>/// 根据名称查询福利/// </summary>/// <param name="sal"></param>/// <returns></returns>public static DataTable SelectBySalary(string sal){string sql = $"SELECT Department,SalaryItem,Formula FROM Formulas f,Posts p WHERE f.PostNum = p.PostNum AND SalaryItem LIKE '%{sal}%'";return DBHelper.GetDataTable(sql);}

根据部门查询

            if (comboBox1.Text != ""){DisplayData(DAL.SelectByFormulas(comboBox1.Text));}else{DisplayData(DAL.SelectBySalary(""));}
        /// <summary>/// 根据部门查询福利/// </summary>/// <param name="dep"></param>/// <returns></returns>public static DataTable SelectByFormulas(string dep){string sql = $"SELECT Department,SalaryItem,Formula FROM Formulas f,Posts p WHERE f.PostNum = p.PostNum AND Department LIKE '%{dep}%'";return DBHelper.GetDataTable(sql);}

还有就是添加按钮会打开添加小界面

点击保存

            if (comboBox1.Text == ""||textBox1.Text == ""||textBox2.Text == ""){MessageBox.Show("数据为空!","提示:",MessageBoxButtons.OK);return;}string dep = "";switch (comboBox1.Text){case "管理部":dep = "Gzg";break;case "人事部":dep = "Rzg";break;case "财务部":dep = "Czg";break;case "客服部":dep = "Kzg";break;case "设计部":dep = "Szg";break;case "销售部":dep = "Xzg";break;default:break;}if (DAL.InsertFormula(dep,textBox1.Text,textBox2.Text)){MessageBox.Show("添加成功!", "提示!", MessageBoxButtons.OK);this.Close();}else{MessageBox.Show("添加失败!", "提示!", MessageBoxButtons.OK);}

保存数据

        /// <summary>/// 添加公式套/// </summary>/// <param name="dep"></param>/// <param name="name"></param>/// <param name="fo"></param>/// <returns></returns>public static bool InsertFormula(string dep,string name,string fo){string sql = $"INSERT INTO Formulas(PostNum,SalaryItem,Formula) VALUES('{dep}','{name}','{fo}')";return DBHelper.GetExecuteNonQuery(sql);}

这个页面就没功能了,就是添加查询
人员查询界面

这个界面有两个大功能,一个是三个表的查询并且合并到一起去重显示,第二个就是点击每行的编辑和查看按钮传递数据跳转到人员添加界面,上面设置的构造函数便用上了
分页和初始显示数据就不多说了
搜索功能的实现

            if (textBox1.Text != ""){DataTable t1 = DAL.SelectByPost(textBox1.Text);List<object> l = new List<object>();foreach (DataRow dr in t1.Rows){l.Add(dr["StaffId"]);}DataTable t2 = DAL.SelectByDepPost(textBox1.Text);DataTable t3 = DAL.SelectByNumPost(textBox1.Text);foreach (DataRow dr in t2.Rows){if (!l.Contains(dr["StaffId"])){t1.ImportRow(dr);}}foreach (DataRow dr in t3.Rows){if (!l.Contains(dr["StaffId"])){t1.ImportRow(dr);}}DisplayData(t1);}else{DisplayData(DAL.SelectByPost(""));}

三个表合并好说,主要是去重
我的思路是根据人员id去重
先查询出一个表,并且获取查询出来的所有数据的id保存到集合中
再判断是否存在于集合内以保存不重复的数据
最后显示

        /// <summary>/// 根据姓名查询全部职位信息--1/// </summary>/// <returns></returns>public static DataTable SelectByPost(string name){string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Name LIKE '%{name}%'";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 根据部门查询职位信息---2/// </summary>/// <param name="dep"></param>/// <returns></returns>public static DataTable SelectByDepPost(string dep){string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Department LIKE '%{dep}%'";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 根据用户编号查询用户信息---3/// </summary>/// <param name="num"></param>/// <returns></returns>public static DataTable SelectByNumPost(string num){string sql = $"SELECT * FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum AND Number LIKE '%{num}%'";return DBHelper.GetDataTable(sql);}

然后是单击表内编辑和查看按钮
首先要将最后两列的类型设置为按钮类型哟

            if (e.ColumnIndex == 11){int id = Convert.ToInt32(dataGridView1.Rows[e.RowIndex].Cells[0].Value);AddStaff addStaff = new AddStaff(this,0,id);addStaff.Show();this.Hide();}else if (e.ColumnIndex == 12){int id = Convert.ToInt32(dataGridView1.Rows[e.RowIndex].Cells[0].Value);AddStaff addStaff = new AddStaff(this, 1, id);addStaff.Show();this.Hide();}

将id传过去,根据上边说过的构造函数执行修改和查看操作

普通人员界面

一共两个地方可以到此页面,就是登陆的时候如果是非人事部员工就会到此页面,还有就是主页面的跳转
这个界面主要用到一个控件tabcontrol,用于切换小组界面,功能也显而易见
主要用到七个功能,简介,签到,请假,公司基本信息,公告,留言,查看公司通讯录
简介和基本信息就是介绍的,根据自己风格兴趣写就行
下面说下其他几个
签到
显示数据和视图设置就不多说,主要就是签到和签出
签到

            DateTime n = DateTime.Now;//判断是否正常上班int b = n.Hour<8 ? 1 : 0;if (DAL.InsertByAtt(User.id,n,b,0)){MessageBox.Show("签到成功!","提示",MessageBoxButtons.OK);//刷新数据DGVInit();}else{MessageBox.Show("签到失败!", "提示", MessageBoxButtons.OK);}
        /// <summary>/// 签到/// </summary>/// <param name="id"></param>/// <param name="STime"></param>/// <param name="work"></param>/// <param name="Sign"></param>/// <returns></returns>public static bool InsertByAtt(int id, DateTime STime, int work, int Sign){string sql = $"insert into Attendances(StaffId,SignTime,[Work],SignStatus) VALUES ({id},'{STime}',{work},{Sign})";return DBHelper.GetExecuteNonQuery(sql);}

签出
这里实现思路:一般公司正常流程签到后就是签出,所以只需寻找数据库最新的一条数据修改签出时间就行

            //获取签到信息DataTable dt = DAL.SelectBySign(User.id);int id = Convert.ToInt32(dt.Rows[0]["AttendanceId"]);DateTime d = Convert.ToDateTime(dt.Rows[0]["SignTime"]);int dn = Convert.ToInt32(dt.Rows[0]["Work"]);//签出时间DateTime n = DateTime.Now;//是否正常下班int b = n.Hour > 17 ? 1 : 0;//上班时间string time = (n - d).Hours.ToString() + "." + (n - d).Minutes.ToString() + ":" + (n - d).Milliseconds.ToString();if (DAL.UpdateByOut(n,b,time,dn==1&&b==1?1:0,id)){MessageBox.Show("签出成功!", "提示", MessageBoxButtons.OK);//刷新DGVInit();}else{MessageBox.Show("签出失败!", "提示", MessageBoxButtons.OK);}
        /// <summary>/// 根据id查询签到/// </summary>/// <param name="id"></param>/// <returns></returns>public static DataTable SelectBySign(int id){string sql = $"SELECT AttendanceId,SignTime,[Work] FROM Attendances WHERE StaffId = {id} ORDER BY AttendanceId DESC";return DBHelper.GetDataTable(sql);}
        /// <summary>/// 签出/// </summary>/// <param name="Out"></param>/// <param name="work"></param>/// <param name="time"></param>/// <param name="sign"></param>/// <param name="id"></param>/// <returns></returns>public static bool UpdateByOut(DateTime Out,int work,string time,int sign,int id){string sql = $"UPDATE Attendances SET OutTime = '{Out}',OffWork = {work},WorkTime = '{time}',SignStatus = {sign} WHERE AttendanceId = " + id;return DBHelper.GetExecuteNonQuery(sql);}

然后就是请假,我这里是添加了一个具有起始时间的状态为2的请假信息

            if (DialogResult.OK == MessageBox.Show("确认申请请假吗?","提示",MessageBoxButtons.OKCancel)){string D = (dateTimePicker2.Value - dateTimePicker1.Value).Days.ToString();string H = (dateTimePicker2.Value - dateTimePicker1.Value).Hours.ToString();string M = (dateTimePicker2.Value - dateTimePicker1.Value).Minutes.ToString();if (DAL.InsertByAtt(User.id,dateTimePicker1.Value,1,dateTimePicker2.Value,1,D+"."+H+":"+M,2)){MessageBox.Show("申请成功!", "提示", MessageBoxButtons.OK);DGVInit();}else{MessageBox.Show("申请失败!", "提示", MessageBoxButtons.OK);}}
        /// <summary>/// 添加考勤信息/// </summary>/// <param name="id"></param>/// <param name="STime"></param>/// <param name="work"></param>/// <param name="OTime"></param>/// <param name="Owork"></param>/// <param name="time"></param>/// <param name="Sign"></param>/// <returns></returns>public static bool InsertByAtt(int id,DateTime STime,int work,DateTime OTime,int Owork,string time,int Sign){string sql = $"insert into Attendances(StaffId,SignTime,[Work],OutTime,OffWork,WorkTime,SignStatus) VALUES ({id},'{STime}',{work},'{OTime}',{Owork},'{time}',{Sign})";return DBHelper.GetExecuteNonQuery(sql);}

然后是公告和留言功能
两个功能差不多一个是读取txt,一个是保存txt
创建公告文件夹Announcement,里边保存一个测试文件Announcement.txt
读取功能

        //读取公告public string SelectAnnouncement(){string file = "../../Announcement/Announcement.txt";FileStream fs = new FileStream(file,FileMode.Open,FileAccess.Read);StreamReader sr = new StreamReader(fs);string txt = sr.ReadToEnd();sr.Close();fs.Close();return txt;}

创建io文件流读取文件
留言功能
创建留言文件夹leave a message

            string txt = LAMessage.Text;if (txt != ""){string time = DateTime.Now.Ticks.ToString();string txtname = "../../leave a message/" + (radioButton1.Checked ? User.id.ToString() + "-" + time : time) + ".txt";WriterTxt(txtname,txt);MessageBox.Show("留言成功!", "提示", MessageBoxButtons.OK);LAMessage.Text = "";}else{MessageBox.Show("留言为空!", "提示", MessageBoxButtons.OK);}
        //写入文件public void WriterTxt(string txtname,string txt){FileStream fs = new FileStream(txtname,FileMode.Create,FileAccess.Write);StreamWriter sw = new StreamWriter(fs);sw.Write(txt);sw.Close();fs.Close();}

判断是否匿名,匿名则使用时间码开头,实名则使用用户id开头,这里可以延伸一个查看用户留言功能,时间问题笔者未实现
在一个是公司通讯录,就是一个绑定数据

        /// <summary>/// 查询电话簿/// </summary>/// <returns></returns>public static DataTable SelectByPhone(){string sql = "SELECT Department,Post,Name,Phone FROM Staffs s,Posts p WHERE s.PostNum = p.PostNum";return DBHelper.GetDataTable(sql);}

|
|
|
以上就是此项目全部内容

一个小项目,但是开发过程收获颇多,有复习也有学习课程以外的,果然实战是提升实力最快的方法,遂写出此文,与诸位共勉,也以此留念。

c# winform 实践项目---人员管理系统相关推荐

  1. C语言项目实践--公司人员管理系统

    一.设计任务 1.1设计题目的描述 (1)了解并掌握算法的设计方法,具备初步的独立分析和设计能力: (2)初步掌握软件开发过程的问题分析.系统设计.程序编码.测试等基本方法和技能: (3)提高综合运用 ...

  2. Javaweb + MVC 实现企业人员管理系统全过程记录(配项目所有代码及数据库文件)

    前言:因为研究生入学任务需要做一个企业人员管理系统,那就做呗... 项目及数据文件下载地址:https://download.csdn.net/download/qq_39410381/1154652 ...

  3. C#winform实现学生人员信息管理系统,可视化查看人员信息,一键修改、删除等,唯美登陆界面

    使用展示: 一.登陆.注册界面 如果是新用户没有注册过的话,点击注册按钮注册.如果已经注册了,则直接输入账号密码登陆即可.  二.人员信息登记 点击选择头像可选择头像,登记信息后点击保存信息按钮即可. ...

  4. [数据结构实践项目]变态的停车场管理系统

    [数据结构实践项目]变态的停车场管理系统 项目简介 设停车场是一个可以停放 n 辆汽车的南北方向的狭长通道,且只有一个大门可供汽车进出.汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在 ...

  5. 计算机会计学ufo报表,计算机会计实践部分工资管理系统.ppt

    <计算机会计实践部分工资管理系统.ppt>由会员分享,可在线阅读,更多相关<计算机会计实践部分工资管理系统.ppt(22页珍藏版)>请在人人文库网上搜索. 1.计算机会计学,主 ...

  6. 基于springboot+vue的戒毒所人员管理系统 毕业设计-附源码251514

    Springboot戒毒所人员管理系统 摘要 随着社会各个领域的信息化进程加快,先进的数字和网络技术为公安执法部门提供了高效的沟通手段.在我国公安监管信息化建设作为监管信息化建设的其中一部分,戒毒所人 ...

  7. 视频教程-C#WinForm工业企业销售管理系统开发-C#

    C#WinForm工业企业销售管理系统开发 二十多年的企业管理软件开发经历,熟知管理软件的整个开发流程,熟练掌握VFP语言,掌握VB语言,了解JAVA.asp.net.CSS.HTML/HTML5等语 ...

  8. Springboot社区人员管理系统的设计与实现 毕业设计-附源码260839

    springboot社区人员管理系统 摘  要 随着社会的发展,社会的各行各业都在利用信息化时代的优势.计算机的优势和普及使得各种信息系统的开发成为必需. 社区人员管理系统,主要的模块包括查看首页.用 ...

  9. nodejs 实践项目_NodeJS:最佳生产实践

    nodejs 实践项目 by Saurabh Rayakwar 通过索拉比·雷阿克瓦尔 NodeJS:最佳生产实践 (NodeJS: Best Practices for Production) Th ...

最新文章

  1. 13_文件的操作模式
  2. 7/15 我的第一篇博客-写给自己
  3. SendEmail使用TLS发送邮件
  4. 我是一名黑客我也是一名程序员
  5. Python创建单例模式的5种方法
  6. VC++ MFC获取对话框上控件的位置
  7. gradle是否可以编译c语言,build.gradle按条件编译与cmake配置
  8. 移动一个网站集所使用的内容数据库
  9. Boost.log链接问题
  10. git 镜像下载和基本使用
  11. 流程图用什么软件做?好用的流程图软件盘点
  12. Codeforces469div2F curfew(贪心)
  13. 201421410013 唐昭靖 作业1
  14. ur机器人计算机模拟仿真,ur机器人编程-设置工具
  15. 互联网红利之道-流量变现
  16. Spring Cloud 2022.0.0正式发布:OpenFeign稳得很全面迈向GraalVM
  17. 学习随笔#12 最优化控制(Optimal Control)
  18. 简单研究Unity中的万向锁和欧拉角以及四元数
  19. 交换机组播风暴_cisco交换机风暴控制
  20. java中50个关键字以及各自用法大全

热门文章

  1. TCK纷争和Apache项目管理机制
  2. 搜索引擎技术学习笔记一
  3. 基于某大学的论文系统的开发实例分析
  4. MACOS无法删除文件错误代码43
  5. 中国数据交易实践趋势报告(2022年)
  6. H265关于RTP封包
  7. html 图片在一个div中放大缩小效果
  8. c语言12个球取8个,08年计算机二级考试C语言辅导:12个球的程序
  9. 仓鼠的鸡蛋(线段树)
  10. “缺陷管理工具”禅道—升华Bug处理流程与相关属性