简介:这份企业人力资源管理系统设计说明书面向计算机相关专业的课程设计、毕业设计学生及需要撰写开题报告与概要设计文档的开发者,围绕人事信息管理这一典型场景,提供从需求分析到模块实现的完整设计思路。资源包共1个doc文件,约530KB,内容按需求分析、数据库设计、各功能模块设计与实现、考核评价点四大部分组织,涵盖部门信息管理、员工信息管理、工资管理、用户管理四大模块,并给出部门表、员工表、工资表、权限表、日志表等数据库组成方案,以及开发环境选型、栏目设计、增删改查与查询输出等具体实现要点。目前已有71人学习下载。读者可据此快速搭建课程设计文档框架,理清功能模块划分与数据库表结构,掌握需求分析、总体设计原则与考核评价维度的写作方法,适合作为开题报告、概要设计说明书及答辩准备的参考模板。
1. 从一份 .doc 设计说明书说起:hrsys 库、四张表与三层结构到底怎么落地
很多同学拿到「企业人力资源管理系统设计说明书」这类课程设计资源,第一反应是当成开题报告模板,复制粘贴改改封面就交了。但真正做过答辩的人都知道,老师翻两页就会问:你的数据库建了几张表?部门表和员工表怎么关联?工资的实发金额是存字段还是算出来的?这份说明书的价值不在文字,而在它把一套可运行系统的骨架写清楚了——数据库名 hrsys,四张核心表(用户表、部门表、员工基本信息表、员工工资表),开发环境是 Visual Basic.NET + SQL Server 2000,功能覆盖部门管理、职工管理、工资管理、用户管理四大模块,还附了 12 条考核评价点。它适合两类人:一是要交课程设计、需要一份能跑通的最小系统参考的在校生;二是想快速搭一个 C/S 架构增删改查练手项目的新手。下面我按「说明书讲了什么 → 怎么照着建库建表 → 代码怎么写 → 哪里容易翻车」的顺序拆一遍,能直接抄的部分我都给出来。
2. 数据库设计:hrsys 四张表怎么建、主外键怎么连
2.1 先想清楚表关系,再动手写 CREATE TABLE
说明书里给了数据表关系图,但没把字段类型写全。我按它描述的业务补全一套能直接执行的建表语句。核心关系是:部门表是主表,员工基本信息表通过部门编号关联它;员工工资表通过员工编号关联员工表;用户表独立,只管登录和权限。这里有个选型理由要说清楚——为什么部门编号、员工编号用字符型而不是自增整型?因为课程设计答辩常要求「编号可读」,比如 D001、E1001,方便演示时肉眼核对,而且导入历史工资时用业务编号做匹配比自增 ID 更稳。
-- 创建数据库 CREATE DATABASE hrsys; GO USE hrsys; GO -- 部门表:部门编号为主键 CREATE TABLE Department ( DeptID VARCHAR(10) PRIMARY KEY, -- 部门编号,如 D001 DeptName VARCHAR(50) NOT NULL, -- 部门名称 EmpCount INT DEFAULT 0, -- 在职人数 Phone VARCHAR(20) -- 联系方式 ); -- 员工基本信息表:EmpID 主键,DeptID 外键指向部门表 CREATE TABLE Employee ( EmpID VARCHAR(10) PRIMARY KEY, -- 员工编号 EmpName VARCHAR(30) NOT NULL, -- 姓名 Gender CHAR(2), -- 性别 BirthDate DATETIME, -- 出生日期 DeptID VARCHAR(10), -- 所在部门 Education VARCHAR(20), -- 学历 CONSTRAINT fk_emp_dept FOREIGN KEY (DeptID) REFERENCES Department(DeptID) ); -- 员工工资表:以工资月份+员工编号做联合主键,避免同月重复发放 CREATE TABLE Salary ( SalaryMonth VARCHAR(7), -- 工资月份,如 2024-06 EmpID VARCHAR(10), -- 员工编号 BaseSalary DECIMAL(10,2), -- 基本工资 FoodAllow DECIMAL(10,2), -- 伙食补贴 MedAllow DECIMAL(10,2), -- 医疗补贴 RealSalary DECIMAL(10,2), -- 实发工资 PRIMARY KEY (SalaryMonth, EmpID), CONSTRAINT fk_sal_emp FOREIGN KEY (EmpID) REFERENCES Employee(EmpID) ); -- 用户表:权限 0 为管理员,1 为普通用户 CREATE TABLE SysUser ( UserName VARCHAR(20) PRIMARY KEY, Password VARCHAR(50) NOT NULL, UserRole INT DEFAULT 1 );建表顺序不能乱:先 Department,再 Employee,最后 Salary,否则外键引用会报「对象不存在」。参数上,金额字段统一用 DECIMAL(10,2),别用 FLOAT,否则工资累加会出现 0.30000000000000004 这种玄学尾数,答辩演示时对不上账很尴尬。实发工资 RealSalary 我建议存成字段而不是每次查询现算,原因是说明书里明确有「导入历史工资」功能,历史月份的补贴可能和当月规则不同,现算会篡改历史数据。
2.2 用存储过程封装增删改,别把 SQL 散在窗体里
说明书特别强调「本设计使用的是存储过程」,这是它比一般课程设计高一档的地方。把业务规则放服务器端,前台只传参,既减轻网络传输,也避免 SQL 注入。下面以部门维护为例给三个存储过程。
-- 新增部门 CREATE PROCEDURE sp_AddDept @DeptID VARCHAR(10), @DeptName VARCHAR(50), @EmpCount INT, @Phone VARCHAR(20) AS BEGIN INSERT INTO Department(DeptID, DeptName, EmpCount, Phone) VALUES(@DeptID, @DeptName, @EmpCount, @Phone); END GO -- 修改部门 CREATE PROCEDURE sp_UpdateDept @DeptID VARCHAR(10), @DeptName VARCHAR(50), @Phone VARCHAR(20) AS BEGIN UPDATE Department SET DeptName=@DeptName, Phone=@Phone WHERE DeptID=@DeptID; END GO -- 删除部门:先校验该部门下是否还有员工 CREATE PROCEDURE sp_DeleteDept @DeptID VARCHAR(10) AS BEGIN IF EXISTS(SELECT 1 FROM Employee WHERE DeptID=@DeptID) RETURN -1; -- 有员工,禁止删除 DELETE FROM Department WHERE DeptID=@DeptID; RETURN 0; END逻辑说明:sp_DeleteDept 里那个 EXISTS 判断是血泪经验。说明书 3.3.1 只写了「删除部门前需确认该部门下无员工信息关联」,但没给实现。如果不加这层校验,直接 DELETE 会因为外键约束报错,程序抛异常弹一堆英文,演示时很难看。返回 -1 让前台弹「该部门下仍有员工,无法删除」,体验就正常了。参数说明:@DeptID 是字符型,调用时前台传字符串,别传数字,否则类型不匹配。
3. 三层结构与窗体实现:登录鉴权、DataGrid 绑定、工资计算
3.1 严格三层:数据访问层单列,考核点第 1 和第 11 条都盯这个
说明书考核评价点里,「使用直连数据库读取、提交数据,数据访问层单列,严格按照 3 层结构分层」出现了两次,合计 15 分,是权重最高的必做项。三层指表示层(窗体)、业务逻辑层(BLL)、数据访问层(DAL)。很多同学图省事,把 SqlConnection 直接写在按钮点击事件里,这样表示层和数据层耦合,老师一看代码就扣分。正确做法是 DAL 里写一个统一的数据库访问类。
' DAL/DbHelper.vb —— 数据访问层,所有窗体共用 Imports System.Data.SqlClient Public Class DbHelper ' 连接字符串集中管理,改服务器只改这一处 Private Shared connStr As String = _ "Data Source=.;Initial Catalog=hrsys;Integrated Security=True" ' 执行增删改,返回受影响行数 Public Shared Function ExecuteNonQuery(ByVal spName As String, _ ByVal params() As SqlParameter) As Integer Using conn As New SqlConnection(connStr) Using cmd As New SqlCommand(spName, conn) cmd.CommandType = CommandType.StoredProcedure If params IsNot Nothing Then cmd.Parameters.AddRange(params) conn.Open() Return cmd.ExecuteNonQuery() End Using End Using End Function ' 执行查询,返回 DataTable 供 DataGrid 绑定 Public Shared Function ExecuteQuery(ByVal spName As String, _ ByVal params() As SqlParameter) As DataTable Dim dt As New DataTable() Using conn As New SqlConnection(connStr) Using cmd As New SqlCommand(spName, conn) cmd.CommandType = CommandType.StoredProcedure If params IsNot Nothing Then cmd.Parameters.AddRange(params) Using da As New SqlDataAdapter(cmd) da.Fill(dt) End Using End Using End Using Return dt End Function End Class逻辑说明:ExecuteNonQuery 用于增删改,ExecuteQuery 用于查询后绑定 DataGrid。参数用 SqlParameter 数组传入,天然防注入。连接字符串里 Data Source 用点号代表本机,Integrated Security=True 表示用 Windows 身份验证,省去写账号密码。如果你用的是 SQL Server 账号登录,改成User ID=sa;Password=你的密码。注意 Using 语句会自动释放连接,别手动 Close 又 Dispose,重复释放会抛异常。
3.2 登录窗体与权限控制:菜单可见性按 UserRole 走
说明书 3.2 写「管理员默认权限为 0,一般用户默认权限为 1,管理员拥有比一般用户更多的系统管理权限」,考核点第 2 条要求「登录后按照权限控制菜单可见性」。实现思路是登录成功后把 UserRole 存到一个全局模块,主窗体加载时按角色隐藏菜单。
' 登录按钮点击事件 Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click Dim params() As SqlParameter = { New SqlParameter("@UserName", txtUser.Text.Trim()), New SqlParameter("@Password", txtPwd.Text.Trim()) } Dim dt As DataTable = DbHelper.ExecuteQuery("sp_CheckLogin", params) If dt.Rows.Count = 0 Then MessageBox.Show("用户名或密码错误") Return End If ' 全局变量记录当前角色 CurrentUser = dt.Rows(0)("UserName").ToString() CurrentRole = CInt(dt.Rows(0)("UserRole")) Me.DialogResult = DialogResult.OK End Sub ' 主窗体 Load 事件:普通用户隐藏用户管理菜单 Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load If CurrentRole = 1 Then mnuUserManage.Visible = False -- 普通用户看不到用户管理 End If End Sub对应的存储过程 sp_CheckLogin 就是SELECT UserName, UserRole FROM SysUser WHERE UserName=@UserName AND Password=@Password。参数说明:密码这里为了演示是明文比对,实际项目要做哈希,但课程设计阶段明文能跑通即可,答辩时主动说明「生产环境需加密」反而是加分项。注意 txtUser.Text.Trim() 的 Trim 不能省,用户复制粘贴带空格是高频翻车点。
3.3 工资计算:导入历史 + 当月调整,实发金额怎么算
说明书 3.5.1 描述得很清楚:第一次使用需人工输入基本工资和各项补贴,点【计算当月工资】算出实发工资;以后月份可【导入工资历史】再单独调整。考核点第 9 条给了 15 分,是难度最高的三星项。实现分两步:导入历史用 INSERT INTO ... SELECT,计算用 UPDATE。
-- 导入历史工资:把上个月的记录复制到本月,实发先置 0 CREATE PROCEDURE sp_ImportHistory @NewMonth VARCHAR(7), @OldMonth VARCHAR(7) AS BEGIN INSERT INTO Salary(SalaryMonth, EmpID, BaseSalary, FoodAllow, MedAllow, RealSalary) SELECT @NewMonth, EmpID, BaseSalary, FoodAllow, MedAllow, 0 FROM Salary WHERE SalaryMonth = @OldMonth; END GO -- 计算实发工资:基本工资 + 伙食补贴 + 医疗补贴 CREATE PROCEDURE sp_CalcSalary @SalaryMonth VARCHAR(7) AS BEGIN UPDATE Salary SET RealSalary = BaseSalary + FoodAllow + MedAllow WHERE SalaryMonth = @SalaryMonth; END逻辑说明:先导入再计算,顺序不能反。导入时 RealSalary 置 0,是为了让「未计算」和「已计算」有区分,前台可以用颜色标记。计算逻辑里如果企业有扣税、扣社保,就在 UPDATE 里继续减,说明书摘要提到「扣除个人所得税和社会保险费用」,可以加- Tax - Insurance两个字段。参数说明:@NewMonth 和 @OldMonth 格式必须是 'yyyy-MM',如果前台用 DateTimePicker 取值,记得.ToString("yyyy-MM"),直接 ToString 会带时分秒导致匹配不上。
4. 避坑与排查:课程设计答辩前必须过的五道坎
4.1 现象:DataGrid 改了数据但数据库没变
原因:DataGrid 默认只是展示,用户在里面直接编辑单元格,改的是内存里的 DataTable,没有回写数据库。说明书 3.3.1 写的是「选中信息绑定到 textbox 再修改」,所以正确交互是选中行→填到文本框→点修改按钮走存储过程。解决:把 DataGrid 的 ReadOnly 设为 True,禁止直接编辑,所有修改走按钮。
4.2 现象:删除部门时报外键约束错误
原因:该部门下还有员工,直接 DELETE 触发 fk_emp_dept 约束。解决:用 2.2 里的 sp_DeleteDept,先 EXISTS 判断再删,返回 -1 时前台提示「请先转移或删除该部门员工」。
4.3 现象:查询员工按姓名查不到,明明库里有
原因:SQL Server 默认排序规则对中文不敏感,但 LIKE 拼接时如果写成'%' + @Name + '%'而参数类型是 NVARCHAR 之外的,可能匹配失败;更常见的是前后空格没 Trim。解决:存储过程里用WHERE EmpName LIKE '%' + LTRIM(RTRIM(@EmpName)) + '%',前台传参也 Trim 一次。
4.4 现象:打印按钮点了没反应,或导出 Excel 乱码
原因:说明书 3.4.2 说打印通过 Excel 样式输出,如果没装 Office 或者用了错误的 COM 引用,就会静默失败。解决:确认项目引用了 Microsoft.Office.Interop.Excel,且目标机器装了 Excel;导出时用Encoding.Default而非 UTF-8,避免中文乱码。
4.5 现象:换台电脑运行就连不上数据库
原因:连接字符串写死了Data Source=192.168.x.x或某个实例名。解决:把连接字符串抽到配置文件 app.config,部署时只改配置不改代码。这也是考核点第 11 条「数据访问层单列」的延伸——连接信息也该单列。
5. 进阶技巧:把说明书变成可演示的答辩利器
到这一步系统能跑了,但答辩拿高分还差一点。我的习惯是给这份设计说明书配一个「演示脚本」:先以普通用户登录,展示部门查询和职工查询(证明权限控制生效,菜单里没有用户管理);退出后用管理员登录,演示新增部门、新增员工、导入历史工资、计算当月工资、打印工资条,最后展示用户管理里新增一个普通用户。整个流程 5 分钟,正好覆盖 12 个考核点。
再给一个验证数据一致性的技巧:在 SQL Server 里跑一句对账查询,确认工资表的实发金额等于三项之和,答辩时如果老师质疑计算逻辑,直接把这个结果贴出来。
-- 对账:找出实发工资不等于三项之和的异常记录 SELECT SalaryMonth, EmpID, BaseSalary, FoodAllow, MedAllow, RealSalary, (BaseSalary + FoodAllow + MedAllow) AS ShouldBe FROM Salary WHERE RealSalary <> (BaseSalary + FoodAllow + MedAllow);正常应该返回 0 行。如果返回了记录,说明有月份没执行 sp_CalcSalary,或者导入历史后忘了重算。这个查询我每次交付前都强制走一遍,比肉眼核对几十行数据靠谱得多。
还有一个容易被忽略的点:说明书里「合理冗余」原则提到「为了提高系统的响应时间,合理的数据冗余也是必要的」。部门表里的 EmpCount(在职人数)就是典型冗余字段——它可以从 Employee 表 COUNT 出来,但每次查部门都 COUNT 一次没必要。做法是在新增/删除员工时同步更新 EmpCount,用触发器或存储过程都行。触发器写法:
-- 员工新增后,对应部门在职人数 +1 CREATE TRIGGER trg_EmpInsert ON Employee AFTER INSERT AS BEGIN UPDATE Department SET EmpCount = EmpCount + 1 WHERE DeptID IN (SELECT DeptID FROM inserted); END注意 inserted 是触发器里的虚拟表,代表本次插入的行。删除员工时对应写一个 AFTER DELETE 触发器做 -1。这样部门列表页直接读 EmpCount,不用联表 COUNT,响应快,也符合说明书的设计原则。从那以后我每次做这类课程设计,都会先把冗余字段的同步逻辑用触发器锁死,再写前台代码,否则演示到一半人数对不上,解释起来很被动。希望帮到你。
本文还有配套的精品资源,点击获取