c# winform 实践项目---人员管理系统

这篇具有很好参考价值的文章主要介绍了c# winform 实践项目---人员管理系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

xx人员管理系统

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

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

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

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

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

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

数据库设计

*****员工表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

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

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

页面及代码设计

首先创建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();
                //声明datatable
                DataTable dt = new DataTable();
                //声明断开式连接对象
                SqlDataAdapter da = new SqlDataAdapter(sql, conn);
                //赋值给datatable
                da.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# winform 实践项目---人员管理系统
我使用的是无边框窗口,设定了窗口初始显示位置
页面阴影和可拖动参考我的另一篇文章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;
            }

登录界面没什么东西
然后下一个主页面
c# winform 实践项目---人员管理系统
首先就是七个功能页面的跳转

            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进行显示

其中涉及到密码修改界面
c# winform 实践项目---人员管理系统
包含多个验证和根据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);
            }

接下来就是主菜了
考勤管理界面
c# winform 实践项目---人员管理系统
此界面用于管理人员的考勤匹配
首先就是菜单栏和工具栏的设置
菜单栏单纯的写文字
工具栏要添加按钮模式,同时设置为图片按钮并存,用以显示图标
在一个就是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);
            }

考勤页面主要就是这些功能
人员部门页面
c# winform 实践项目---人员管理系统
此页面用于管理人员的部门信息,包括人员统计及管理等
首先就是页面的初始化显示
构造方法同上个页面
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();

人员添加界面
c# winform 实践项目---人员管理系统
此页面主要用于添加人员信息
因为有多个界面需要跳转到这个界面,所以这里出了单纯传页面有多个构造方法的重载

        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;
            //查询id
            int 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);
        }

大概功能就这些
人员考勤界面
c# winform 实践项目---人员管理系统
此页面就是显示数据,和界面的排序
页面初始化

        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;
        }

分别查找次数并返回

这里涉及到一个分页
讲一下分页类,我单独创建了分页类,用于对页面进行分类,并且可用于多界面
分页
界面
c# winform 实践项目---人员管理系统
分页类

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;
            }
        }

此页功能大概就这些
人员福利界面
c# winform 实践项目---人员管理系统
这个界面主要就是对于员工福利的查询和添加的小功能
顶多附加分页,分页功能就不说了,参考上页
初始显示

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

还有就是添加按钮会打开添加小界面
c# winform 实践项目---人员管理系统
点击保存

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

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

            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传过去,根据上边说过的构造函数执行修改和查看操作

普通人员界面
c# winform 实践项目---人员管理系统
一共两个地方可以到此页面,就是登陆的时候如果是非人事部员工就会到此页面,还有就是主页面的跳转
这个界面主要用到一个控件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 实践项目---人员管理系统
一个小项目,但是开发过程收获颇多,有复习也有学习课程以外的,果然实战是提升实力最快的方法,遂写出此文,与诸位共勉,也以此留念。文章来源地址https://www.toymoban.com/news/detail-407141.html

到了这里,关于c# winform 实践项目---人员管理系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Cloud +UniApp 智慧工地云平台源码,智能监控和AI分析系统,危大工程管理、视频监控管理、项目人员管理、绿色施工管理

    一套智慧工地云平台源码,PC管理端+APP端+平板端+可视化数据大屏端源码 智慧工地可视化系统利用物联网、人工智能、云计算、大数据、移动互联网等新一代信息技术,通过工地中台、三维建模服务、视频AI分析服务等技术支撑,实现智慧工地高精度动态仿真,趋势分析、预

    2024年02月14日
    浏览(36)
  • 云借阅图书管理系统的测试项目实践

    项目背景:通过学习到的 SSM(Spring + SpringMVC + MyBatis)框架知识来实现一个前后端分离的云借阅图书管理系统。 目标:完成系统搭建,用户和图书相关模块编写,在 SSM 框架整合的基础上实现系统功能。 时间:2022-11-30 到 2022-12-26。 项目成员: 项目经理:lyg 产品经理:cch 开

    2024年02月10日
    浏览(50)
  • GPS人员定位系统:一种更安全高效的人员定位管理系统

    GPS人员定位系统从物联网及无线通信技术创新的角度,结合RTK测量技术,为一些需要高精度的行业提供厘米级甚至毫米级定位精度的解决方案,提高室外工作效率,实现企业安全生产智慧管理。 随着北斗GPS定位系统组网成功,关于GPS、定位、RTK等等之类的话题频繁登上热搜,

    2024年01月23日
    浏览(32)
  • JAVA:实现简单的人员管理系统

    ------实现系统的增删改查,代码会在底部会发出来; 1.1         右键在指定目录新建一个软件包; 1.2         在 Name 取好名字点击 Finish 建立包;  1.3         右键新建的包创建两个类;  1.4         取名后点击 Finish ;         为了看起来更规范,我一个取名为 Staff 、

    2024年02月11日
    浏览(27)
  • 高校人员信息管理系统(C++版)

    目录                                  高校人员信息管理系统                                   一、问题描述 二、功能要求 三、问题的解决方案 四、代码段 1、多文件 2、单文件 备注:大一(下)C++语言课程设计 某高校有四类员工:教师、实验员、行政人员,教

    2024年02月10日
    浏览(60)
  • 基于微信小程序的外来人员管理系统

    随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,微信被用户普遍使用,为方便用户能够可以随时进行查看个人中心、外籍人员信息、派出所信息等,特开发了

    2024年02月19日
    浏览(32)
  • 基于Android Studio开发的人员管理系统APP

    目录 人员管理系统 前言 一、系统的大概流程 二、详细开发步骤 1.登陆界面 2.中间跳转界面 3.添加用户 4.全部用户界面  5.项目下载 总结 这是一个具有登录功能和人员信息增删改查功能的人员管理系统,在之前也有做过一个通过http协议与云平台对接的app,正好需要完成一个

    2024年02月07日
    浏览(55)
  • 高校人员信息管理系统(Java课程设计,带图形界面版)

    题目 1 、问题描述 某高校有四类员工:教师、实验员、行政人员,教师兼行政人员;共有的信息包括:编号、姓名、性别、年龄等。其中,教师还包含的信息有:所在系部、专业、职称;实验员还包含的信息由:所在实验室、职务;行政人员还包含的信息有:政治面貌、职称

    2024年02月09日
    浏览(31)
  • asp.net审计项目管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

    一、源码特点         asp.net审计项目管理系统 是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语言 开发 二、功能介绍 (1)科室管理:对科室信息进行添加、删除、修改和查看 (2)权限管

    2024年02月11日
    浏览(39)
  • 基于C#的大学生创新创业项目管理系统--84236(免费领源码)可做计算机毕业设计JAVA、PHP、爬虫、APP、小程序、C#、C++、python、数据可视化、大数据、全套文案

    随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,高校当然也不例外。大学生创新创业项目管理系统是以实际运用为开发背景,运用软件工程原理和开发方法,采用C#语言构建的一个管理系统。整个开发

    2024年02月03日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包