人事管理系统

时间:2022-02-10 16:37:56
人事管理系统二、充分理解课程设计的目的和意义    人事管理是任何企事业单位都需要进行的一项工作,因此,开发制作人事管理系统具有较大的社会现实意义,同时人事管理系统是一切数据库应用系统的典范。它具有数据库应用系统的特征,,系统结构与现实生活紧密结合,具体直观,是数据库应用开发中经常进行例证的好例子。人事管理系统三、系统设计1.系统功能分析人事管理系统主要有以下几项功能要求:☆ 新员工资料的输入☆ 自动分配员工号,并且设置初始的用户密码☆ 人事变动的详细记录,包括岗位和部门的调整☆ 员工信息的查询和修改,包括员工个人信息和密码等2.系统功能模块设计根据系统功能的要求,可以将系统分解成几个功能模块来分别设计,功能模块如右图所示。3.与其他系统的关系本系统是公司人事管理信息系统的基础部分,它为其他子系统,如考勤管理系统、工资管理系统和员工培训系统,提供员工的基本信息。同时为其它系统提供了员工登录的密码认证和权限分配功能。4.数据流程图

人事管理系统
 

               
四、数据库设计 1.数据库需求分析    根据数据流程图,可以列出以下数据项和数据结构:     员工信息:员工号、密码、权限、姓名、性别、生日、部门、职务、教育程度、专业、通讯地址、电话、E-mail、当前状态和备注。     人事变动:记录号、员工、变动和详细描述。 所需的外部数据支持:     部门设置:部门编号、部门名称…… 2.数据库概念结构设计    下图是人事管理系统的E-R图。   人事管理系统                   3.数据库逻辑结构设计与实现    根据E-R图,本系统需要有2个数据表分别存放员工个人信息和人事变动记录。并且需要一个外部数据表(部门信息)的支持。同时部分记录字段要用代码来表示,因此需要3个代码表来分别记录教育程度、职务和人事变更的代码。最后,设立一个计数器数据表用于实现员工号的自动分配。这7个数据表用Access 2000实现,Access 2000中的设计视图如下所示。其中数据类型的细节应根据具体字段分别设置。
字段大小 索引 必填字段
6 有(无重复)
20
1
10
1
中日期
3
3
1
20
50
20
50
1
   
人事管理系统 PERSON员工个人信息表
字段大小 索引 必填字段
整型 有(无重复)
6
1
常规日期
   
人事管理系统         PERSONNEL人事变更记录表
字段大小 索引 必填字段
3 有(无重复)
20
人事管理系统      EDU_LEVEL受教育程度代码表
字段大小 索引 必填字段
3 有(无重复)
20
人事管理系统      JOB职务代码表
字段大小 索引 必填字段
3 有(无重复)
20
人事管理系统     PESONNEL_CHANGE人事变动代码表
字段大小 索引 必填字段
3 有(无重复)
整型
10
人事管理系统       COUNTER 计数器
字段大小 索引 必填字段
3 有(无重复)
20
6
   
人事管理系统       DEPARTMENT部门信息表 4.初始数据的输入     需要输入的初始数据包括:人员信息、部门信息、计数器、受教育程度代码、职务代码和人事变动代码。 人员信息
ID PASSWD AUTHORITY 其它字段
RSK DEJLCP 3 任意填
计数器设置
计数器编号 说明
P 员工编号
C 人事变更记录编号
受教育程度代码
代码 说明
0 小学
1 初中
2 高中
3 职高
4 大专
5 大本
6 硕士
7 博士
8 博士后
人事变更代码
代码 说明
0 新员工加入
1 职务变动
2 辞退
部门信息表
ID NAME
CWC 财务处
JLS 经理室
MAT 仓库
PXC 培训处
RSC 人事处
SJC 设计处
职务代码表
CODE DESCRIPTION
BMJ 部门经理
GCS 工程师
KJS 会计师
MIS 秘书
PYG 普通员工
ZGC 总工程师
ZJL 总经理
五、各个功能模块的创建     在本程序中,将使用不支持文档/视图体系(Document/View architecture)的多文档界面的结构来开发数据库管理程序。MDI结构包括一个主框架窗口和若干个子框架窗口,子框架窗口可包含文档类和相关的视类,如果使用文档类,MDI文档模板类CmultiDocTemplate将为文档类和视类之间提供方便的联系,可简化编程的工作量。在本程序中不使用文档类,因此没有必要创建文档模板类的对象,此外程序中还创建了自己的视类以实现相关功能。MDI界面可以方便地在各个子窗口之间切换。 1.生成程序框架     在这里,用AppWizard生成程序框架,且手工加入数据库支持。在MFC AppWizard-Step1中选择Multiple document项,并去掉Document/View architecture support?选项。其余均采用缺省配置。 这样生成的程序中包含CTestApp(设应用程序名为Test)、CMainFrameCChildFrameCChildViewCAboutDlg五个类。由于子框架类CChildFrame中自动创建CchildView类,而此类并非我们所需,因此在程序中我们将不用CChildFrame CChildView类,而创建自己的子框架和视类。用ClassWizard创建一个新的子框架类CTheChildFrame,基类为CMDIChildWnd,程序中将用此子框架类包含视类,因程序的功能主要在视类中实现,故无需修改缺省创建的CTheChildFrame类。    本程序数据库的操作是通过MFCODBC类实现的。在操作系统“控制面板”里的“ODBC数据源”中添加一个“Microsoft Access Driver(*.mdb)的用户数据源,名称为“Misdb”。为了使用ODBC类,需要在stdafx.h中加入#include “afxdb.h”一行。因本程序只需要连接一个数据库,所以定义了一个CDatabase 型的全局变量db,一次性地打开和关闭数据库,方便程序的编写。 2. 主框架窗口设计 1)菜单的创建    Visual C++6.0的菜单编辑器(Menu Editor)可以很方便地创建菜单。在菜单编辑器中打开的设计窗口如下图所示。 人事管理系统人事管理系统      AppWizard创建的程序缺省有两个菜单:IDR_MAINFRAME为主框架窗口所用,IDR_TESTTYPE(设应用程序名为Test)为子框架窗口所用。因本程序中没有用缺省的子框架,所以将IDR_TESTTYPE菜单删去,同时重新编辑IDR_MAINFRAME菜单,菜单属性设置如下表:
菜单栏 菜单项 属性 取值(说明)
系统   Caption 系统(&S)
  连接 ID ID_SYSTEM_CONNECT
  Caption 连接(&C) /t F2
  Prompt 连接到服务器
  断开连接 ID ID_SYSTEM_DISCONNECT
  断开连接 Caption 断开连接(&D) /t F3
  Prompt 断开当前连接
  分割线   选中SEPARATOR属性
  退出 ID ID_APP_EXIT
  Caption 退出(&X)/tCtrl+Q
  Prompt 关闭整个应用程序
人事管理   Caption 人事管理(&M)
  增加新员工 ID ID_MANAGE_ADD
  Caption 增加新员工(&A)
  Prompt 输入新员工的信息
  人事变动 ID ID_MANAGE_CHANGE
  Caption 人事变动(&C)
  Prompt 记录员工的职位变动
  查询修改 ID ID_MANAGE_SEARCH
  Caption 查询修改(&S)
  Prompt 查询修改员工信息
窗口   Caption 窗口(&W)
  重叠排列 ID ID_WINDOW_CASCADE
  Caption 重叠排列(&C)
  Prompt 重叠排列窗口
  水平平铺 ID ID_WINDOW_TILE_HORZ
  Caption 水平平铺(&H)
  Prompt 水平排列窗口
  垂直平铺 ID ID_WINDOW_TILE_VERT
  Caption 垂直平铺(&V)
  Prompt 垂直排列窗口
  最小化所有窗口 ID ID_WINDOW_MINIALL
  Caption 最小化所有窗口(&M)
  Prompt 将所有窗口最小化
帮助   Caption 帮助(&H)
  关于 ID ID_APP_ABOUT
  Caption 关于 Test(&A)...
  Prompt 本程序的说明
    其中,“退出”、“重叠排列”、“水平平铺”、“垂直平铺”和“关于”菜单项用了系统的标准ID,其功能已由MFC实现,无需另外编程。 2)工具条的创建
次序 ID
1 ID_SYSTEM_CONNECT
2 ID_SYSTEM_DICONNECT
3 ID_MANAGE_ADD
4 ID_MANAGE_CHANGE
5 ID_MANAGE_SEARCH
6 ID_WINDOW_CASCADE
7 ID_WINDOW_TILE_HORZ
8 ID_WINDOW_TILE_VERT
9 ID_APP_ABOUT
人事管理系统Visual C++6.0的工具条编辑器(Toolbar Editor)可以很方便的编辑工具条。本程序创建的工具条如上图所示,其中工具条各按钮的ID分别对应相应的菜单项,按从左到右的次序对应的菜单项ID如上表所示。 3)增加一个状态栏指示器  在程序中加入一个状态栏指示器以显示登录状态。首先用增加一个资源IDID_INDICATOR_LOGIN,然后在MainFrm.cpp中找到indicators变量的定义处,添加ID至其列表,程序如下: static UINT indicators[] = {        ID_SEPARATOR,           // status line indicator        ID_INDICATOR_CAPS,        ID_INDICATOR_NUM,        ID_INDICATOR_SCRL,        ID_INDICATOR_LOGIN,     //登录状态 }; 4)程序相关代码  CMainFrame 中定义如下变量。 CTheChildFrame *m_pAdd, *m_pChange, *m_pSearch; // 指向三个功能子框架窗口        BOOL m_bLogin; // 登录状态        BOOL m_bItemAdd, m_bItemChange, m_bItemSearch; // 相应的菜单项及工具栏按钮是否可用    为了实现菜单项与工具条按钮的开放与禁用,需要通过ClassWizard加入相应的IDUPDATE_COMMAND_UI处理程序如下: void CMainFrame::OnUpdateSystemConnect(CCmdUI* pCmdUI) {        pCmdUI->Enable(!m_bLogin); // 根据登录状态改变菜单项和工具栏相应按钮状态 } void CMainFrame::OnUpdateSystemDisconnect(CCmdUI* pCmdUI) {        pCmdUI->Enable(m_bLogin); // 根据登录状态改变菜单项和工具栏相应按钮状态 } void CMainFrame::OnUpdateManagerAdd(CCmdUI* pCmdUI) {        pCmdUI->Enable(m_bItemAdd); // 根据m_bItemAdd改变菜单项和工具栏相应按钮状态 } void CMainFrame::OnUpdateManagerSearch(CCmdUI* pCmdUI) {        pCmdUI->Enable(m_bItemSearch); // 根据m_bItemSearch改变菜单项和工具栏相应按钮状态 } void CMainFrame::OnUpdateManagerChange(CCmdUI* pCmdUI) {        pCmdUI->Enable(m_bItemChange); // 根据m_bItemChange改变菜单项和工具栏相应按钮状态 } CMainFrame类的构造函数中需要初始化一些变量。 CMainFrame::CMainFrame() {        m_bLogin=FALSE;        m_bItemAdd=FALSE;        m_bItemChange=FALSE;        m_bItemSearch=FALSE;        m_pAdd=m_pChange=m_pSearch=NULL; } 3.加密类的创建 在本程序中,为了保证数据库的安全,多处使用了加密算法。加密类创建的目的就是为了方便在应用程序中引用加密过程,加密类名为CCrypt,在文件Crypt.h中声明两个静态函数: public:        static CString Encrypt(CString S, WORD Key); // 加密函数        static CString Decrypt(CString S, WORD Key); // 解密函数 类的实现代码如下: // 常量 #define C1 52845 #define C2 22719 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCrypt::CCrypt() { } CCrypt::~CCrypt() { } CString CCrypt::Encrypt(CString S, WORD Key) // 加密函数 {        CString Result,str;        int i,j;        Result=S; // 初始化结果字符串        for(i=0; i<S.GetLength(); i++) // 依次对字符串中各字符进行操作        {               Result.SetAt(i, S.GetAt(i)^(Key>>8)); // 将密钥移位后与字符异或               Key = ((BYTE)Result.GetAt(i)+Key)*C1+C2; // 产生下一个密钥        }        S=Result; // 保存结果        Result.Empty(); // 清除结果        for(i=0; i<S.GetLength(); i++) // 对加密结果进行转换        {               j=(BYTE)S.GetAt(i); // 提取字符               // 将字符转换为两个字母保存               str="12"; // 设置str长度为2               str.SetAt(0, 65+j/26);               str.SetAt(1, 65+j%26);               Result += str;        }        return Result; } CString CCrypt::Decrypt(CString S, WORD Key) // 解密函数 {        CString Result,str;        int i,j;        Result.Empty(); // 清除结果        for(i=0; i < S.GetLength()/2; i++) // 将字符串两个字母一组进行处理        {               j = ((BYTE)S.GetAt(2*i)-65)*26;               j += (BYTE)S.GetAt(2*i+1)-65;               str="1"; // 设置str长度为1               str.SetAt(0, j);               Result+=str; // 追加字符,还原字符串        }        S=Result; // 保存中间结果        for(i=0; i<S.GetLength(); i++) // 依次对字符串中各字符进行操作        {               Result.SetAt(i, (BYTE)S.GetAt(i)^(Key>>8)); // 将密钥移位后与字符异或               Key = ((BYTE)S.GetAt(i)+Key)*C1+C2; // 产生下一个密钥        }        return Result; } 4. 登录对话框的创建    登录对话框如下图所示,包括一个Combo Box、两个Edit Box和两个ButtonCombo Box中输人事管理系统入缺省ODBC数据源名称“MISDB”。登录和取消按钮的ID分别设置为IDOKIDCANCEL,即系统默认IDIDCANCEL采用系统缺省的处理,不做另外编程。IDOK需另外编程以登录数据库。为了改变标题“登录人事管理系统”的字体大小,需要改变其IDID_STATIC_LOGINTEXT,为对话框加入一个由CDialog类继承的CLoginDlg类封装的窗体资源,然后用Class Wizard为所需控件加入成员变量。为CLoginDlg类加入一个CFont类的成员变量m_font
控件类型 ID 成员变量 说明
Combo Box IDC_CMD_DSN m_strDSN ODBC数据源
Edit Box IDC_EDT_USER m_strUser 用户名
Edit Box IDC_EDT_PASSWD m_strPasswd 密码
CLoginDlg类需要用到加密类,因此需要在cpp文件开头加入以下行:#include “Crypt.h”。另外,为了使用全局数据库变量db,需要在cpp文件开头加入以下语句:extern CDatabase db; 然后在OnInitialDialog( )函数中作如下处理: BOOL CLoginDlg::OnInitDialog() {               CDialog::OnInitDialog();        // TODO: Add extra initialization here        // 改变"登录人事管理系统"字体大小        LOGFONT LogFont;        GetFont()->GetLogFont(&LogFont);        LogFont.lfHeight+=LogFont.lfHeight/2;        LogFont.lfWidth+=LogFont.lfWidth/2;        m_font.CreateFontIndirect(&LogFont);        GetDlgItem(IDC_STATIC_LOGINTEXT)->SetFont(&m_font);        return TRUE; // return TRUE unless you set the focus to a control                      // EXCEPTION: OCX Property Pages should return FALSE } “登录”按钮的处理代码如下: void CLoginDlg::OnOK() {        BOOL bLogin=FALSE;        CString strPasswd, strAuthority;        UpdateData(); // 更新数据变量        if(!db.Open(m_strDSN)) return; // 连接数据库        CRecordset rs(&db);        rs.Open(CRecordset::forwardOnly,               "select PASSWD, AUTHORITY from PERSON where ID='"+m_strUser+"'");        if(!rs.IsEOF())        {               rs.GetFieldValue("PASSWD", strPasswd);               rs.GetFieldValue("AUTHORITY", strAuthority);               if(strPasswd == CCrypt::Encrypt(m_strPasswd, 123) &&                      strAuthority == "3")               {                      bLogin=TRUE; // 已连接               }               else                      MessageBox("请重新输入密码。/n注意大小写!","密码错误");        }        else        {               MessageBox("请确认用户名大小写是否正确!","无此用户");        }        rs.Close();        if(bLogin) EndDialog(IDOK);        else db.Close(); // 关闭数据库 } CMainFrame类需要用到CLoginDlg类,因此需要在cpp文件开头加入以下行: #include "LoginDlg.h"。另外,为了使用全局数据库变量db,需要在cpp文件开头加入以下语句: extern CDatabase db; CMainFrame中,映射菜单上“连接”的COMMAND事件处理代码如下: void CMainFrame::OnSystemConnect() {        // TODO: Add your command handler code here        CLoginDlg dlg;        if(dlg.DoModal()==IDOK)        {               m_bLogin=TRUE;               m_bItemAdd=TRUE;            m_bItemChange=TRUE;            m_bItemSearch=TRUE;               m_wndStatusBar.SetPaneText(1,"已登录到数据库:"+dlg.m_strDSN);        } } void CMainFrame::OnSystemDisconnect() { 人事管理系统       // TODO: Add your command handler code here        db.Close();        if(m_pAdd)m_pAdd->DestroyWindow();        if(m_pChange)m_pChange->DestroyWindow();        if(m_pSearch)m_pSearch->DestroyWindow();        m_bLogin=FALSE;        m_bItemAdd=FALSE;        m_bItemChange=FALSE;        m_bItemSearch=FALSE;        m_wndStatusBar.SetPaneText(1,"尚未登录数据库!请按F2登录"); } 5. 增加新员工视类的创建 首先加入一个新的窗体资源,在Insert Resource对话框中选择DialogIDD_FORMVIEW项(注意:在对话框的属性项里应该把语言选择为中文)。窗体创建后,在其上添加所需控件,最后的布局如右图所示。创建好资源后,为窗体加入一个由CFormView类继承的CAddView封装此窗体资源,然后用Class Wizard为所需控件加入成员变量。
控件类型 ID 成员变量 说明
Edit Box IDC_ADD_EDT_ID m_strID 员工号
Edit Box IDC_ADD_EDT_PASSWD m_strPasswd 密码
Edit Box IDC_ADD_EDT_NAME m_strName 姓名
Radio Button IDC_ADD_RADIO_MALE 性别-
Radio Button IDC_ADD_RADIO_FEMALE 性别-
Edit Box IDC_ADD_EDT_BIRTHDAY m_strBirthday 生日
Combo Box IDC_ADD_CMB_DEPARTMENT m_strDepartment m_cDepartment 部门
Combo Box IDC_ADD_CMB_JOB m_strJob m_cJob 职务
Combo Box IDC_ADD_CMB_EDULEVEL m_strEdulevel m_cEdulevel 受教育水平
Edit Box IDC_ADD_EDT_SPECIALTY m_strSpecialty 专业
Edit Box IDC_ADD_EDT_ADDRESS m_strAddress 地址
Edit Box IDC_ADD_EDT_TEL m_strTel 电话
Edit Box IDC_ADD_EDT_EMAIL m_strEmail E-mail
Edit Box IDC_ADD_EDT_MEMO m_strMemo 备注(StyleMultiline)
Button IDC_ADD_BTN_ADD “增加”按钮
 CAddView类需要用到主框架窗口类和加密类,因此需要在cpp文件开头加入以下两行: #include “Crypt.h” #include “MainFrm.h” 另外,为了使用全局数据库变量db,需要在cpp文件开头加入以下语句:extern CDatabase db; 每次增加新成员时需要先做一些初始化工作,如设置自动生成员工号和密码等,用ClassView加入初始化函数Init(),代码如下: void CAddView::Init() {  //清空成员变量        m_strID = _T("");        m_strPasswd = _T("");        m_strName = _T("");        m_strBirthday = _T("");        m_strDepartment = _T("");        m_cDepartment.SetCurSel(-1);        m_strJob = _T("");        m_cJob.SetCurSel(-1);        m_strEdulevel = _T("");        m_cEdulevel.SetCurSel(-1);        m_strSpecialty = _T("");        m_strAddress = _T("");        m_strTel = _T("");        m_strEmail = _T("");        m_strMemo = _T("");     //生成员工号        CString str;        int counter; // 用于计数        CRecordset rs(&db); // 数据集        rs.Open(CRecordset::forwardOnly,               "select COUNTER_VALUE from COUNTER where ID='P'");        rs.GetFieldValue("COUNTER_VALUE", str);        sscanf(str, "%d", &counter); // 获取计数值        rs.Close();        str.Format("P%05d", counter); // 产生标准格式的编号        m_strID=str; // 自动产生员工号        m_strPasswd=str; // 默认密码为员工号        // 设置缺省性别为男        ((CButton*)GetDlgItem(IDC_ADD_RADIO_MALE))->SetCheck(TRUE);        UpdateData(FALSE); // 更新界面数据 }    重载CFormViewOnInitialUpdate函数如下,其中调整窗口外观,并设置几个ComboBox中的值: void CAddView::OnInitialUpdate() {        CFormView::OnInitialUpdate();        // TODO: Add your specialized code here and/or call the base class        // 使框架窗口大小与视图匹配        GetParentFrame()->RecalcLayout();     ResizeParentToFit(FALSE);        GetParentFrame()->SetWindowText("增加新员工"); // 设置标题        CRecordset rs(&db); // 数据集        CString str;        // 设置部门下拉框所取的值为DEPARTMENT表中的值        rs.Open(CRecordset::forwardOnly, "select NAME from DEPARTMENT");        while(!rs.IsEOF())        {               rs.GetFieldValue("NAME", str);               m_cDepartment.AddString(str);               rs.MoveNext();        }        rs.Close();        // 设置职务下拉框所取的值为JOB表中的值        rs.Open(CRecordset::forwardOnly, "select DESCRIPTION from JOB");        while(!rs.IsEOF())        {               rs.GetFieldValue("DESCRIPTION", str);               m_cJob.AddString(str);               rs.MoveNext();        }        rs.Close();        // 设置受教育水平下拉框所取的值为EDU_LEVEL表中的值        rs.Open(CRecordset::forwardOnly, "select DESCRIPTION from EDU_LEVEL");        while(!rs.IsEOF())        {               rs.GetFieldValue("DESCRIPTION", str);               m_cEdulevel.AddString(str);               rs.MoveNext();        }        rs.Close();        Init(); // 调用初始化函数 } “增加”按钮的COMMAND消息处理如下,其中完成了记录的添加。 void CAddView::OnAddBtnAdd() {        // TODO: Add your control notification handler code here        CString str,strSQL;        int counter; // 用于计数        CRecordset rs(&db); // 数据集        UpdateData(); // 更新数据        if(m_strName.IsEmpty()) // 姓名为空则返回        {               AfxMessageBox("姓名不能为空!");               return;        } // 累加员工编号计数器        rs.Open(CRecordset::forwardOnly,               "select COUNTER_VALUE from COUNTER where ID='P'");        rs.GetFieldValue("COUNTER_VALUE", str);        sscanf(str, "%d", &counter); // 获取计数值        rs.Close(); // 关闭数据集        counter++;    // 计数值加1        str.Format("%d", counter); // 转换为字符串        strSQL="update COUNTER set COUNTER_VALUE=" + str + " where ID='P'"; // 设置SQL语句        db.ExecuteSQL(strSQL); // 执行 // 增加员工个人信息记录        CString strPasswd,strSex,strDepID,strJobID,strEduID;        // 判断生日是否为空        if(m_strBirthday.IsEmpty()) m_strBirthday="1900-1-1"; // 缺省值        // 加密密码        strPasswd=CCrypt::Encrypt(m_strPasswd, 123);        // 判断性别        if(((CButton*)GetDlgItem(IDC_ADD_RADIO_MALE))->GetCheck()) strSex="M";        else strSex="F";        // 得到部门ID        rs.Open(CRecordset::forwardOnly,               "select ID from DEPARTMENT where NAME='" + m_strDepartment +"'");        rs.GetFieldValue("ID", strDepID);        rs.Close();        // 得到职务代码        rs.Open(CRecordset::forwardOnly,               "select CODE from JOB where DESCRIPTION='" + m_strJob +"'");        rs.GetFieldValue("CODE", strJobID);        rs.Close();        // 得到受教育水平代码        rs.Open(CRecordset::forwardOnly,               "select CODE from EDU_LEVEL where DESCRIPTION='" + m_strEdulevel +"'");        rs.GetFieldValue("CODE", strEduID);        rs.Close();        // SQL语句        strSQL="insert into PERSON(ID,PASSWD,NAME,SEX,/               BIRTHDAY,DEPARTMENT,JOB,EDU_LEVEL,SPECIALTY,/               ADDRESS,TEL,EMAIL,REMARK) /               values('"               + m_strID + "','" // ID               + strPasswd + "','" // PASSWD               + m_strName + "','" // NAME               + strSex + "','" // SEX               + m_strBirthday + "','" // BIRTHDAY               + strDepID + "','" // DEPARTMENT               + strJobID + "','" // JOB               + strEduID + "','" // EDU_LEVEL               + m_strSpecialty + "','" // SPECIALTY               + m_strAddress + "','" // ADDRESS               + m_strTel + "','" // TEL               + m_strEmail + "','" // EMAIL               + m_strMemo + "')"; // REMARK        db.ExecuteSQL(strSQL); // 执行 // 获取人事变动记录号并累加        rs.Open(CRecordset::forwardOnly,               "select COUNTER_VALUE from COUNTER where ID='C'");        rs.GetFieldValue("COUNTER_VALUE", str);        sscanf(str, "%d", &counter); // 获取计数值        rs.Close(); // 关闭数据集        counter++;    //计数值加1        str.Format("%d", counter); // 转换为字符串        strSQL="update COUNTER set COUNTER_VALUE=" + str + " where ID='C'"; // 设置SQL语句        db.ExecuteSQL(strSQL); // 执行 // 追加人事变动记录        str.Format("%d",counter); // 计数值转换为字符串        CTime time=CTime::GetCurrentTime();        CString strNow=time.Format("%Y-%m-%d %H:%M:%S");        // SQL语句        strSQL="insert into PERSONNEL(ID,PERSON,CHANGE,/               RECORD_TIME,DESCRIPTION)/               values("               + str + ",'" // ID               + m_strID + "','" // PERSON               + "0" + "','" // CHANGE - 加入公司代码               + strNow + "','" // RECORD_TIME               + "加入公司')"; // DESCRIPTION        db.ExecuteSQL(strSQL); // 重新初始化窗口        Init(); } 窗口关闭时,需要恢复菜单项和工具条按钮状态并清空相应的子框架窗口指针。 void CAddView::OnDestroy() {     CFormView::OnDestroy();               ((CMainFrame*)AfxGetMainWnd())->m_bItemAdd=TRUE; // 开放"增加新员工"功能        ((CMainFrame*)AfxGetMainWnd())->m_pAdd=NULL; // 清空窗口指针 } CMainFrame中,映射菜单上“增加新员工”的COMMAND事件处理代码如下: void CMainFrame::OnManagerAdd() {        // 创建子框架和视        m_pAdd=new CTheChildFrame();        CCreateContext context;        context.m_pNewViewClass=RUNTIME_CLASS(CAddView);        if(!m_pAdd->LoadFrame(IDR_MAINFRAME,               WS_OVERLAPPEDWINDOW|FWS_PREFIXTITLE,this,&context))return;        m_pAdd->InitialUpdateFrame(NULL,TRUE);        m_bItemAdd=FALSE;          //禁止“增加新员工”功能 } 6. 人事变动视类的创建    首先加入一个新的窗体资源,同样在Insert Resource对话框中选择DialogIDD_FORMVIEW项。窗体资源创建后,在其上添加所需控件,最后的布局如下图所示。创建好资源后,为窗体加入一个由CFormView类继承的CChangeView封装此窗体资源,然后用Class Wizard为所需控件加入成员变量。
控件类型 ID 成员变量 说明
Edit Box IDC_CHANGE_EDT_ID m_strID 员工号
Radio Button IDC_CHANGE_RADIO_JOB 职务变更
Radio Button IDC_CHANGE_RADIO_FIRE 辞职退休
Date Time Picker IDC_CHANGE_DATETIMEPICKER m_Time 时间
Edit Box IDC_CHANGE_EDT_NAME m_strName 姓名
Combo Box IDC_CHANGE_CMB_DEPARTMENT m_cDepartment 部门
Combo Box IDC_CHANGE_CMB_JOB m_cJob 职务
Edit Box IDC_CHANGE_EDT_DESCRIPTION m_strDescription 具体描述
Button IDC_CHANGE_BTN_CHANGE “修改”按钮
人事管理系统CChangeView中需要加入如下语句包含主框架窗口类: #include “MainFrm.h” 同样,本类也需要加入以下语句引用全局变量db extern CDatabase db; 初始化函数代码如下: void CChangeView::Init() {    // 初始化成员变量        m_strID = _T("");        m_Time = CTime::GetCurrentTime();        m_strName = _T("");        m_strDescription = _T("");        m_cDepartment.SetCurSel(-1);        m_cJob.SetCurSel(-1);        // 设置缺省变动情况为职务变更 ((CButton*)GetDlgItem(IDC_CHANGE_RADIO_JOB))->SetCheck(TRUE);        UpdateData(FALSE); // 更新界面数据 } 重载CFormView类的OnInitialUpdate()函数如下: void CChangeView::OnInitialUpdate() {  CFormView::OnInitialUpdate();               // 使框架窗口大小与视图匹配        GetParentFrame()->RecalcLayout();     ResizeParentToFit(FALSE);        GetParentFrame()->SetWindowText("人事变动"); // 设置标题        CRecordset rs(&db); // 数据集        CString str;        // 设置部门下拉框所取的值为DEPARTMENT表中的值        rs.Open(CRecordset::forwardOnly, "select NAME from DEPARTMENT");        while(!rs.IsEOF())        {               rs.GetFieldValue("NAME", str);               m_cDepartment.AddString(str);               rs.MoveNext();        }        rs.Close();        // 设置职务下拉框所取的值为JOB表中的值        rs.Open(CRecordset::forwardOnly, "select DESCRIPTION from JOB");        while(!rs.IsEOF())        {               rs.GetFieldValue("DESCRIPTION", str);               m_cJob.AddString(str);               rs.MoveNext();        }        rs.Close();        Init(); // 调用初始化函数 } 当员工号编辑框中输入改变时,需要检索员工信息以显示。用Class Wizard加入处理IDC_CHANGE_EDT_IDEN_CHANGE消息的函数,代码如下: void CChangeView::OnChangeChangeEdtId() {        UpdateData(); // 更新数据        CRecordset rs(&db);        CString strDep,strJob;        rs.Open(CRecordset::forwardOnly,               "select NAME,DEPARTMENT,JOB from PERSON where ID='" + m_strID + "'");        if(!rs.IsEOF()) // 非空则获取员工信息        {               rs.GetFieldValue("NAME", m_strName); // 名字               rs.GetFieldValue("DEPARTMENT", strDep); // 部门编号               rs.GetFieldValue("JOB", strJob); // 职务代码               rs.Close();               if(!strDep.IsEmpty())               {                      rs.Open(CRecordset::forwardOnly,                             "select NAME from DEPARTMENT where ID='" + strDep + "'");                      rs.GetFieldValue("NAME", strDep); // 部门名称                      rs.Close();               }               if(!strJob.IsEmpty())               {                      rs.Open(CRecordset::forwardOnly,                             "select DESCRIPTION from JOB where CODE='" + strJob + "'");                      rs.GetFieldValue("DESCRIPTION", strJob); // 职务名称                      rs.Close();               }               UpdateData(FALSE); // 更新数据               m_cDepartment.SelectString(-1,strDep);               m_cJob.SelectString(-1,strJob);               m_bExist=TRUE; // 该员工存在        }        else // 否则清空员工信息        {               rs.Close();               m_strName.Empty();               m_cDepartment.SetCurSel(-1);               m_cJob.SetCurSel(-1);               UpdateData(FALSE); // 更新数据               m_bExist=FALSE; // 该员工不存在        } }  点击“修改”按钮时,添加人事变动记录。 void CChangeView::OnChangeBtnChange() { CRecordset rs(&db);        CString str,strSQL;        int counter;        if(!m_bExist) // 该员工号不存在        {               MessageBox("请确认员工号!","输入错误");               return;        }        UpdateData(); // 更新数据 // 获取人事变动记录号并累加        rs.Open(CRecordset::forwardOnly,               "select COUNTER_VALUE from COUNTER where ID='C'");        rs.GetFieldValue("COUNTER_VALUE", str);        sscanf(str, "%d", &counter); // 获取计数值        rs.Close(); // 关闭数据集        counter++; // 计数器加1        str.Format("%d", counter); // 转换为字符串        strSQL="update COUNTER set COUNTER_VALUE=" + str + " where ID='C'"; // 设置SQL语句        db.ExecuteSQL(strSQL); // 执行 // 更新员工信息        CString strDepID,strJobID,strState,strChange;        // 得到部门ID        m_cDepartment.GetWindowText(str);        rs.Open(CRecordset::forwardOnly,               "select ID from DEPARTMENT where NAME='" + str +"'");        rs.GetFieldValue("ID", strDepID);        rs.Close();        // 得到职务代码        m_cJob.GetWindowText(str);        rs.Open(CRecordset::forwardOnly,               "select CODE from JOB where DESCRIPTION='" + str +"'");        rs.GetFieldValue("CODE", strJobID);        rs.Close();        if(((CButton*)GetDlgItem(IDC_CHANGE_RADIO_FIRE))->GetCheck())        {               strState="F";               strChange="2"; // 辞退        }        else        {               strState="T";               strChange="1"; // 职务变动        }        strSQL="update PERSON set STATE='" + strState + "',"               + "DEPARTMENT='" + strDepID + "',"               + "JOB='" + strJobID + "'";        db.ExecuteSQL(strSQL); // 执行 // 追加人事变动记录        str.Format("%d",counter); // 计数值转换为字符串        CString strNow=m_Time.Format("%Y-%m-%d %H:%M:%S");        // SQL语句        strSQL="insert into PERSONNEL(ID,PERSON,CHANGE,RECORD_TIME,DESCRIPTION)/               values("               + str + ",'" // ID               + m_strID + "','" // PERSON               + strChange + "','" // CHANGE               + strNow + "','" // RECORD_TIME               + m_strDescription + "')"; // DESCRIPTION        db.ExecuteSQL(strSQL); // 重新初始化窗口        Init();             }    窗口关闭时需要进行一定的状态修改,处理WM_DESTORY消息。 void CChangeView::OnDestroy() {    CFormView::OnDestroy();               ((CMainFrame*)AfxGetMainWnd())->m_bItemChange=TRUE; // 开放"人事变动"功能"        ((CMainFrame*)AfxGetMainWnd())->m_pChange=NULL; // 清空窗口指针      } CMainFrame中,映射菜单上“人事变动”的COMMAND事件处理代码如下: void CMainFrame::OnManagerChange() {        // TODO: Add your command handler code here        m_pChange=new CTheChildFrame();        CCreateContext context;        context.m_pNewViewClass=RUNTIME_CLASS(CChangeView);        if(!m_pChange->LoadFrame(IDR_MAINFRAME,               WS_OVERLAPPEDWINDOW|FWS_PREFIXTITLE,this,&context))return;        m_pChange->InitialUpdateFrame(NULL,TRUE);        m_bItemChange=FALSE;    //禁止“人事变动”功能 }   7. 员工信息查询修改视类的创建    首先加入一个新的窗体资源,同样在Insert Resource对话框中选择DialogIDD_FORMVIEW项。窗体最后的布局如下图。创建好资源后,为窗体加入一个由CFormView类继承的CSearchView类封装此窗体资源,然后用Class Wizard为所需控件加入成员变量。
控件类型 ID 成员变量 说明
Edit Box IDC_SEARCH_EDT_ID m_strID 员工号
Combo Box IDC_SEARCH_CMB_DEPARTMENT m_cDepartment 部门
Combo Box IDC_SEARCH_CMB_JOB m_cJob 职务
Combo Box IDC_SEARCH_CMB_EDULEVEL m_cEdulevel 受教育水平
Edit Box IDC_SEARCH_EDT_SPECIALTY m_strSpecialty 专业
Edit Box IDC_SEARCH_EDT_MEMO m_strMemo 备注
Edit Box IDC_SEARCH_EDT_PASSWD m_strPasswd 密码
Button IDC_SEARCH_BTN_CHGPASSWD “修改密码”按钮
Radio Button IDC_SEARCH_RADIO_MALE 性别-
Radio Button IDC_SEARCH_RADIO_FEMALE 性别-
Edit Box IDC_SEARCH_EDT_NAME m_strName 姓名
Edit Box IDC_SEARCH_EDT_BIRTHDAY m_strBirthday 生日
Edit Box IDC_SEARCH_EDT_ADDRESS m_strAddress 住址
Edit Box IDC_SEARCH_EDT_TEL m_strTel 电话
Edit Box IDC_SEARCH_EDT_EMAIL m_strEmail 电子邮件
Button IDC_SEARCH_BTN_CHANGE “修改员工信息”按钮
List Control IDC_SEARCH_LIST m_cList 人事变动表
CSearchView中需要加入如下语句包含主框架窗口类和加密类: 人事管理系统#include “MainFrm.h” #include “Crypt.h” 同样,本类也需要加入以下语句引用全局变量db extern CDatabase db; 初始化函数代码如下: void CSearchView::Init() {    //清空成员变量        m_strID = _T("");        m_strSpecialty = _T("");        m_strMemo = _T("");        m_strPasswd = _T("");        m_strName = _T("");        m_strBirthday = _T("");        m_strAddress = _T("");        m_strTel = _T("");        m_strEmail = _T("");               UpdateData(FALSE);    // 更新界面数据   } 重载CFormViewOnInitialUpdate函数如下: void CSearchView::OnInitialUpdate() {     CFormView::OnInitialUpdate();               // m_cList加入网格        DWORD style=m_cList.GetExtendedStyle();        m_cList.SetExtendedStyle(style|LVS_EX_GRIDLINES);        // 使框架窗口大小与视图匹配        GetParentFrame()->RecalcLayout();     ResizeParentToFit(FALSE);        GetParentFrame()->SetWindowText("员工信息查询修改"); // 设置标题        CRecordset rs(&db); // 数据集        CString str;        // 设置部门下拉框所取的值为DEPARTMENT表中的值        rs.Open(CRecordset::forwardOnly, "select NAME from DEPARTMENT");        while(!rs.IsEOF())        {               rs.GetFieldValue("NAME", str);               m_cDepartment.AddString(str);               rs.MoveNext();        }        rs.Close();        // 设置职务下拉框所取的值为JOB表中的值        rs.Open(CRecordset::forwardOnly, "select DESCRIPTION from JOB");        while(!rs.IsEOF())        {               rs.GetFieldValue("DESCRIPTION", str);               m_cJob.AddString(str);               rs.MoveNext();        }        rs.Close();        // 设置受教育水平下拉框所取的值为EDU_LEVEL表中的值        rs.Open(CRecordset::forwardOnly, "select DESCRIPTION from EDU_LEVEL");        while(!rs.IsEOF())        {               rs.GetFieldValue("DESCRIPTION", str);               m_cEdulevel.AddString(str);               rs.MoveNext();        }        rs.Close();        // 添加List控件的列        m_cList.InsertColumn(0, "记录编号", LVCFMT_LEFT, 100);        m_cList.InsertColumn(1, "记录时间", LVCFMT_LEFT, 100);        m_cList.InsertColumn(2, "具体描述", LVCFMT_LEFT, 215);        Init(); // 调用初始化函数 } 当“员工号”编辑框中输入员工号时,执行以下代码: void CSearchView::OnChangeSearchEdtId() { UpdateData(); // 更新数据        m_cList.DeleteAllItems(); // 清空列表框        CRecordset rs(&db);        CString strDep,strJob,strEdulevel,strSex;        rs.Open(CRecordset::forwardOnly,               "select * from PERSON where ID='" + m_strID + "'");        if(!rs.IsEOF()) // 非空则获取员工信息        {               rs.GetFieldValue("NAME", m_strName); // 名字               rs.GetFieldValue("DEPARTMENT", strDep); // 部门编号               rs.GetFieldValue("JOB", strJob); // 职务代码               rs.GetFieldValue("EDU_LEVEL", strEdulevel); // 受教育水平               rs.GetFieldValue("SPECIALTY", m_strSpecialty); // 专业               rs.GetFieldValue("REMARK", m_strMemo); // 备注               rs.GetFieldValue("BIRTHDAY", m_strBirthday); // 生日               m_strBirthday=m_strBirthday.Left(10); // 取日期部分               rs.GetFieldValue("ADDRESS", m_strAddress); // 住址               rs.GetFieldValue("TEL", m_strTel); // 电话               rs.GetFieldValue("EMAIL", m_strEmail); // Email               rs.GetFieldValue("SEX", strSex); // 性别               rs.Close();               // 得到部门名称               if(!strDep.IsEmpty())               {                      rs.Open(CRecordset::forwardOnly,                             "select NAME from DEPARTMENT where ID='" + strDep + "'");                      rs.GetFieldValue("NAME", strDep); // 部门名称                      rs.Close();               }               // 得到职务名称               if(!strJob.IsEmpty())               {                      rs.Open(CRecordset::forwardOnly,                             "select DESCRIPTION from JOB where CODE='" + strJob + "'");                      rs.GetFieldValue("DESCRIPTION", strJob); // 职务名称                      rs.Close();               }               // 得到教育水平描述               if(!strEdulevel.IsEmpty())               {                      rs.Open(CRecordset::forwardOnly,                             "select DESCRIPTION from EDU_LEVEL where CODE='"                             + strEdulevel + "'");                      rs.GetFieldValue("DESCRIPTION", strEdulevel); // 教育水平描述                      rs.Close();               }               // 设置性别选框               if(strSex=="M") ((CButton*)GetDlgItem(IDC_SEARCH_RADIO_MALE))->SetCheck(TRUE);               else ((CButton*)GetDlgItem(IDC_SEARCH_RADIO_FEMALE))                      ->SetCheck(TRUE);               UpdateData(FALSE); // 更新数据               m_cDepartment.SelectString(-1,strDep);               m_cJob.SelectString(-1,strJob);               m_cEdulevel.SelectString(-1,strEdulevel);               // 更新列表框数据               int i=0;               CString str1,str2,str3;               rs.Open(CRecordset::forwardOnly,                      "select ID,RECORD_TIME,DESCRIPTION from PERSONNEL/                      where PERSON='" + m_strID + "'");               while(!rs.IsEOF())               {                      // 得到数据                      rs.GetFieldValue("ID", str1);                      rs.GetFieldValue("RECORD_TIME", str2);                      str2=str2.Left(10); // 只取日期                      rs.GetFieldValue("DESCRIPTION", str3);                      // 加入List                      m_cList.InsertItem(i,"");                      m_cList.SetItemText(i, 0, str1);                      m_cList.SetItemText(i, 1, str2);                      m_cList.SetItemText(i, 2, str3);                      i++;                      rs.MoveNext(); // 移动记录               }               rs.Close();               m_bExist=TRUE; // 该员工存在        }        else // 否则清空员工信息        {               rs.Close();               m_strSpecialty = _T("");               m_strMemo = _T("");               m_strPasswd = _T("");               m_strName = _T("");               m_strBirthday = _T("");               m_strAddress = _T("");               m_strTel = _T("");               m_strEmail = _T("");               m_cDepartment.SetCurSel(-1);               m_cJob.SetCurSel(-1);               m_cEdulevel.SetCurSel(-1);               UpdateData(FALSE); // 更新数据               ((CButton*)GetDlgItem(IDC_SEARCH_RADIO_MALE))->SetCheck(FALSE);               ((CButton*)GetDlgItem(IDC_SEARCH_RADIO_FEMALE))->SetCheck(FALSE);               m_bExist=FALSE; // 该员工不存在        } } 单击“修改密码”按钮时执行以下代码: void CSearchView::OnSearchBtnChgpasswd() {  if(!m_bExist) // 该员工号不存在        {               AfxMessageBox("该员工号不存在");               return;        }        UpdateData(); // 更新数据        CString str,strSQL;        str=CCrypt::Encrypt(m_strPasswd, 123); // 加密        strSQL="update PERSON set PASSWD='" + str + "'"; // SQL语句        db.ExecuteSQL(strSQL); // 执行           } 单击“修改员工信息”按钮时执行以下代码: void CSearchView::OnSearchBtnChange() { if(!m_bExist) // 该员工号不存在        {               AfxMessageBox("该员工号不存在");               return;        }        UpdateData(); // 更新数据 // 修改员工个人信息记录        CString str,strSex,strDepID,strJobID,strEduID,strSQL;        CRecordset rs(&db);        // 判断性别        if(((CButton*)GetDlgItem(IDC_SEARCH_RADIO_MALE))->GetCheck()) strSex="M";        else strSex="F";        // 得到部门ID        m_cDepartment.GetWindowText(str);        if(!str.IsEmpty()) // 不空        {               rs.Open(CRecordset::forwardOnly,                      "select ID from DEPARTMENT where NAME='" + str +"'");               rs.GetFieldValue("ID", strDepID);               rs.Close();        }            // 得到职务代码        m_cJob.GetWindowText(str);        if(!str.IsEmpty()) // 不空        {               rs.Open(CRecordset::forwardOnly,                      "select CODE from JOB where DESCRIPTION='" + str +"'");               rs.GetFieldValue("CODE", strJobID);               rs.Close();        }        // 得到受教育水平代码        m_cEdulevel.GetWindowText(str);        if(!str.IsEmpty()) // 不空        {               rs.Open(CRecordset::forwardOnly,                      "select CODE from EDU_LEVEL where DESCRIPTION='" + str +"'");               rs.GetFieldValue("CODE", strEduID);               rs.Close();        }        // SQL语句        strSQL="update PERSON set/               NAME='" + m_strName //NAME               + "',SEX='" + strSex // SEX               + "',BIRTHDAY='" + m_strBirthday // BIRTHDAY               + "',DEPARTMENT='" + strDepID // DEPARTMENT               + "',JOB='" + strJobID // JOB               + "',EDU_LEVEL='" + strEduID // EDU_LEVEL               + "',SPECIALTY='" + m_strSpecialty // SPECIALTY               + "',ADDRESS='" + m_strAddress // ADDRESS               + "',TEL='" + m_strTel // TEL               + "',EMAIL='" + m_strEmail // EMAIL               + "',REMARK='" + m_strMemo // REMARK               + "' where ID='" + m_strID + "'"; // 条件        db.ExecuteSQL(strSQL); // 执行           } 窗口关闭时需要进行一定的状态修改,处理WM_DESTORY消息。 void CSearchView::OnDestroy() {    CFormView::OnDestroy();               ((CMainFrame*)AfxGetMainWnd())->m_bItemSearch=TRUE; // 开放"人事变动"功能"        ((CMainFrame*)AfxGetMainWnd())->m_pSearch=NULL; // 清空窗口指针       } CMainFrame中,映射菜单上“查询修改”的COMMAND事件处理代码如下: void CMainFrame::OnManagerSearch() {        // TODO: Add your command handler code here        m_pSearch=new CTheChildFrame();        CCreateContext context;        context.m_pNewViewClass=RUNTIME_CLASS(CSearchView);        if(!m_pSearch->LoadFrame(IDR_MAINFRAME,               WS_OVERLAPPEDWINDOW|FWS_PREFIXTITLE,this,&context))return;        m_pSearch->InitialUpdateFrame(NULL,TRUE);        m_bItemSearch=FALSE; } CMainFrame中,映射菜单上“最小化所有窗口”的COMMAND事件处理代码如下: void CMainFrame::OnWindowMiniall() {        // 最小化所有窗口        if(m_pAdd)m_pAdd->ShowWindow(SW_MINIMIZE);        if(m_pChange)m_pChange->ShowWindow(SW_MINIMIZE);     if(m_pSearch)m_pSearch->ShowWindow(SW_MINIMIZE); } 在程序结束时需要关闭数据库,因此需要处理CMainFrameWM_DESTROY消息: void CMainFrame::OnDestroy() {        CMDIFrameWnd::OnDestroy();               // TODO: Add your message handler code here        if(db.IsOpen())db.Close(); } 8.系统的实现    本程序每个功能模块可以依次编译调试执行完成。最终,各视类和对话框设计完成并都通过调试正常后,启动程序,首先出现主框架窗口。但是由于没有登录服务器,大部分菜单项都是不可用的。只有“连接”、“关于”和“退出”菜单可选。    单击“连接”菜单和工具条相应按钮会弹出“登录”窗口,登录界面允许修改ODBC数据源名称,无需重新编译程序。    登录后,相关菜单会被激活。此时可以单击菜单或相应的工具条按钮来弹出相应的子框架窗口和视类。在MDI模式下,3个功能窗口可以同时被显示。    “增加新员工”子窗口中,员工号和密码会自动按顺序生成,并且不允许修改。“人事变动”和“员工信息查询修改”子窗口中,须先输入员工号,确认显示的信息后才可进行相关的修改。产生的3个窗体列在“窗口”菜单下。当鼠标在菜单项上移动时,状态栏中会自动显示菜单项的Prompt属性的内容。“窗口”菜单中的4项功能是标准的窗口排列功能。