• 597.00 KB
  • 2022-05-17 13:18:20 发布

精品毕业论文--考勤管理系统设计与数据库

  • 72页
  • 当前文档由用户上传发布,收益归属用户
  1. 1、本文档共5页,可阅读全部内容。
  2. 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
  3. 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
  4. 文档侵权举报电话:19940600175。
6969摘 要随着计算机的普及和计算机科学技术的飞速发展,人们开始越来越多地利用计算机解决实际问题。员工考勤管理是企业信息管理的重要部分面对大量的人事工资信息,采用人力处理将浪费大量的时间、人力和物力,且数据的准确性低。因此,开发一个界面友好,易于操作的员工考勤管理软件进行自动化处理变得十分重要,这正是本系统开发的目的和意义。本项目开发过程中,主要进行的工作是需求分析、概要设计、详细设计、项目应用的前期准备包括培训、硬件配置等。软件采用基本对话框界面,能满足中小型企业员工考勤管理的基本需要。本论文针对该软件的各个方面,开发过程中涉及到的技术和工具都分别进行了阐述。根据以上分析本系统主要模块如下:1登录窗口模块,2主窗口模块,3添加出勤记录模块,4加班记录模块,5请假记录模块,6出差记录模块,7月度出勤情况表模块。总之,本次设计工作是一次理论联系实际的过程。对我本人来说不仅是一次难得的学习机会,而且通过实践使我深刻地了解了这些抽象概念的实质,为我将来的工作奠定了扎实地基础。关键词:考勤、系统、信息69 AbstractAlongwithcomputerpopularizationandcomputersciencetechnologyrapiddevelopment,thepeoplestarttousethecomputersolutionactualproblemmoreandmoremany.Thestaffchecksattendancethemanagementistheenterpriseinformationmanagementimportantpartfacingthemassivehumanaffairswagesinformation,willusemanpowerprocessingtowastethemassivetime,themanpowerandthephysicalresource,alsothedataaccuracywillbelow.Therefore,developsacontactsurfacetobefriendly,easytooperatethestaffchecksattendancethemanagementsoftwaretocarryonautomatedprocessingtobecomeextremelyimportant,thisispreciselythissystemdevelopmentgoalandthesignificance.Inthisprojectperformancehistory,mainlycarriesontheworkisthedemandanalysis,theoutlinedesign,thedetaileddesign,theprojectapplicationearlierperiodpreparationincludingtraining,thehardwaredispositionandsoon.Thesoftwareusesthebasicdialogboxcontactsurface,cansatisfythesmallandmedium-sizedenterprisestaffstocheckattendancethemanagementbasicneed.Presentpaperinviewofthissoftwareeachaspect,Intheperformancehistoryinvolvesthetechnologyandthetoolseparatelyhaveallcarriedontheelaboration.Accordingtoaboveanalyzesthissystemmainmoduletobeasfollows:1registersthewindowmodule,2mainwindowmodules,3increasegoingoutondutyrecordmodule,4workingovertimerecordmodule,5asksforleavetherecordingmodule,6businesstriprecordmodule,inJulygoingoutondutysituationtablemodule.Inbrief,thisdesignworkisaapplytheorytorealityprocess.Notonlytomeisararestudyopportunity,moreovermademethroughthepracticetounderstandprofoundlytheseabstractconceptessence,futuretheworkhaslaidsolidlythefoundationforme.Keyword:Checkingattendance,system,information69 1论绪11.1应用背景11.2开发工具的选择11.2.1VisualC++6.0简介11.2.2使用VisualC++编程的理由21.2.3面向对象的应用服务层设计21.3论文的工作介绍32数据库技术概论42.1 数据库技术的介绍42.2 数据库发展及阶段特点42.3 数据库加密技术的运用62.4数据库理论基础62.4.1 数据库模型62.4.2 数据库体系结构82.4.3 数据的独立性92.4.4 范式102.5数据库设计原则112.6数据库设计的基本方法112.7Access数据库技术的选择123系统总体设计143.1  系统需求分析143.2  系统概要设计153.2.1 系统结构设计153.2.2 数据库设计173.3  系统详细设计244系统应用程序设计264.1 系统程序框架的组成264.2登录认证对话框的实现274.3 主对话框窗体功能的实现284.4 上班时间设置窗体功能的实现294.5 考勤修改窗体功能的实现304.6添假出勤记录属性页的实现314.7加班记录属性页功能的实现324.8请假和出差属性页功能的实现334.9考勤统计模块功能的实现355系统开发总结365.1结束语365.2参考文献365.3致谢366附录3869 1绪论1.1应用背景随着经济的发展,企业的规模不断扩大,人员流动日趋频繁,人员出入考勤管理的工作量也随之增加,以往的人工处理方式对于员工很多的企业来说就显得力不从心,利用现代计算机技术可使考勤人员管理从繁重的劳动中解脱出来,特别是对于人员出勤档案的查询可做到更及时,更准确。方便员工的出勤统计情况等各方面的工作。考勤制度是每个企业单位所必需的,计算机的出现使员工出勤情况的记录和统计工作变的十分简单。通过开发一个企业企业员工管理系统,可使企业员工的出勤管理工作系统化,规范化和自动化,从而达到全面提高企业员工考勤管理效率的目的。1.2开发工具的选择本系统是在VC++6.0开发环境下,采用Dialogbased的应用程序框架。由一个主对话框和若干个功能对话框组成。系统采用microsoftoffice中的Access2000来设计数据库,再连接数据源。1.2.1VisualC++6.0简介   VisualC++6.0是Microsoft公司开发的基于C/C++的集成开发工具,它是VisualStudio中功能最为强大、代码效率最高的开发工具。   VisualC++6.0与以前的版本相比有了多方面的改进。它的编译器、调试器、连接器、编辑器、资源编辑器都有所加强,在编辑器中还提供了自动语句生成功能,编辑器会像VisualBasic一样自动提示函数的参数、对象的成员。另外,VisualC++6.0还提供了很多向导。MFC提供了一些新的类,提供了更强大的数据访问功能。   用户可利用VisualC++6.0以两种方式编写Win32应用程序,一种方式是基于WindowsAPI的C编程方式,另一种是基于MFC69 的C++编程方式。C编程方式是传统的、久经考验的编程方式,代码的效率较高,但开发难度与开发的工作量大。C++编程方式代码运行效率相对较低,但开发难度小、开发工作量小、源代码效率高。C编程方式的用户己经很少,本书将以C++编程方式向用户介绍利用VisualC++6.0的程序设计。1.2.2使用VisualC++编程的理由VisualC++的集成开发环境提供了一个快速的框架,很大地提高了编程效率,但是,要真正掌握VisualC++6.0,还必须对C/C+语言编程有深入地了解,理解MFC库和Windows下的编程方法.在Windows下编程,通常是调用WindowsAPI得以实现.VisualC++6.0将大量地WindowsAPI以C++格式进行封装,通MPFC方式提供给开发人员,大大简化了开发人员地编程工作,提供了工作效率.因而,要学好VisualC++,MFC地掌握是关键.VisualC++6.0中,我们可以使用MFC完成大多熟地工作,也可以直接调用WindowsAPI完成一些底层地开发.用VisualC++6.0开发的程序代码简练,运行速度快.VisualC++6.0中,提供了两个功能强大的编程工具:AppWizard和ClassWizard.利用VisualC++6.0的AppWizard可以在很短的时间内创建出Windows应用程序的框架;二ClassWizard,则可以在应用程序框架之上迅速增加新的类,成员变量与函数,使Windows编程得以快速实现,两者结合,让Windows下的编程变得非常简单.1.2.3面向对象的应用服务层设计N层的应用软件系统,由于其众多的优点,已经成为典型的软件系统架构,也已经为广大开发人员所熟知。在一个典型的三层应用软件系统中,应用系统通常被划分成以下三个层次:数据库层、应用服务层和用户界面层。如下图所示:本系统也是采用三层应用服务设计,分别是数据库层、应用服务层和用户界面层,分三层逐步展开详细的设计。69 1.3论文的工作介绍绪论部分介绍了本系统的应用背景以及对数据库开发工具的选择。第二章介绍了数据库的发展,关系数据库,数据库体系结构,Access技术的选择等为设计和理解应用程序做了铺垫。。第三章是本文的主体,按照软件工程的要求,从需求分析开始,经过概要设计最后到详细设计,完成对整个系统的设计。第四章根据第三章的设计结果利用Access2000和VisualC++6.0进行了具体的窗体和应用程序设计。总结部分介绍了设计体会和编程体会,并指出了系统设计中的不足和改进的方向69 2数据库技术概论2.1 数据库技术的介绍数据库技术是目前IT行业中发展最快的领域之一,已经被广泛应用于各种类型的数据处理系统之中。了解并掌握数据库知识已经成为各类科技人员和管理人员的基本要求。数据库技术是一种计算机辅助管理数据的方法,它研究如何组织和存储数据,如何高效地获取和处理数据。数据管理是指对数据的组织、编码、分类、存储、检索和维护。它是数据处理的中心问题。数据管理方法根据数据管理的特点,其发展可划分为三个阶段:人工管理阶段、文件管理阶段和数据库系统阶段。一个完整的数据库系统是由计算机软硬件系统、数据库、数据库管理系统、应用程序和数据库管理员五个方面组成,其核心是数据库管理系统(DBMS)。2.2 数据库发展及阶段特点20世纪70年代关系模型提出后,由于其突出的优点,迅速被商用数据库系统所采用。据统计,70年代以来新发展的DBMS系统中,近百分之九十是采用关系数据模型,其中涌现出了许多性能优良的商品化关系数据库管理系统。例如,小型数据库系统Foxpro,ACCESS,PARADOX等,大型数据库系统DB2,INGRES,ORACLE,INFORMIX,SYBASE,SQLSERVER等。80年代和90年代是RDBMS产品发展和竞争的时代。各种产品经历了从集中到分布,从单机环境到网络环境,从支持信息管理到联机事务处理(OLTP),再到联机分析处理(OLAP)的发展过程;对关系模型的支持也逐步完善;系统的功能不断增强。1、对关系模型的支持 第一阶段(70年代)的RDBMS仅支持关系数据结构和基本的关系操作(选择、投影、连接)。例如:DBASE之流。第二阶段(80年代),对关系操作的支持已经比较完善,但是对数据完整性的支持仍然较差。此时,SQL语言已经成为关系数据库的标准,各家对SQL标准的支持还都是不存的(几乎全不是超水平发挥)。69 第三阶段(90年代)的产品,加强了数据完成性和安全性的性能。完整性的控制在核心层实现,克服了在工具曾的完整性可能存在“旁路”的弊病。2、运行环境第一阶段在大型、中性、小型机上运行的RDBMS一般为多用户系统,用户通过终端并发地存取、共享数据资源。微机上的一般为单用户版本。第二阶段的产品向两个方发展。一个是提高可移植性,使之能在多种硬件平台和操作系统下工作。另一个方向是数据库联网,向分布是系统发展,支持多种网络协议。 第三阶段的产品追求开放性,满足可移植性、可连接性、可伸缩性。3、系统构成早期的产品主要提供数据定义、数据存取、数据控制等基本的操作和数据存储组织、并发控制、安全性完整性检查、系统恢复、数据库的重新组织和重新构造等基本功能。这些成为RDBMS的核心功能。第二阶段的产品以数据管理的基本功能为核心,着力开发外围软件系统,比如FORMS表格生成系统、REPORTS报表系统、MENUS菜单生成系统等。这些外围工具软件,就是所谓的第四代应用开发环境,他们大大提高了数据库应用开发的效率。4、对应用的支持RDBMS的第一代产品主要用于信息管理领域。这些应用对联机速度的要求不是很高。第二阶段的主要应用领域转移到了联机事务处理上,提高事务吞吐量,提高事务联机相应性能是各个商家的重点问题。相对应的关键实现技术是:性能,提高RDBMS对联机事务响应速度;可靠性。由于联机事务不允许RDBMS间断运行,在发生故障、软硬件故障时均能有相应的恢复能力,保证联机事务的正常运行、撤销和恢复。保证数据的完整性和移植性。第三阶段的热点是联机分析处理。用户希望数据库系统不仅能够迅速、完美地完成数据处理的任务;而且,希望它能有一定的辅助决策的能力。2.3 数据库加密技术的运用随着网络技术的发展,网络安全也就成为当今网络社会的焦点问题,69 加密技术就是适应了网络安全的需要而应运产生的,数据加密作为实现网络安全的关键技术之一,它为我们进行一般的电子商务活动提供了安全保障。数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。而本系统为考勤管理系统,为了不使无关人员随意进入系统,只要是采用在登陆的对回话框CLoginDlg中设置用考勤员和密码来保护系统的安全,其做法是在登陆对话框中的登陆按钮OnOK()函数中调用加密类CCryp的加密函数Encrypt来进行加密的。2.4数据库理论基础2.4.1 数据库模型从20世纪50年代中期开始,计算机的应用由科学研究部门逐步扩展到企业、行政部门。至60年代,数据处理成为计算机的主要应用。数据库技术作为数据管理技术,是计算机软件领域的一个重要分支,产生于60年代末。现已形成相当规模的理论体系和实用技术。模型是对现实世界的抽象。在数据库技术中,我们用模型的概念描述数据库的结构与语义,对现实世界进行抽象,表示实体类型及实体间联系的模型称为“数据模型”。目前广泛作用的数据模型可分为两种类型。一种是独立于计算机系统的模型,完全不涉及信息在系统中的表示,只是用来描述某个特定组织所关心的信息结构,这类模型称为“概念数据模型”。要领模型用于建立信息世界的数据模型,强调其语义表达功能,应该概念简单、清晰,易于用户理解,它是现实世界的第一层抽象,是用户和数据库设计人员之间进行交流的工具。这一其中著名的模型是“实体联系模型”。另一种数据模型是直接面向数据库的逻辑结构,它是现实世界的第二层抽象。这类模型涉及到计算机系统和数据库管理系统,又称为“结构数据模型”69 。例如,层次、网状、关系、面向对象等模型。这类模型有严格的形式化定义,以便于在计算机系统中实现。(1)层次模型。用树型结构表示实体类型及实体间联系的数据模型。树的结点是记录类型,每个非根结点有且只有一个父结点。上一层记录类型和下一层记录类型间联系是1∶n联系。层次模型的特点是记录之间的联系通过指针实现,查询效率较高。但层次模型有两个缺点:一是只能表示1∶n联系,虽然有多种辅助手段实现了m∶n联系,但都较复杂,用户不易掌握,二是由于树型结构层次顺序的严格和复杂,引起数据的查询和更新操作也很复杂,因此,编写应用程序也很复杂。(2)网状模型。用有向图结构表示实体类型及实体间联系的数据模型。。1969年dbtg报告提出的数据模型是网状模型的主要代表。有向图中的结点是记录类型,有向边表示从箭尾一端的记录类型到箭头一端的记录类型间联系是1∶n联系。网状模型的特点:记录之间联系通过指针实现,m∶n联系也容易实现(每个m∶n联系可拆成两个1∶n联系),查询效率较高。网状模型的缺点是编写应用程序比较复杂,程序员必须熟悉数据库的逻辑结构。由于层次系统和网状系统的应用程序编制比较复杂,因此,从20世纪80年代中期起,其市场已被关系系统所取代。但是使用这两种模型建立起的许多数据库仍然在正常运转,只是在外层加了个关系数据库语言的接口。网状模型有许多成功的产品,20世纪70年代的产品大部分网状系统,例如,honeywell公司的ids/ⅱ、hp公司的image/3000、burroughs公司的dmsⅱ69 、umivac公司的dms1100、cullinet公司的idms、cimcom公司的total等(3)关系模型。关系模型的主要是用二维表格结构表达实体集,用外键表示实体间联系。关系模型是由若干个关系模式组成的集合。关系模式相当于前面提到的记录类型,它的实例称为关系,每个关系实际上是一张二维表格。关系模型和层次、网状模型的最大判别是用关键码而不是用指针导航数据,表格简单用户易懂,编程时并不涉及存储结构,访问技术等细节。关系模型是数学化模型。sql语言是关系数据库的标准化语言,已得到了广泛的应用。20世纪70年代对关系数据库的研究主要集中在理论和实验系统的开发方面。80年代初才形成产品,但很快得到广泛的应用和普及,并最终取代了层次、网状数据库产品。现在市场上典型的关系dbms产品有db2、oracle、sybase、informix和微机型产品foxpro、access等。关系模型和网状、层次模型的最大区别是:关系模型用表格数据而不是通过指针链来表示和实现实体间联系。关系模型的数据结构简单、易懂。只需用简单的查询语句就可对数据库进行操作。关系模型是数学化的模型,可把表格看成一个集合,因此集合论、数理逻辑等知识可引入到关系模型中来。关系模型已是一个成熟的有前途的模型,已得到广泛应用。(4)面向对象模型。目前,关系数据库的使用已相当普遍,但是,现实世界中仍然存在着许多含有复杂数据结构的应用领域,例如,cad数据、图形数据等,而关系模型在这方面的处理能力就显得力不从心。因此,人们需要更高级的数据库技术来表达这类信息。面向对象的概念最早出现在程序设计语言中,随后迅速渗透到计算机领域的每一个分支。面向对象数据库是面向对象概念与数据库技术相结合的产物。面向对象模型能完整地描述现实世界的数据结构,具有丰富的表达能力,但模型相对较复杂,涉及的知识面也广,因此面向对象数据库尚未达到关系数据库那样的普及程度。2.4.2 数据库体系结构数据库的体系结构分三级:内部级(internal),概念级(conceptual)和外部级(external)。这个三级结构有时也称为“三级模式结构”,或“数据抽象的三个级别”,最早是在1971年通过的dbtg报告中提出,后来收入在1975年的美国ansi/sparc报告中。虽然现在dbms的产品多种多样,在不同的操作系统支持下工作,但是大多数系统在总的体系结构上都具有三级模式的结构特征。从某个角度看到的数据特性称为“数据视图”(data69 view)。外部级最接近用户,是单个用户所能看到的数据特性。单个用户使用的数据视图的描述称为“外模式”。概念级涉及到所有用户的数据定义,是全局的数据视图。全局数据视图的描述称为“概念模式”。内部级最接近于物理存储设备,涉及到实际数据存储的结构。物理存储数据视图的描述称为“内模式”。数据库的三级模式结构是数据的三个抽象级别。它把数据的具体组织留给dbms去做,用户只要抽象地处理数据,而不必关心数据在计算机中的表示和存储,这样就减轻了用户使用系统的负担。三级结构之间往往差别很大,为了实现这三个抽象级别的联系和转换,dbms在三级结构之间提供两个层次的映象(mappings):外模式/模式映象,模式/内模式映象。此处模式是概念模式的简称。2.4.3 数据的独立性由于数据库系统采用三级模式结构,因此系统具有数据独立性的特点。在数据库技术中,数据独立性是指应用程序和数据之间相互独立,不受影响。数据独立性分成物理数据独立性和逻辑数据独立性两级。(1)物理数据独立性如果数据库的内模式要进行修改,即数据库的存储设备和存储方法有所变化,那么模式/内模式映象也要进行相当的修改,使概念模式尽可能保持不变。也就是对内模式的修改尽量不影响概念模式,当然,对于外模式和应用程序的影响更小,这样,我们称数据库达到了物理数据独立性。(2)逻辑数据独立性如果数据库的概念模式要进行修改,譬如增加记录类型或增加数据项,那么外模式/模式映象也要进行相应的修改,使外模式尽可能保持不变。也就是对概念模式的修改尽量不影响外模式和应用程序,这样,我们称数据库达到了逻辑数据独立性。现有关系系统产品均提供了较高的物理独立性,而对逻辑独立性的支持尚有欠缺,例如,对外模式的数据更新受到限制等。2.4.4 范式69 建立起一个良好的数据指标体系,是建立数据结构和数据库的最重要的一环。一个良好的数据指标体系是建立db的必要条件,但不是充分条件。我们完全可以认为所建指标体系中的一个指标类就是关系数据库中的一个基本表,而这个指标类下面的一个个具体指标就是这个基本表中的一个字段。但如果直接按照这种方式建库显然还不能算最佳。对于指标体系中数据的结构在建库前还必须进行规范化的重新组织。在数据的规范化表达中,一般将一组相互关联的数据称为一个关系(relation),而在这个关系下的每个数据指标项则被称为数据元素(dataelement),这种关系落实到具体数据库上就是基本表,而数据元素就是基本表中的一个字段(field)。规范化表达还规定在每一个基本表中必须定义一个数据元素为关键字(key),它可以唯一地标识出该表中其它相关的数据元素。在规范化理论中表是二维的,它有如下四个性质:在表中的任意一列上,数据项应属于同一个属性(如图中每一列都存放着不同合同记录的同一属性数据)。表中所有行都是不相同的,不允许有重复组项出现(如图中每一行都是一个不同的合同记录)。在表中,行的顺序无关紧要(如图中每行存的都是合同记录,至于先放哪一个合同都没关系)。在表中,列的顺序无关紧要,但不能重复(如图中合同号和合同名谁先谁后都没关系,但二者不可重复或同名)。在对表的形式进行了规范化定义后,数据结构还有五种规范化定义,定名为规范化模式,称为范式。在这五种范式中,一般只用前三种,对于常用系统就足够了。而且这五种范式是“向上兼容”的,即满足第五范式的数据结构自动满足一、二、三、四范式,满足第四范式的数据结构自动满足第一、二、三范式,……,依此类推。第一范式(firstnormalform,简称1stnf)就是指在同一表中没有重复项出现,如果有则应将重复项去掉。这个去掉重复项的过程就称之为规范化处理。在本文所讨论的开发方法里,1stnf实际上是没有什么意义的。因为我们按规范化建立的指标体系和表的过程都自动保证了所有表都满足1stnf。第二范式(secondnormalform,简称2ndnf)是指每个表必须有一个(而且仅一个)数据元素为主关键字(primary69 key),其它数据元素与主关键字一一对应。例如,在图l9.7中如果我们将合同号定义为主关键字(其它数据元素中的记录数据都有可能重名,故不能作为主关键字),故只要知道了一个合同记录的合同号,就可以唯一地在同一行中找到该合同的任何一项具体信息。通常我们称这种关系为函数依赖(functionaldependence)关系。即表中其它数据元素都依赖于主关键字,或称该数据元素唯一地被主关键字所标识。第三范式(thirdnormalform,简称3rdnf)就是指表中的所有数据元素不但要能够唯一地被主关键字所标识,而且它们之间还必须相互独立,不存在其它的函数关系。也就是说对于一个满足了2ndnf的数据结构来说,表中有可能存在某些数据元素依赖于其它非关键宇数据元素的现象,必须加以消除。为防止数据库出现更新异常、插入异常、删除异常、数据冗余太大等现象,关系型数据库要尽量按关系规范化要求进行数据库设计。2.5数据库设计原则一个好的数据库产品不等于就有一个好的应用系统,如果不能设计一个合理的数据库模型,不仅会增加客户端和服务器段程序的编程和维护的难度,而且将会影响系统实际运行的性能。一般来讲,在一个MIS系统分析、设计、测试和试运行阶段,因为数据量较小,设计人员和测试人员往往只注意到功能的实现,而很难注意到性能的薄弱之处,等到系统投入实际运行一段时间后,才发现系统的性能在降低就回对系统设计带来麻烦,所以数据库设计要按一定的严谨的原则进行。2.6数据库设计的基本方法数据库设计是建立数据库及其应用系统的核心和基础,它要求对于指定的应用环境,构造出较优的数据库模式,建立起数据库应用系统,并使系统能有效地存储数据,满足用户的各种应用需求。一般按照规范化的设计方法,常将数据库设计分为若干阶段:69   系统规划阶段主要是确定系统的名称、范围;确定系统开发的目标功能和性能;确定系统所需的资源;估计系统开发的成本;确定系统实施计划及进度;分析估算系统可能达到的效益;确定系统设计的原则和技术路线等。对分布式数据库系统,还应分析用户环境及网络条件,以选择和建立系统的网络结构。  需求分析阶段要在用户调查的基础上,通过分析,逐步明确用户对系统的需求,包括数据需求和围绕这些数据的业务处理需求。通过对组织、部门、企业等进行详细调查,在了解现行系统的概况、确定新系统功能的过程中,收集支持系统目标的基础数据及其处理方法。  概念设计阶段要产生反映企业各组织信息需求的数据库概念结构,即概念模型。概念模型必须具备丰富的语义表达能力、易于交流和理解、易于变动、易于向各种数据模型转换、易于从概念模型导出与DBMS有关的逻辑模型等特点。  逻辑设计阶段除了要把E-R图的实体和联系类型,转换成选定的DBMS支持的数据类型,还要设计子模式并对模式进行评价,最后为了使模式适应信息的不同表示,需要优化模式。  物理设计阶段的主要任务是对数据库中数据在物理设备上的存放结构和存取方法进行设计。数据库物理结构依赖于给定的计算机系统,而且与具体选用的DBMS密切相关。物理设计常常包括某些操作约束,如响应时间与存储要求等。  系统实施阶段主要分为建立实际的数据库结构;装入试验数据对应用程序进行测试;装入实际数据建立实际数据库三个步骤。  另外,在数据库的设计过程中还包括一些其他设计,如数据库的安全性、完整性、一致性和可恢复性等方面的设计,不过,这些设计总是以牺牲效率为代价的,设计人员的任务就是要在效率和尽可能多的功能之间进行合理的权衡。2.7Access数据库技术的选择在办公软件Office套件中,最为广大用户熟悉的是Word和Excel,因为它们功能强大且方便易用,更因为它们不仅可用于办公,还可用于个人写作和家庭记帐理财等。同为Office套件中一部分的Access,虽然有着同样强大的功能,但使用的人却相对少些,不像Word和Excel那样广泛。 Access数据库管理系统是MicrosoftOffice套件的重要组成部分,是Access的最新版本,可在Windows环境下运行。Access适用于小型商务活动,用以存贮和管理商务活动所需要的数据。Access不仅是一个数据库,而且它具有强大的数据管理功能,它可以方便地利用各种数据源,生成窗体(表单),查询,报表和应用程序等。69 本考勤管理系统也正是利用Access的特点建立数据库。数据库是有结构的数据集合,它与一般的数据文件不同,MicrosoftAccess是一种关系式数据库,关系式数据库由一系列表组成,表又由一系列行和列组成,每一行是一个记录,每一列是一个字段,每个字段有一个字段名,字段名在一个表中不能重复。  表与表之间可以建立关系(或称关联,连接),以便查询相关联的信息。Access数据库以文件形式保存,文件的扩展名是MDB。Access数据库由六种对象组成,它们是表、查询、窗体、报表、宏和模块。表(Table)——表是数据库的基本对象,是创建其他5种对象的基础。表由记录组成,记录由字段组成,表用来存贮数据库的数据,故又称数据表。  查询(Query)——查询可以按索引快速查找到需要的记录,按要求筛选记录并能连接若干个表的字段组成新表。  窗体(Form)——窗体提供了一种方便的浏览、输入及更改数据的窗口。还可以创建子窗体显示相关联的表的内容。窗体也称表单。  报表(Report)——报表的功能是将数据库中的数据分类汇总,然后打印出来,以便分析。  宏(Macro)——宏相当于DOS中的批处理,用来自动执行一系列操作。Access列出了一些常用的操作供用户选择,使用起来十分方便。  模块(Module)——模块的功能与宏类似,但它定义的操作比宏更精细和复杂,用户可以根据自己的需要编写程序。模块使用VisualBasic编程。  Access可以方便地利用各种数据源,包括dBASE,FoxBase,FoxPro,Excel,Word等。Access增加了数据库访问的安全机制,可对表一级设置访问许可权。Access还可以方便地利用FoxPro数据库、Excel电子表格的数据,还可以和Word混合使用,打印通用信函或信封。3系统总体设计69 软件系统的总体设计大约要经历可行性分析和项目开发计划,需求分析,概要设计,详细设计,编码,测试以及维护等七个阶段。可行性分析和项目开发计划在前面已经叙述,下面所要做的是进行软件需求分析,概要设计和详细设计。编码过程将在下一节论述,而测试和维护过程不在本文叙及.3.1  系统需求分析在经过前一阶段的分析之后,我确定了我的开发课题为企业员工考勤管理系统。现在所要做的是要准确定义系统必须做什么以及系统必须具备的功能。软件需求分析中我采用结构化分析方法(structuredanalysis,简称sa),sa是面向数据流进行需求分析的方法,像所有的软件分析方法(如面向对象分析方法、idef方法等等)一样,sa也是一种建模活动,它使用简单易读的符号,根据软件内部数据传递、变换的关系,自顶向下逐层分解,描绘满足功能要求的软件模型。在系统中我采用数据流图(dfd)这种半形式化的描述方式表达需求。它是一种功能模型,以图形的方式描绘数据在系统中流动和处理的过程,只反映系统必须完成的逻辑功能。它有四种基本图形符号:◆→:箭头,表示数据流;◆〇:圆或椭圆,表示加工;◆═:双杠,表示数据存储;◆□:方框,表示数据的源点或终点。,顶层流图仅包含一个员工,它代表被开发系统,它的输入流是该系统的输入数据了,输出流是该系统的输出数据;底层流图是指其加工不需要再做分解的数据流图,中间层流图表示对其上层父图的细化,它的每一步操作可能继续细化成子图。出勤的原始记录主要来源于考勤机,并且以固定格式保存在数据库中。考勤管理系统的任务是如何处理这些数据.系统的数据流程如下:69  通过以上的数据流图之后,我们已大体地了解了系统的功能和目标,接下来所要做的就是系统功能模块的划分和数据库的设计,也就是系统的概要设计。3.2  系统概要设计在软件需求分析阶段,搞清楚了软件“做什么”的问题,形成了目标系统的逻辑模型。现在我们所要做的就是要把软件“做什么”的逻辑模型变换为“怎么做”的物理模型,即着手实现软件的需求。首先,我们需要描述的是系统的总的体系结构。3.2.1 系统结构设计69 系统的概要设计中最重要的就是系统的模块化。模块化是指解决一个复杂问题时自项向下逐层把软件系统划分成若干个模块的过程。每个模块完成一个特定的功能,所有的模块按某种方法组织起来,成为一个整体,完成整个系统所要求的功能。 将系统划分为多个模块是为了降低软件系统的复杂性,提高可读性、可维护性,但模块的划分不能是任意的,应尽量保持其独立性。也就是说,每个模块只完成系统要求的独立的子功能,并且与其他模块的联系最少且接口简单,即尽量做到高内聚低耦合,提高模块的独立性,为设计高质量的软件结构奠定基础。在系统的概要设计中我采用结构化设计(structuredesign,简称sd),sd以需求分析阶段产生的数据流图dfd为基础,按一定的步骤映射成软件结构。我首先将整个系统化分为几个小问题,小模块,在系统中,我设计了上下班时间设置、出勤记录管理、和考勤统计管理3个小模块。然后,进一步细分模块,添加细节。比如,出勤记录管理我又将其分为添加修改出勤管理、加班管理、请假管理;出差管理(即是代理出勤管理)等等。以下就是系统的结构图:(在这里为了表达方便我将结构图分开来表达。)上下班时间设置出勤统计情况出勤情况记录考勤管理系统 在得到系统的第一层功能模块图后,经过进一步地细化,得一系统的子功能模块图:出勤情况记录出差情况记录添加出勤情况请假情况记录加班情况记录69 3.2.2 数据库设计在信息世界中,信息从客观事物出发流经数据库,通过决策机构最后又回到客观世界,信息的这一循环经历了三个领域:信息世界,数据世界,现实世界。现实世界的事物反映到人的头脑中,人的大脑对它有个认识过程,经过分析(选择、命名、分类等)进入信息世界。这些信息再进一步加工、编码,然后进数据世界,而软件系统的开发工作需要考虑这两个方面的问题,也就是要考虑系统开发所需要的数据,以及如何对这些数据进行操作。这两个问题贯穿了整个软件系统的开发过程,这也就是数据库的设计问题,软件设计的一个核心。1 、er图设计在系统设计的开始,我首先考虑的是如何用数据模型来数据库的结构与语义,以对现实世界进行抽象。目前广泛使用的数据模型可分为两种类型,一种是独立于计算机系统的“概念数据模型”,如“实体联系模型”;另一种是直接面向数据库逻辑结构的“结构数据模型”。在本系统中我采用“实体联系模型”(er模型)来描述数据库的结构与语义,以对现实世界进行第一次抽象。er模型直接从现实世界抽象出实体类型及实体间联系,然后用er图来表示数据模型。它有两个明显的优点:接近于人的思维,容易理解;与计算机无关,用户容易接受。但er模型只能说明实体间语义的联系,不能进一步说明详细的数据结构,它只是数据库设计的第一步。er图是直观表示概念模型的工具,它有四个基本成分:◆矩形框,表示实体类型(考虑问题的对象)。◆菱形框,表示联系类型(实体间的联系)。◆椭圆形框,表示实体类型和联系类型的属性。对于关键码的属性,在属性名下划一横线。◆直线,联系类型与其涉及的实体类型之间以直线连接。本系统为企业员工考勤管理,主要管理员工的出勤、请假、出差和加班等事项。系统根据需要可以记录出勤人员的信息,同时还需要了解员工的请假、出差和加班等的记录情况。依据考勤管理的实际情况,考虑了多方面的因素以后,确定系统的er图。考勤管理系统的E-R图如图所示69  在该数据库中,我设计了六个实体,分别是员工、出勤管理、加班管理、请假管理;出差管理,月度考勤统计管理。在本系统中员工是核心,也是基本,没有了员工其它的也就没有什么意义了。员工记录的添加是考虑到出勤记录问题,也就是说,在出勤管理的实际运用中,需要记录每个员工的具体情况这样才方便月度的统计,特别是由于员工的工资要按工作时的多少发放,所以在设计数据库时,,员工记录这一实体非常重要。通过这一个er图我们可以比较清楚地了解员工工作时间的多少,及其具体的情况,从员工的出勤到请假,加班等情况的勤奋情况及其员工的素质,同时也可以为以后的查询或核对提供一定有用的信息。下面就是各实体及联系类型的属性即数据库的逻辑设计,所以考勤管理系统的E-R图转换为关系表为:员工(员工号,员工密码,权限,姓名)出勤记录(员工号,记录编号,出入状态,出入时间)69 加班记录(员工号,记录编号,加班时间,日期)请假记录(员工号,记录编号,起始时间,结束时间,缘由)出差记录(员工号,记录编号,起始时间,结束时间,具体描述)因为每一个基本表关系都是完全依赖且没有传递依赖,所以关系达到3NF范式2、数据库表格设计在完成系统的er图之后,需要将er模型转化为关系模型,也就是说,要设计出数据库所需要的表格。在这里,我选用的是关系数据库。因为关系数据库中的二维表格可以很清楚地描述数据之间的联系。在这里不得不提到一个概念——范式。其实在上一节的er图设计中,已经运用了范式的思想,不仅如此,在数据库的表格设计中更离不开范式的思想,它是数据库设计的基础,如果不注意这个问题将会导致一系列问题的出现。我在系统中定义的表格都严格地按照范式的思想和要求去完成,数据库中的所有表格都达到了三范式的要求。根据系统er图,针对本系统的特点,在对所搜集的数据进行规范化之后,定义了如下六张表格,分别是ATTENDANCE出勤记录表,LEAVE请假记录表,OVERTIME加班记录表,ERRAND出差记录表,员工及密码信息表。通过对这六张表格的操作可以较好地完成系统设计的各项功能,六张表格之间有着不同程度的联系。ATTENDANCE出勤记录表字段名称 数据类型 说明 person 文本 员工编号 in_out 文本 出入情况io_time 日期/时间 出入时间69 图1ATTENDANCE出勤记录表出勤记录表主要用于记录员工出入情况和时间的详细信息,包括记录号、员工、出入情况和时间、各类信息,它即是该数据库的主表,是系统主界面的主要内容。在该表中员工编号是主键,出入情况和时间为其属性成员。做为备注有一点说明,我的数据库中备注的数据类型是文本,而不是备注类型,主要考虑到该字段的长度并不大,而且在VisualC++中文本数据类型的处理也比较方便一点。图2LEAVE请假记录表字段名称数据类型 说明 person 文本 员工编号start_time 日期/时间 假期开始时间end_time 日期/时间 假期结束时间reason文本 请假缘由LEAVE请假记录表主要是记录员工的请假情况,请假的开始时间和结束时间,以方便以后员工的统计情况。69 图3OVERTIME加班记录表person 文本 员工编号work_hours 数字加班时间work_date 日期/时间 加班日期OVERTIME加班记录表主要是记录员工的加班时间长度和日期如图3所示。图4ERRAND出差记录表person 文本 员工编号start_time 日期/时间 假期开始时间end_time 日期/时间 假期结束时间discription文本 具体描述ERRAND出差记录表主要是记录员工的出差起始时间/结束时间和具体描述。图5PERSON员工信息表 字段名称 数据类型 说明69 Person文本 员工编号passwd文本 密码authority文本 用户权限 name文本员工姓名sex 文本性别birthday 日期/时间 生日job 文本 职务edu_level 文本 受教育程度specialty文本 专业技能address文本 家庭住址tel文本联系电话 PERSON员工信息表员工信息表主要用于记录有关员工的各类信息,包括姓名、职称、出生日期、联系电话、联系地址等。它主要用来为系统提供员工的有关信息,因为在系统中,出勤管理、加班管理、请假管理;出差管理,月度考勤统计管理操作均与员工有着一定的联系,需要查找有关此项记录有关的员工信息 等都要用到这个表。图6COUNTER信息表字段名称 数据类型 说明Counter_value数字计数值Descrtption文本描述69 COUNTER信息表主要是记录员工的统计工作。图7DEPARTMENT信息表字段名称 数据类型 说明Name文本部门名称Manager文本部门经理Intro备注简介  DEPARTMENT信息表主要是记录员工部门里面的各种信息。图8ATTENDANCE—STAT信息表字段名称 数据类型 说明Year_month文本统计月份Person文本员工号Work_hour数字累计工作时间Over_hour数字累计加班时间Leave_hour数字累计请假时间Errand_hday数字累计出差时间Late_times数字迟到次数Early_times数字早退次数Absent_times数字旷工次数69 ATTENDANCE—STAT信息表主要用于记录有关统计的详细信息,主要是按月度来统计包括员工的工作时间、加班时间,累计请假时间,累计出差时间,迟到和早退的次数等信息。通过以上设计已经完成了系统的概要设计,当我们有了系统的功能模块图和数据库之后,就需要着手去实现每一个模块,为每一个功能设计程序流程图,这也就是系统的详细设计。3.3  系统详细设计在前面的概要设计中,已将系统划分为多个模块,并将它们按照一定的原则组装起来,同时确定了每个功能及模块之间的外部接口。现在所要做的就是确定每个模块具体执行过程,也可以说是“过程设计”。在处理过程设计时我采用的是结构化程序设计(简称sp)方法。需要指出的是系统的详细设计并不是指具体的编程序,而是将概要设计阶段产生的系统功能模块图细化成很容易产生程序的图纸。因此详细设计的结果基本决定了最终程序的质量。为软件的质量,延长软件的生存期,软件的可测试性、可维护性提供重要的保障。详细设计的目标不仅是逻辑上正确地实现每个模块的功能,还应使设计出的处理过程清晰易读。由前一阶段产生的系统功能模块图,我为系统的主要部分设计了如下程序模块图:69   通过以上步骤,基本上完成了对整个系统的总体设计,接下来所要做的就是软件的编码工作。系统总体设计的好坏直接影响着下一步工作,只有在这一阶段设计出好的模块图和程序流程图,才能更有利于编码,产生好的软件系统。69 4系统应用程序设计4.1 系统程序框架的组成本实例采用dialogbased的应用程序框架.由一个主对话框和若干个功能对话框组成,其中功能对话框登陆对话框和上下班时间设置对话框都是非模态对话框用AppWizard生成程序框架,加入数据库支持.在MFCAppWizar-Step1中选择DialogBased选项,其余均采用缺省配置.本程序数据库的操作是通过MFC的ODBC类实现的,为了使用ODBC类,需要在stdafx.h中加入#include“afxdb.h”一行.因本程序只需连接一个数据库,所以定义了一个CDatadase型的全局变量db,一次性打开和关闭数据库,方便程序的编写.数据库的打开在登录认证对话框中.在主程序结束前关闭数据库,因此在App类的ExitInstance()函数中加入以下代码;if(db.Isopen())db.Close();使用全局数据库变量db,需要在其他地方使用他的文件中加入以下语句:ExternDatabasedb;为了访问数据库中的表格,本程序从CRecordset中派生8个类,分别用于封装所需访问的表格,如下列图表所示.这些类通过RFX(RecordFieldExchange)机制将成员变量也表格中的字段值联系起来,通过访问成员变量可以访问当前记录中字段的值.CRecordset派生类在Acess数据库中对应的表格:CRecordset表格CAttendanceRSATTENDANCE出勤记录表CCounterRSCOUNTER计数器表CdepattRSDEPARTMENT部门信息表CerrandRSERRAND出差记录表CerrandRSCLeaveRSCOvertimeRSOVERTIME加班记录表CPersonRSPERSON员工个人信息表CStatRSATTENDANCE_STAT月度考勤统计表69 4.2登录认证对话框的实现首先在控制面板中建立ODBC数据源,数据源名称为MISDB,运行程序Attendance.exe,进入登陆界面(界面一)。用户名为HONG,密码为123。登陆窗口对话框,包括三个输入框和两个按钮。主要控件类型,ID和对应的成员变量及说明见见表。登陆窗口对话框的封装类为CLoginDlg。界面一:登录认对话框其中两个Button采用了缺省ID,即IDOK和IDCANCEL,其中对IDOK的点击加了登录代码,CLoginDlg类需要用到加密类,为了保证统一,加密类使用了CCrypt类,需要在cpp文件开头加入#include“CCrypt”一行。另外,为了使用全局变量数据库变量db,需要在cpp文件开头加入下面的语句:externCDatabasedb;改变"登录人事管理系统"字体的类型为华文彩云和需要在OnInitDialog()添加下面的代码。BOOLCLoginDlg::OnInitDialog(){CDialog::OnInitDialog();m_font.CreatePointFont(180,"华文彩云",NULL);GetDlgItem(IDC_STATIC_LOGINTEXT)->SetFont(&m_font,true);//如数据库为打开状态,则关闭if(db.IsOpen())db.Close();69 }在用户的“登陆”按钮功能实现的代码在voidCLoginDlg::OnOK()函数中见附录最侯为了先运行登录认证对话框,还需在App类的InitInstance()函数中加代码://显示登录对话框CLoginDlgLoginDlg;if(LoginDlg.DoModal()!=IDOK)returnFALSE;4.3 主对话框窗体功能的实现用户登录后即显示主对话框窗口,主对话框包括5个按钮,分别实现5项功能,封装主对话框的类是CAttendanceDlg,主要界面及说明如下:界面二:主对话框在CAttendanceDlg中定义以下成员变量:CBrushm_brush;CStatDlg*m_pStatDlg;CAttDlg*m_pAttDlg;69 CFontm_font;//改变标题字体类型m_font.CreatePointFont(180,"华文彩云",NULL);GetDlgItem(IDC_STATIC_HEAD)->SetFont(&m_font,true);//初始化对话框指针为空m_pAttDlg=NULL;m_pStatDlg=NULL;对话框中的5个按钮的功能主要就是显示相应的功能对话框.。各按钮的功能主要是显示相应的功能对话框。各按钮的事件处理代码见附录。4.4 上班时间设置窗体功能的实现点击“设置”进入界面三设置上下班时间。在界面三中,你可以修改上下班时间,点击“修改”,设置的时间会记录到配置文件“workplan.ini”中。如果配置文件不存在,上下班时间就被设定为程序中的默认值。界面三:上班时间设置窗体公司的上下班时间相当固定,而且需要在统计时频繁使用,所以不需要保存在数据库中.本例采用标准的INI设置文件来保存这些数据;“修改”按钮的BN_CLICKEN事件处理程序用于保存当前的设置.“恢复默认设置”按钮的BN_CLICKED事件处理程序用于恢复原来的设置.这个函数也同时被OnInitDialog()函数引用,以实现初始化操作.OnWorkplanReset()69 函数则存放恢复默认设置按钮的码4.5 考勤修改窗体功能的实现考勤修改对话框主要用来人工输入出勤情况.如果考勤机出现问题,这个功能及时弥补数据.同时加班,请假,出差的记录都需要通过这个对话框来输入.对话框的布局如下图所示.为了区分不同的输入,在对话框中嵌入了CPropertySheet和4个CPropertyPage,4个CPropertyPage分别放置出勤,加班,请假和出差记录的修改界面.4个界面共用一个查询条件设置,下图中下方的空白界面即是用来放置CPropertySheet和CPropertyPage的,考勤修改对话框的封装类是CAttDlg。对话框界面如下:界面四在对话框中嵌入了CPropertySheet和4个CPropertyPage,就需要定义类的变量CPage1m_Page1(出勤页),CPage2m_Page2(加班页),CPage3m_Page3(请假页),CPage4m_Page4(出差页),和CPropertySheetm_Sheet。然后修改它的初始化函数BOOLCAttDlg::OnInitDialog()的代码,见附录。在输入员工号时,需要及时检索员工姓名,以确定设置的条件有效.通过ClassWizard加入处理IDC_EDT_SEEKPERSONID的EN_CHANGE消息处理的函数OnChangeEdtSeekpersonid(),见附录。69 4.6添假出勤记录属性页的实现再加入一个对话框资源将其封装类设为CPropertyPage他的继承类为CPage1,对话框的界面如下界面五在界面五中,可以检索或修改出勤记录。检索考勤记录:在“记录检索条件”中,选中“时间范围”复选框,输入时间范围,或选中“员工”复选框,输入员工号,在右边的文本框中会自动显示员工号对应的员工名字,然后点击“按条件检索”,在“出勤记录列表”中会显示出选定时间范围或员工的出勤记录。:添加记录:在“添加记录”中输入出入时间,出入情况,部门缩写(输入后右边会显示部门名称),员工号(输入后右边会显示员工名字)。点击“全部员工”把全部员工每人一条出勤记录添加到数据库并在出勤列表中显示,点击“部门员工”为该部门的每位员工添加一条出勤记录到数据库并在出勤列表中显示,点击69 “单个员工”为该员工添加一条出勤记录到数据库并在出勤列表中显示。下面的进度条会显示添加记录的进度。删除记录:在“出勤记录列表”中选定记录编号,然后点击“删除所选记录”,把记录从列表和数据库中删除。他的属性页面的初始化函数为OnInitDialog()。为了更新列表框内容,编写的UpdateList()函数调用此函数可使列表框显示给定的数据表格,当输入部门编号时,自动检索部门名称.他的实现函数为OnChangeEdtDepartid()。在输入员工号时,也需要及时检索员工姓名,以确定设置的条件有效,在函数OnChangeEdtPersonid()中实现。添加部门和全体员工出勤记录的过程最终客分解为添加单个员工记录的过程.通过添加出勤记录函数IO_Add(CStringstrPersonID)实现。添加记录的3个按钮的处理程序分别调用以上的函数。:OnBtnAddall()为添加所有员工出勤记录,OnBtnAdddepart()为追加部门员工考勤记录,OnBtnAddperson()为追加单个员工考勤记录。4.7加班记录属性页功能的实现这个属性页的创建以上面的添假出勤记录属性页的创建类似,封装类都为CPropertyPage类他的继承类为CPage2,对话框的界面如下。同时也要对他的初始化函数OnInitDialog(),UpdateList()函数,OnChangeEdtOvertimePersonid()略做修改。添加按钮的实现如下函数为OnBtnOvertimeAdd(),下面的“删除所以记录”按钮和”按条件检索”按钮的功能与添加修改出勤记录中的相应按钮功能类似,代码不再重复出现,可见源程序69 界面六4.8请假和出差属性页功能的实现这两个属性爷的创建基本相同,请假记录的封装类为CPropertyPage继承的CPage3类,出差记录的封装类为CPropertyPage继承的CPage4类界面的初始化,列表的更新,员工姓名的检索,删除记录,按条件检索功能等基本类似,只是代码修改少许则可其中请假属性页功能的添加记录函数在OnBtnLeaveAdd()中实现。请假和出差的考勤记录检索,添加和删除同修改出勤记录类似。界面如下:69 界面七69 界面八4.9考勤统计模块功能的实现考勤统计对话框列表的初始化和数据的更新功能OnChangeEdtSeekpersonid()功能和“检索”功能也和前面类似,最后是“统计按钮”的功能其函数为OnStatBtnStat()(按月度统计的)。其初始化时间设计要修改构造函数,具体见附录。其的界面如下69 界面九69 5系统开发总结5.1结束语这个系统是在VC++6.0开发环境下,采用Dialogbased的应用程序框架。通过这次课程设计,我对数据库系统开发有了比较深入的了解。首先,领会到系统分析的重要性。如:系统功能模块分析和设计,数据库需求分析和设计,数据库概念结构设计(ER图)都在软件开发中占有相当重要的地位,在具体实现,编写软件之前,你必须花相当大的时间和精力去做系统分析,这是软件开发的实用性,可行性,安全性的前提和保证。其次,在详细设计过程中,通过边学习边实践,了解了Access的功能和使用,并认识了数据库理论在数据库系统开发过程中的应用。学会了数据源的建立和连接。本考勤管理系统记录了员工上下班,加班,请假和出差的情况,和实现统计功能后,可以和其他管理系统配套使用,例如,为工资管理系统直接提供每个月工作时间的统计结果,用以计算工资。同时考勤系统也需要其他系统提供的员工、部门等信息。通过这次的实践使我深刻地了解了这些管理系统软件的开发过程,为以后的学习和工作打下基础,同时也使我认识到开发经验的不足,希望在以后的学习中更上一层楼。69 参考文献[1]李闽溟,数据库系统开发实例导航,人民邮电出版社,2002[2]丁宝康,数据库原理,经济科学出版社,2000[3]陆丽娜,软件工程,经济科学出版社,2000[4]彭海河,VisualC++.net实例入门,海洋出版社,2002[5]赵仕健.VC++6.0编程与实例解析.北京:科学出版社,2000[6]康博创作室等编著.VisualC++6.0高级开发教程.人民邮电出版社[7]齐舒创作室编著.VisualC++6.0编程技巧与实例分析.中国水利水电出版社[8]官章全刘加明编著.VisualC++6.0类库大全.电子工业出版社[9]于乐.VisualC++开发现状[M].北京:机械出版社,2003.[10]BjarneStroustrupTheC++programminglanguage2ndedition[M][11]DavidJ.KruglinskiInsideVisualC++4thEdition.69 致谢感谢。。。。。。。。69 附录登录框代码:BOOLCLoginDlg::OnInitDialog(){CDialog::OnInitDialog();m_font.CreatePointFont(180,"华文彩云",NULL);GetDlgItem(IDC_STATIC_LOGINTEXT)->SetFont(&m_font,true);//如数据库为打开状态,则关闭if(db.IsOpen())db.Close();}在用户登陆过程的“登陆”按钮中添加下面的代码。voidCLoginDlg::OnOK(){//TODO:AddextravalidationhereBOOLbLogin=FALSE;CStringstrPasswd,strCount;UpdateData();//更新数据变量if(!db.Open(m_strDSN))return;//连接数据库strPasswd=CCrypt::Encrypt(m_strPasswd,123);//加密密码//MessageBox(strPasswd);CRecordsetrs(&db);//构造记录集rs.Open(CRecordset::forwardOnly,"selectCOUNT(ID)asCOUNTfromPERSONwhereID=""+m_strUser+""andPASSWD=""+strPasswd+""andAUTHORITY="4"");//执行查询rs.GetFieldValue("COUNT",strCount);rs.Close();//关闭数据集if(strCount=="1")//判断认证是否通过{EndDialog(IDOK);//结束对话框,返回IDOK}else{MessageBox("请确认用户名和密码,注意大小写!","认证失败");db.Close();//关闭数据库}//CDialog::OnOK();}为了先运行登录认证对话框,还需在App类的InitInstance()函数中加入以下代码://显示登录对话框69 CLoginDlgLoginDlg;if(LoginDlg.DoModal()!=IDOK)returnFALSE;主对话框窗体功能代码:在CAttendanceDlg中定义以下成员变量:classCAttendanceDlg:publicCDialog{//Constructionpublic:CBrushm_brush;CStatDlg*m_pStatDlg;CAttDlg*m_pAttDlg;CFontm_font;CAttendanceDlg(CWnd*pParent=NULL);在它的cpp文件下修改BOOLCAttendanceDlg::OnInitDialog(){CDialog::OnInitDialog();m_font.CreatePointFont(180,"华文彩云",NULL);GetDlgItem(IDC_STATIC_HEAD)->SetFont(&m_font,true);//初始化对话框指针为空m_pAttDlg=NULL;m_pStatDlg=NULL;5个按钮的功能代码如下voidCAttendanceDlg::OnBtnExit(){EndDialog(IDCANCEL);//退出主对话框,关闭程序}voidCAttendanceDlg::OnBtnRelogin(){//隐藏主对话框ShowWindow(SW_HIDE);//显示登录对话框CLoginDlgdlg;if(dlg.DoModal()==IDOK){ShowWindow(SW_SHOW);//显示对话框}elseEndDialog(IDCANCEL);//退出程序}voidCAttendanceDlg::OnBtnConfig()69 {//显示工作时间设置对话框CWorkplanDlgdlg;dlg.DoModal();}voidCAttendanceDlg::OnBtnRecord(){//非模态显示出勤记录对话框if(!m_pAttDlg)//指针为空,创建对话框{m_pAttDlg=newCAttDlg();m_pAttDlg->Create(IDD_DLG_ATTENDANCE,this);m_pAttDlg->ShowWindow(SW_SHOW);}else//对话框已创建m_pAttDlg->ShowWindow(SW_SHOW);//显示窗口}voidCAttendanceDlg::OnBtnStatistics(){//非模态显示考勤统计对话框if(!m_pStatDlg)//指针为空,创建对话框{m_pStatDlg=newCStatDlg();m_pStatDlg->Create(IDD_DLG_STAT,this);m_pStatDlg->ShowWindow(SW_SHOW);}else//对话框已创建m_pStatDlg->ShowWindow(SW_SHOW);//显示窗口}上班时间设置窗体的Cpp文件代码“修改”按钮代码:voidCWorkplanDlg::OnWorkplanModify(){//TODO:AddyourcontrolnotificationhandlercodehereCStringstrFileName=".\workplan.ini";//INI文件名UpdateData();//更新数据WritePrivateProfileString("WorkPlan","Time1",m_Time1.Format("%H:%M:%S"),strFileName);WritePrivateProfileString("WorkPlan","Time2",m_Time2.Format("%H:%M:%S"),strFileName);69 WritePrivateProfileString("WorkPlan","Time3",m_Time3.Format("%H:%M:%S"),strFileName);WritePrivateProfileString("WorkPlan","Time4",m_Time4.Format("%H:%M:%S"),strFileName);}初始化代码:BOOLCWorkplanDlg::OnInitDialog(){CDialog::OnInitDialog();//m_brush.CreateSolidBrush(RGB(0,0,255));OnWorkplanReset();//初始化时间设置returnTRUE;//returnTRUEunlessyousetthefocustoacontrol//EXCEPTION:OCXPropertyPagesshouldreturnFALSE}“恢复默认设置”按钮代码voidCWorkplanDlg::OnWorkplanReset(){//TODO:AddyourcontrolnotificationhandlercodehereCStringcstr[4];charstr[4][9];inti;intnHour,nMinute,nSecond;//时,分,秒CStringstrFileName=".\workplan.ini";//INI文件名//读取INI文件GetPrivateProfileString("WorkPlan","Time1","08:00:00",str[0],9,strFileName);GetPrivateProfileString("WorkPlan","Time2","12:00:00",str[1],9,strFileName);GetPrivateProfileString("WorkPlan","Time3","14:00:00",str[2],9,strFileName);GetPrivateProfileString("WorkPlan","Time4","18:00:00",str[3],9,strFileName);for(i=0;i<4;i++)cstr[i]=str[i];//定义四个时间变量并初始化为INI文件中的值sscanf(cstr[0].Left(2),"%d",&nHour);//得到时sscanf(cstr[0].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[0].Mid(6,2),"%d",&nSecond);//得到秒CTimet1(2002,1,1,nHour,nMinute,nSecond);//初始化t1sscanf(cstr[1].Left(2),"%d",&nHour);//得到时sscanf(cstr[1].Mid(3,2),"%d",&nMinute);//得到分69 sscanf(cstr[1].Mid(6,2),"%d",&nSecond);//得到秒CTimet2(2002,1,1,nHour,nMinute,nSecond);//初始化t2sscanf(cstr[2].Left(2),"%d",&nHour);//得到时sscanf(cstr[2].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[2].Mid(6,2),"%d",&nSecond);//得到秒CTimet3(2002,1,1,nHour,nMinute,nSecond);//初始化t3sscanf(cstr[3].Left(2),"%d",&nHour);//得到时sscanf(cstr[3].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[3].Mid(6,2),"%d",&nSecond);//得到秒CTimet4(2002,1,1,nHour,nMinute,nSecond);//初始化t4//设置成员变量m_Time1=t1;m_Time2=t2;m_Time3=t3;m_Time4=t4;UpdateData(FALSE);//更新界面数据} 考勤修改窗体代码:在头文件中的代码:classCAttDlg:publicCDialog{//Constructionpublic:CPage1m_Page1;//出勤页CPage2m_Page2;//加班页CPage3m_Page3;//请假页CPage4m_Page4;//出差页CPropertySheetm_Sheet;CAttDlg(CWnd*pParent=NULL);在cpp文件中:BOOLCAttDlg::OnInitDialog(){CDialog::OnInitDialog();//TODO:Addextrainitializationherem_Sheet.AddPage(&m_Page1);//加第1页m_Sheet.AddPage(&m_Page2);//加第2页m_Sheet.AddPage(&m_Page3);//加第3页m_Sheet.AddPage(&m_Page4);//加第4页69 m_Sheet.Create(this,WS_CHILD|WS_VISIBLE,0);//创建窗口m_Sheet.ModifyStyleEx(0,WS_EX_CONTROLPARENT);//修改风格m_Sheet.ModifyStyle(0,WS_TABSTOP);//修改风格//设置窗口位置m_Sheet.SetWindowPos(NULL,0,100,0,0,SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);returnTRUE;}voidCAttDlg::OnChangeEdtSeekpersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造记录集rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录集if(rs.GetRecordCount()==1)//判断员工记录是否存在{m_strName=rs.m_NAME;//得到员工姓名}elsem_strName.Empty();//清除员工姓名的显示rs.Close();//关闭记录集UpdateData(FALSE);//更新界面数据}添假出勤记录属性页page1初始化及各个按钮的代码:BOOLCPage1::OnInitDialog(){CPropertyPage::OnInitDialog();//出入情况缺省为出((CButton*)GetDlgItem(IDC_RADIO_OUT))->SetCheck(TRUE);//为List添加网格m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);//设置List的列intnWidth=110;m_cList.InsertColumn(0,"记录编号",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(1,"员工号",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(2,"出入情况",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(3,"时间",LVCFMT_LEFT,nWidth);CAttendanceRSrs(&db);//构造出勤记录表UpdateList(rs);//更新ListreturnTRUE;//returnTRUEunlessyousetthefocustoacontrol69 //EXCEPTION:OCXPropertyPagesshouldreturnFALSE}voidCPage1::UpdateList(CAttendanceRS&rs)//更新列表框内容{inti=0;CStringstrID,strTime;rs.Open();//打开出勤记录表m_cList.DeleteAllItems();//清除列表框内容while(!rs.IsEOF())//对数据表中所有记录进行处理{m_cList.InsertItem(i,"");//添加新ItemstrID.Format("%d",rs.m_ID);//转换为字符串m_cList.SetItemText(i,0,strID);m_cList.SetItemText(i,1,rs.m_PERSON);m_cList.SetItemText(i,2,rs.m_IN_OUT);m_cList.SetItemText(i,3,rs.m_IO_TIME.Format("%Y-%m-%d%H:%M"));rs.MoveNext();//跳到下一条记录i++;}rs.Close();//关闭出勤记录表}//添加出勤记录函数voidCPage1::IO_Add(CStringstrPersonID){intcounter;//用于计数CStringstrIO;//保存出入情况CCounterRSrs_counter(&db);//构造计数器记录表//记录编号rs_counter.m_strFilter="ID="A"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//添加记录//判断确定出入情况if(((CButton*)GetDlgItem(IDC_RADIO_OUT))->GetCheck())strIO="O";elsestrIO="I";//转换出入时间类型intnYear,nMonth,nDay,nHour,nMinute;//年,月,日,时,分sscanf(m_strIOTime.Left(4),"%d",&nYear);//得到年69 sscanf(m_strIOTime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strIOTime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strIOTime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strIOTime.Mid(14,2),"%d",&nMinute);//得到分//得到出入时间CTimeIO_time(nYear,nMonth,nDay,nHour,nMinute,0);CAttendanceRSrs_attendance(&db);//构造考勤记录表rs_attendance.Open();//打开考勤记录表rs_attendance.AddNew();//追加考勤记录rs_attendance.m_ID=counter;rs_attendance.m_PERSON=strPersonID;rs_attendance.m_IN_OUT=strIO;rs_attendance.m_IO_TIME=IO_time;rs_attendance.Update();rs_attendance.Close();//关闭考勤记录表UpdateList(rs_attendance);//更新列表框}voidCPage1::OnBtnAddall()//添加所有员工出勤记录{inti,n;//用于保存记录条数CPersonRSrs_person(&db);//构造员工信息表//设置过滤条件,提取员工列表rs_person.m_strFilter="STATE="T"";rs_person.Open();//打开员工信息表n=rs_person.GetRecordCount();//获取员工人数i=0;//初始化已添加记录条数//初始化进度条m_cProgress.SetRange(0,n);m_cProgress.SetPos(0);while(!rs_person.IsEOF())//对数据表中所有记录进行处理{IO_Add(rs_person.m_ID);//添加当前员工出勤记录rs_person.MoveNext();//跳到下一个员工记录m_cProgress.SetPos(++i);//显示进度}rs_person.Close();//关闭员工信息表}voidCPage1::OnBtnAdddepart()//追加部门员工考勤记录{inti,n;//用于保存记录条数CPersonRSrs_person(&db);//构造员工信息表69 if(m_strDepartName.IsEmpty())return;//判断部门代号是否正确//设置过滤条件rs_person.m_strFilter="DEPARTMENT=""+m_strDepartID+""andSTATE="T"";rs_person.Open();//打开员工信息表n=rs_person.GetRecordCount();//获取员工人数i=0;//初始化已添加记录条数//初始化进度条m_cProgress.SetRange(0,n);m_cProgress.SetPos(0);while(!rs_person.IsEOF())//对数据表中所有记录进行处理{IO_Add(rs_person.m_ID);//添加当前员工出勤记录rs_person.MoveNext();//跳到下一个员工记录m_cProgress.SetPos(++i);//显示进度}rs_person.Close();//关闭员工信息表}voidCPage1::OnBtnAddperson()//追加单个员工考勤记录{if(!m_strPersonName.IsEmpty())//判断员工是否存在{IO_Add(m_strPersonID);//追加单个员工记录}}voidCPage1::OnBtnDeleteattend()//删除出勤记录列表中所选记录{CStringstrSQL;intnItem;//得到第一个被选择Item的位置POSITIONpos=m_cList.GetFirstSelectedItemPosition();if(pos==NULL){AfxMessageBox("没有选择记录!");return;}while(pos)//遍历所有被选Item{nItem=m_cList.GetNextSelectedItem(pos);//得到ItemIndex69 //构造SQL语句strSQL="deletefromATTENDANCEwhereID="+m_cList.GetItemText(nItem,0);db.ExecuteSQL(strSQL);//执行}CAttendanceRSrs(&db);//构造出勤记录表UpdateList(rs);//更新列表框}voidCPage1::OnBtnSeekio(){CAttendanceRSrs(&db);//构造出勤记录表CAttDlg*pDlg;//指向包含本对象的CAttDlg的指针CStringstrFilter;//用于保存过滤字符串CStringstrSTime,strETime;//起始,结束时间pDlg=(CAttDlg*)GetParent()->GetParent();//得到指针pDlg->UpdateData();//更新数据strSTime=pDlg->m_StartTime.Format("%Y-%m-%d");strETime=pDlg->m_EndTime.Format("%Y-%m-%d");if(pDlg->m_bSeekbyperson)//判断是否根据员工号检索strFilter="PERSON=""+pDlg->m_strPersonID+""";//添加过滤条件if(pDlg->m_bSeekbytime)//判断是否有时间范围{if(strFilter.GetLength()>0)//判断是否已有过滤条件strFilter+="and";//如果是,需要添加and连接符strFilter+="IO_TIME>#"+strSTime+"#";//添加开始时间过滤strFilter+="andIO_TIME<#"+strETime+"#";//添加结束时间过滤}if(strFilter.GetLength()>0)//判断是否有过滤条件rs.m_strFilter=strFilter;//设置FilterUpdateList(rs);//更新列表框}voidCPage1::OnChangeEdtDepartid(){UpdateData();//更新数据CDepartRSrs(&db);//构造记录集rs.m_strFilter="ID=""+m_strDepartID+""";//设置过滤条件69 rs.Open();//打开记录集if(rs.GetRecordCount()==1)//判断部门代码输入是否正确{m_strDepartName=rs.m_NAME;//提取部门名称}elsem_strDepartName.Empty();//清除部门名称rs.Close();//关闭记录集UpdateData(FALSE);//更新界面数据//TODO:IfthisisaRICHEDITcontrol,thecontrolwillnot//sendthisnotificationunlessyouoverridetheCDialog::OnInitDialog()//functionandcallCRichEditCtrl().SetEventMask()//withtheENM_CHANGEflagORedintothemask.//TODO:Addyourcontrolnotificationhandlercodehere}voidCPage1::OnChangeEdtPersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造PERSON记录表rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录表if(rs.GetRecordCount()==1)//判断员工号是否正确{m_strPersonName=rs.m_NAME;//提取员工姓名m_strDepartID=rs.m_DEPARTMENT;//提取员工所在部门编号}elsem_strPersonName.Empty();//清除员工姓名显示rs.Close();//关闭记录表UpdateData(FALSE);//更新界面数据OnChangeEdtDepartid();//显示部门名称}加班记录属性页功能page2代码BOOLCPage2::OnInitDialog(){CPropertyPage::OnInitDialog();//为List添加网格m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);//设置List的列intnWidth=110;69 m_cList.InsertColumn(0,"记录编号",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(1,"员工号",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(2,"加班时间",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(3,"加班日期",LVCFMT_LEFT,nWidth);COvertimeRSrs(&db);//构造加班记录表UpdateList(rs);//更新ListreturnTRUE;//returnTRUEunlessyousetthefocustoacontrol//EXCEPTION:OCXPropertyPagesshouldreturnFALSE}voidCPage2::UpdateList(COvertimeRS&rs){inti=0;CStringstrID,strWorkHours,strTime;rs.Open();//打开加班记录表m_cList.DeleteAllItems();//清除列表框内容while(!rs.IsEOF())//对数据表中所有记录进行处理{m_cList.InsertItem(i,"");//添加新ItemstrID.Format("%d",rs.m_ID);//转换为字符串m_cList.SetItemText(i,0,strID);m_cList.SetItemText(i,1,rs.m_PERSON);strWorkHours.Format("%d",rs.m_WORK_HOURS);m_cList.SetItemText(i,2,strWorkHours);m_cList.SetItemText(i,3,rs.m_WORK_DATE.Format("%Y-%m-%d"));rs.MoveNext();//跳到下一条记录i++;}rs.Close();//关闭加班记录表}voidCPage2::OnChangeEdtOvertimePersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造PERSON记录表rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录表if(rs.GetRecordCount()==1)//判断员工号是否正确{m_strPersonName=rs.m_NAME;//提取员工姓名}elsem_strPersonName.Empty();//清除员工姓名显示rs.Close();//关闭记录表69 UpdateData(FALSE);//更新界面数据}voidCPage2::OnBtnOvertimeAdd(){intcounter;//用于保存计数CCounterRSrs_counter(&db);//构造计数器记录表UpdateData();//更新数据if(m_strPersonName.IsEmpty())return;//判断员工号是否正确//记录编号rs_counter.m_strFilter="ID="O"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//添加记录COvertimeRSrs_overtime(&db);//构造加班记录表rs_overtime.Open();//打开表rs_overtime.AddNew();//新增一项记录//设置字段值rs_overtime.m_ID=counter;rs_overtime.m_PERSON=m_strPersonID;rs_overtime.m_WORK_HOURS=m_nHour;rs_overtime.m_WORK_DATE=m_Date;rs_overtime.Update();//更新数据库rs_overtime.Close();//关闭加班记录表UpdateList(rs_overtime);//更新列表框}voidCPage2::OnBtnOvertimeDeleteattend(){CStringstrSQL;intnItem;//得到第一个被选择Item的位置POSITIONpos=m_cList.GetFirstSelectedItemPosition();if(pos==NULL){AfxMessageBox("没有选择记录!");return;}69 while(pos)//遍历所有被选Item{nItem=m_cList.GetNextSelectedItem(pos);//得到ItemIndex//构造SQL语句strSQL="deletefromOVERTIMEwhereID="+m_cList.GetItemText(nItem,0);db.ExecuteSQL(strSQL);//执行}COvertimeRSrs(&db);//构造加班记录表UpdateList(rs);//更新列表框}voidCPage2::OnBtnOvertimeSeekio(){COvertimeRSrs(&db);//构造加班记录表CAttDlg*pDlg;//指向包含本对象的CAttDlg的指针CStringstrFilter;//用于保存过滤字符串CStringstrSTime,strETime;//起始,结束时间pDlg=(CAttDlg*)GetParent()->GetParent();//得到指针pDlg->UpdateData();//更新数据strSTime=pDlg->m_StartTime.Format("%Y-%m-%d");strETime=pDlg->m_EndTime.Format("%Y-%m-%d");if(pDlg->m_bSeekbyperson)//判断是否根据员工号检索strFilter="PERSON=""+pDlg->m_strPersonID+""";//添加过滤条件if(pDlg->m_bSeekbytime)//判断是否有时间范围{if(strFilter.GetLength()>0)//判断是否已有过滤条件strFilter+="and";//如果是,需要添加and连接符strFilter+="WORK_DATE>#"+strSTime+"#";//添加开始时间过滤strFilter+="andWORK_DATE<#"+strETime+"#";//添加结束时间过滤}if(strFilter.GetLength()>0)//判断是否有过滤条件rs.m_strFilter=strFilter;//设置FilterUpdateList(rs);//更新列表框}请假属性页功能page3代码BOOLCPage3::OnInitDialog(){CPropertyPage::OnInitDialog();69 //为List添加网格m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);//设置List的列intnWidth=90;m_cList.InsertColumn(0,"记录编号",LVCFMT_LEFT,nWidth-20);m_cList.InsertColumn(1,"员工号",LVCFMT_LEFT,nWidth-20);m_cList.InsertColumn(2,"开始时间",LVCFMT_LEFT,nWidth+20);m_cList.InsertColumn(3,"结束时间",LVCFMT_LEFT,nWidth+20);m_cList.InsertColumn(4,"缘由",LVCFMT_LEFT,nWidth);CLeaveRSrs(&db);//构造请假记录表UpdateList(rs);//更新ListreturnTRUE;//returnTRUEunlessyousetthefocustoacontrol}voidCPage3::UpdateList(CLeaveRS&rs){inti=0;CStringstrID,strSTime,strETime;rs.Open();//打开请假记录表m_cList.DeleteAllItems();//清除列表框内容while(!rs.IsEOF())//对数据表中所有记录进行处理{m_cList.InsertItem(i,"");//添加新ItemstrID.Format("%d",rs.m_ID);//转换为字符串m_cList.SetItemText(i,0,strID);m_cList.SetItemText(i,1,rs.m_PERSON);strSTime=rs.m_START_TIME.Format("%y-%m-%d%H:%M");m_cList.SetItemText(i,2,strSTime);strETime=rs.m_END_TIME.Format("%y-%m-%d%H:%M");m_cList.SetItemText(i,3,strETime);m_cList.SetItemText(i,4,rs.m_REASON);rs.MoveNext();//跳到下一条记录i++;}rs.Close();//关闭记录表}voidCPage3::OnChangeEdtLeavePersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造PERSON记录表rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录表if(rs.GetRecordCount()==1)//判断员工号是否正确69 {m_strPersonName=rs.m_NAME;//提取员工姓名}elsem_strPersonName.Empty();//清除员工姓名显示rs.Close();//关闭记录表UpdateData(FALSE);//更新界面数据}voidCPage3::OnBtnLeaveAdd(){intcounter;//用于计数CCounterRSrs_counter(&db);//构造计数器记录表UpdateData();//更新数据//记录编号rs_counter.m_strFilter="ID="L"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//添加记录intnYear,nMonth,nDay,nHour,nMinute;//年,月,日,时,分//转换起始时间类型sscanf(m_strSTime.Left(4),"%d",&nYear);//得到年sscanf(m_strSTime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strSTime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strSTime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strSTime.Mid(14,2),"%d",&nMinute);//得到分//得到起始时间CTimeS_time(nYear,nMonth,nDay,nHour,nMinute,0);//转换结束时间类型sscanf(m_strETime.Left(4),"%d",&nYear);//得到年sscanf(m_strETime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strETime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strETime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strETime.Mid(14,2),"%d",&nMinute);//得到分//得到结束时间CTimeE_time(nYear,nMonth,nDay,nHour,nMinute,0);CLeaveRSrs_leave(&db);//构造请假记录表rs_leave.Open();//打开请假记录表69 rs_leave.AddNew();//追加请假记录rs_leave.m_ID=counter;rs_leave.m_PERSON=m_strPersonID;rs_leave.m_START_TIME=S_time;rs_leave.m_END_TIME=E_time;rs_leave.m_REASON=m_strReason;rs_leave.Update();rs_leave.Close();//关闭请假记录表UpdateList(rs_leave);//更新列表框}voidCPage3::OnBtnLeaveDeleteattend(){CStringstrSQL;intnItem;//得到第一个被选择Item的位置POSITIONpos=m_cList.GetFirstSelectedItemPosition();if(pos==NULL){AfxMessageBox("没有选择记录!");return;}while(pos)//遍历所有被选Item{nItem=m_cList.GetNextSelectedItem(pos);//得到ItemIndex//构造SQL语句strSQL="deletefromLEAVEwhereID="+m_cList.GetItemText(nItem,0);db.ExecuteSQL(strSQL);//执行}CLeaveRSrs(&db);//构造请假记录表UpdateList(rs);//更新列表框//TODO:Addyourcontrolnotificationhandlercodehere}voidCPage3::OnBtnLeaveSeekio(){CLeaveRSrs(&db);//构造请假记录表CAttDlg*pDlg;//指向包含本对象的CAttDlg的指针CStringstrFilter;//用于保存过滤字符串CStringstrSTime,strETime;//起始,结束时间pDlg=(CAttDlg*)GetParent()->GetParent();//得到指针pDlg->UpdateData();//更新数据69 strSTime=pDlg->m_StartTime.Format("%Y-%m-%d");strETime=pDlg->m_EndTime.Format("%Y-%m-%d");if(pDlg->m_bSeekbyperson)//判断是否根据员工号检索strFilter="PERSON=""+pDlg->m_strPersonID+""";//添加过滤条件if(pDlg->m_bSeekbytime)//判断是否有时间范围{if(strFilter.GetLength()>0)//判断是否已有过滤条件strFilter+="and";//如果是,需要添加and连接符strFilter+="END_TIME>#"+strSTime+"#";//添加开始时间过滤strFilter+="andSTART_TIME<#"+strETime+"#";//添加结束时间过滤}if(strFilter.GetLength()>0)//判断是否有过滤条件rs.m_strFilter=strFilter;//设置FilterUpdateList(rs);//更新列表框}出差属性页功能page4代码BOOLCPage4::OnInitDialog(){CPropertyPage::OnInitDialog();//为List添加网格m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);//设置List的列intnWidth=90;m_cList.InsertColumn(0,"记录编号",LVCFMT_LEFT,nWidth-20);m_cList.InsertColumn(1,"员工号",LVCFMT_LEFT,nWidth-20);m_cList.InsertColumn(2,"开始时间",LVCFMT_LEFT,nWidth+20);m_cList.InsertColumn(3,"结束时间",LVCFMT_LEFT,nWidth+20);m_cList.InsertColumn(4,"具体描述",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(5,"考勤代理人信息",LVCFMT_LEFT,nWidth);CErrandRSrs(&db);//构造出差记录表UpdateList(rs);//更新ListreturnTRUE;//returnTRUEunlessyousetthefocustoacontrol//EXCEPTION:OCXPropertyPagesshouldreturnFALSE}voidCPage4::UpdateList(CErrandRS&rs){inti=0;CStringstrID,strSTime,strETime;rs.Open();//打开出差记录表m_cList.DeleteAllItems();//清除列表框内容69 while(!rs.IsEOF())//对数据表中所有记录进行处理{m_cList.InsertItem(i,"");//添加新ItemstrID.Format("%d",rs.m_ID);//转换为字符串m_cList.SetItemText(i,0,strID);m_cList.SetItemText(i,1,rs.m_PERSON);strSTime=rs.m_START_TIME.Format("%y-%m-%d%H:%M");m_cList.SetItemText(i,2,strSTime);strETime=rs.m_END_TIME.Format("%y-%m-%d%H:%M");m_cList.SetItemText(i,3,strETime);m_cList.SetItemText(i,4,rs.m_DESCRIPTION);///m_cList.SetItemText(i,5,rs.m_AGENTPERSON);rs.MoveNext();//跳到下一条记录i++;}rs.Close();//关闭出差记录表}voidCPage4::OnChangeEdtErrandPersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造PERSON记录表rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录表if(rs.GetRecordCount()==1)//判断员工号是否正确{m_strPersonName=rs.m_NAME;//提取员工姓名}elsem_strPersonName.Empty();//清除员工姓名显示rs.Close();//关闭记录表UpdateData(FALSE);//更新界面数据}voidCPage4::OnBtnErrandAdd(){intcounter;//用于计数CCounterRSrs_counter(&db);//构造计数器记录表UpdateData();//更新数据//记录编号rs_counter.m_strFilter="ID="E"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加169 rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//添加记录intnYear,nMonth,nDay,nHour,nMinute;//年,月,日,时,分//转换起始时间类型sscanf(m_strSTime.Left(4),"%d",&nYear);//得到年sscanf(m_strSTime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strSTime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strSTime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strSTime.Mid(14,2),"%d",&nMinute);//得到分//得到起始时间CTimeS_time(nYear,nMonth,nDay,nHour,nMinute,0);//转换结束时间类型sscanf(m_strETime.Left(4),"%d",&nYear);//得到年sscanf(m_strETime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strETime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strETime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strETime.Mid(14,2),"%d",&nMinute);//得到分//得到结束时间CTimeE_time(nYear,nMonth,nDay,nHour,nMinute,0);CErrandRSrs_errand(&db);//构造出差记录表rs_errand.Open();//打开出差记录表rs_errand.AddNew();//追加出差记录rs_errand.m_ID=counter;rs_errand.m_PERSON=m_strPersonID;rs_errand.m_START_TIME=S_time;rs_errand.m_END_TIME=E_time;rs_errand.m_DESCRIPTION=m_strDescription;rs_errand.Update();rs_errand.Close();//关闭出差记录表UpdateList(rs_errand);//更新列表框}voidCPage4::OnBtnErrandDeleteattend(){CStringstrSQL;intnItem;//得到第一个被选择Item的位置POSITIONpos=m_cList.GetFirstSelectedItemPosition();if(pos==NULL)69 {AfxMessageBox("没有选择记录!");return;}while(pos)//遍历所有被选Item{nItem=m_cList.GetNextSelectedItem(pos);//得到ItemIndex//构造SQL语句strSQL="deletefromERRANDwhereID="+m_cList.GetItemText(nItem,0);db.ExecuteSQL(strSQL);//执行}CErrandRSrs(&db);//构造出差记录表UpdateList(rs);//更新列表框}voidCPage4::OnBtnErrandSeekio(){CErrandRSrs(&db);//构造出差记录表CAttDlg*pDlg;//指向包含本对象的CAttDlg的指针CStringstrFilter;//用于保存过滤字符串CStringstrSTime,strETime;//起始,结束时间pDlg=(CAttDlg*)GetParent()->GetParent();//得到指针pDlg->UpdateData();//更新数据strSTime=pDlg->m_StartTime.Format("%Y-%m-%d");strETime=pDlg->m_EndTime.Format("%Y-%m-%d");if(pDlg->m_bSeekbyperson)//判断是否根据员工号检索strFilter="PERSON=""+pDlg->m_strPersonID+""";//添加过滤条件if(pDlg->m_bSeekbytime)//判断是否有时间范围{if(strFilter.GetLength()>0)//判断是否已有过滤条件strFilter+="and";//如果是,需要添加and连接符strFilter+="END_TIME>#"+strSTime+"#";//添加开始时间过滤strFilter+="andSTART_TIME<#"+strETime+"#";//添加结束时间过滤}if(strFilter.GetLength()>0)//判断是否有过滤条件rs.m_strFilter=strFilter;//设置FilterUpdateList(rs);//更新列表框}69 考勤统计模块功能代码:修改构造函数如下:CStatDlg::CStatDlg(CWnd*pParent/*=NULL*/):CDialog(CStatDlg::IDD,pParent){CTimeEnd_t=CTime::GetCurrentTime();//当前时间CTimeSpantp(30,0,0,0);//时间间隔为30天//{{AFX_DATA_INIT(CStatDlg)m_strTime=End_t.Format("%Y-%m");m_bSeekbytime=FALSE;m_bSeekbyperson=FALSE;m_strPersonID=_T("");m_strPersonName=_T("");m_STime=End_t-tp;m_ETime=End_t;m_strSeektime=_T("");//}}AFX_DATA_INIT}初始化函数BOOLCStatDlg::OnInitDialog(){CDialog::OnInitDialog();//为List添加网格m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);//设置List的列intnWidth=100;m_cList.InsertColumn(0,"记录编号",LVCFMT_LEFT,80);m_cList.InsertColumn(1,"员工号",LVCFMT_LEFT,50);m_cList.InsertColumn(2,"年月",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(3,"正常工作时间(小时)",LVCFMT_LEFT,nWidth+40);m_cList.InsertColumn(4,"加班时间(小时)",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(5,"请假时间(半天)",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(6,"出差时间(半天)",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(7,"迟到次数",LVCFMT_LEFT,nWidth-30);m_cList.InsertColumn(8,"早退次数",LVCFMT_LEFT,nWidth-30);m_cList.InsertColumn(9,"旷工次数",LVCFMT_LEFT,nWidth-30);CStatRSrs(&db);//构造出勤记录表UpdateList(rs);//更新ListreturnTRUE;//returnTRUEunlessyousetthefocustoacontrol//EXCEPTION:OCXPropertyPagesshouldreturnFALSE}更新列表函数69 voidCStatDlg::UpdateList(CStatRS&rs){inti=0;CStringstr;rs.Open();//打开统计数据表m_cList.DeleteAllItems();//清除列表框内容while(!rs.IsEOF())//对数据表中所有记录进行处理{m_cList.InsertItem(i,"");//添加新Itemstr.Format("%d",rs.m_ID);//转换为字符串m_cList.SetItemText(i,0,str);m_cList.SetItemText(i,1,rs.m_PERSON);m_cList.SetItemText(i,2,rs.m_YEAR_MONTH);str.Format("%d",rs.m_WORK_HOUR);m_cList.SetItemText(i,3,str);str.Format("%d",rs.m_OVER_HOUR);m_cList.SetItemText(i,4,str);str.Format("%d",rs.m_LEAVE_HDAY);m_cList.SetItemText(i,5,str);str.Format("%d",rs.m_ERRAND_HDAY);m_cList.SetItemText(i,6,str);str.Format("%d",rs.m_LATE_TIMES);m_cList.SetItemText(i,7,str);str.Format("%d",rs.m_EARLY_TIMES);m_cList.SetItemText(i,8,str);str.Format("%d",rs.m_ABSENT_TIMES);m_cList.SetItemText(i,9,str);rs.MoveNext();//跳到下一条记录i++;}rs.Close();//关闭统计数据表}voidCStatDlg::OnChangeStatEdtSeekpersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造记录集rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录集if(rs.GetRecordCount()==1)//判断员工记录是否存在{m_strPersonName=rs.m_NAME;//得到员工姓名}69 elsem_strPersonName.Empty();//清除员工姓名的显示rs.Close();//关闭记录集UpdateData(FALSE);//更新界面数据}voidCStatDlg::OnStatBtnSeek(){CStringstrFilter;//保存过滤字符串CStatRSrs(&db);//构造统计数据表UpdateData();//更新数据//判断根据员工号过滤if(m_bSeekbyperson)strFilter="PERSON=""+m_strPersonID+""";//判断根据年月过滤if(m_bSeekbytime){if(!strFilter.IsEmpty())//如果已有过滤条件strFilter+="and";//需添加and连接符//设置时间过滤条件strFilter+="YEAR_MONTH=#"+m_strSeektime+"#";}if(!strFilter.IsEmpty())//判断是否有过滤字符串{rs.m_strFilter=strFilter;//设置过滤条件}UpdateList(rs);//更新列表框}月度统计voidCStatDlg::OnStatBtnStat(){CRecordsetrs_Q_attend(&db);//构造Q_attend记录集CRecordsetrs_Q_leave(&db);//构造Q_leave记录集CRecordsetrs_Q_errand(&db);//构造Q_errand记录集CTimeSpantp_1(1,0,0,0);//构造一个1天的CTimeSpanCTimeSpantp_02(0,2,0,0);//构造一个2小时的CTimeSpanCTimeSpanTimeSpan[4];//保存上下班时间intnHours[2];//保存上下午工作时间CStringstrSTime,strETime;//保存始末时间CTimeTimeStamp,LateTime,EarlyTime,WorkStart,WorkEnd;//保存中间判断时间intnWorkHour,nOverHour,nLeaveHDay,nErrandHDay;//保存时间间隔长度BOOLbLate,bEarly,bAbsent,bLeave,bErrand;//保存判断结果intnLateTimes,nEarlyTimes,nAbsentTimes;//保存次数CStringcstr[4];//暂存起始时间69 charstr[4][9];//暂存起始时间inti,j,n,counter;//用于循环和计数CStringstrTmp,strTmp1,strTmp2;//临时变量//临时变量,年,月,日,时,分,秒intnHour,nMinute,nSecond;CStringstrFileName=".\workplan.ini";//INI文件名UpdateData();//更新数据//读取INI文件GetPrivateProfileString("WorkPlan","Time1","08:00:00",str[0],9,strFileName);GetPrivateProfileString("WorkPlan","Time2","12:00:00",str[1],9,strFileName);GetPrivateProfileString("WorkPlan","Time3","14:00:00",str[2],9,strFileName);GetPrivateProfileString("WorkPlan","Time4","18:00:00",str[3],9,strFileName);for(i=0;i<4;i++)cstr[i]=str[i];//定义四个时间间隔变量并初始化为INI文件中的值CTimeSpan*pTS;for(i=0;i<4;i++){sscanf(cstr[i].Left(2),"%d",&nHour);//得到时sscanf(cstr[i].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[i].Mid(6,2),"%d",&nSecond);//得到秒//构造一个时间间隔变量pTS=newCTimeSpan(0,nHour,nMinute,nSecond);TimeSpan[i]=*pTS;//赋值deletepTS;}nHours[0]=(TimeSpan[1]-TimeSpan[0]).GetTotalHours();//计算上午工作时间if((TimeSpan[1]-TimeSpan[0]).GetMinutes()>30)nHours[0]++;//四舍五入nHours[1]=(TimeSpan[3]-TimeSpan[2]).GetTotalHours();//计算下午工作时间if((TimeSpan[3]-TimeSpan[2]).GetMinutes()>30)nHours[1]++;//四舍五入//转换统计开始时间strSTime="#"+m_STime.Format("%Y-%m-%d")+"#";//转换统计结束时间,且天数加1strETime="#"+(m_ETime+tp_1).Format("%Y-%m-%d")+"#";//提取员工列表CPersonRSrs_person(&db);//构造员工表rs_person.m_strFilter="STATE="T"";//设置过滤器,提取员工列表rs_person.Open();//打开员工表n=rs_person.GetRecordCount();//记录员工人数69 i=0;//初始化已处理员工人数m_cProgress.SetRange(0,n);//设置进度条m_cProgress.SetPos(0);//初始化进度条while(!rs_person.IsEOF())//依次对每个员工进行统计{//获取出勤记录//执行查询rs_Q_attend.Open(CRecordset::forwardOnly,"selectIN_OUT,IO_TIMEfromATTENDANCEwherePERSON=""+rs_person.m_ID+""andIO_TIME>"+strSTime+"andIO_TIME<"+strETime+"orderbyIO_TIME");strTmp1.Empty();//清空strTmp1//初始化nWorkHour=nOverHour=0;nLeaveHDay=nErrandHDay=0;nLateTimes=nEarlyTimes=nAbsentTimes=0;TimeStamp=m_STime;//初始化时间戳为统计开始时间while(TimeStamp#"+EarlyTime.Format("%Y-%m-%d%H:%M:%S")+"#");bLeave=(rs_Q_leave.GetRecordCount()>0);//判断是否有请假记录rs_Q_leave.Close();//关闭记录集//判断是否出差rs_Q_errand.Open(CRecordset::forwardOnly,"selectIDfromERRANDwherePERSON=""+rs_person.m_ID69 +""andSTART_TIME<#"+LateTime.Format("%Y-%m-%d%H:%M:%S")+"#andEND_TIME>#"+EarlyTime.Format("%Y-%m-%d%H:%M:%S")+"#");bErrand=(rs_Q_errand.GetRecordCount()>0);//判断是否有出差记录rs_Q_errand.Close();//关闭记录集if(bLeave)//如果有请假记录nLeaveHDay++;//请假记录加1elseif(bErrand)//如果有出差记录{nErrandHDay++;//出差计数加1nWorkHour+=nHours[j];//按正常班累加工作时间}else//正常上班{WorkStart=LateTime;//设置工作开始时间WorkEnd=EarlyTime;//设置工作结束时间bLate=TRUE;//初始化迟到判断bAbsent=FALSE;//初始化旷工判断//判断是否迟到if(!rs_Q_attend.IsEOF()&&//记录集不空strTmp1.IsEmpty())//空,第一次GetFieldValuers_Q_attend.GetFieldValue("IO_TIME",strTmp1);//得到IO_TIMEwhile(!rs_Q_attend.IsEOF()&&StrToTime(strTmp1)<=LateTime){//根据时间顺序判断是否迟到//得到IN_OUTrs_Q_attend.GetFieldValue("IN_OUT",strTmp2);bLate=(strTmp2=="O");//判断上班时间前是否报到rs_Q_attend.MoveNext();//跳到下一条出勤记录//得到IO_TIMEif(!rs_Q_attend.IsEOF())rs_Q_attend.GetFieldValue("IO_TIME",strTmp1);}//判断是否旷工if(bLate)//判断是否迟到{if(!rs_Q_attend.IsEOF()&&StrToTime(strTmp1)30)nWorkHour++;//四舍五入}}}//Endof遍历班次}//Endof是否工作日TimeStamp+=tp_1;//推进一天}//EndofTimeStamp#"+m_STime.Format("%Y-%m-%d%H:%M:%S")+"#andWORK_DATE<#"+m_ETime.Format("%Y-%m-%d%H:%M:%S")+"#");if(rs_Q_overtime.GetRecordCount()>0)//有记录{//提取加班时间rs_Q_overtime.GetFieldValue("SUM",strTmp);sscanf(strTmp,"%d",&nOverHour);}elsenOverHour=0;//无记录rs_Q_overtime.Close();//判断是否已有该月考勤记录CStatRSrs_stat(&db);//构造统计数据表//设置过滤串rs_stat.m_strFilter="PERSON=""+rs_person.m_ID+""andYEAR_MONTH=""+m_strTime+""";rs_stat.Open();//打开数据表if(rs_stat.GetRecordCount()==0)//判断是否有该月份考勤记录{//获取计数CCounterRSrs_counter(&db);//构造计数器表rs_counter.m_strFilter="ID="S"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//追加统计记录rs_stat.AddNew();rs_stat.m_ID=counter;rs_stat.m_YEAR_MONTH=m_strTime;rs_stat.m_PERSON=rs_person.m_ID;rs_stat.m_WORK_HOUR=nWorkHour;rs_stat.m_OVER_HOUR=nOverHour;rs_stat.m_LEAVE_HDAY=nLeaveHDay;rs_stat.m_ERRAND_HDAY=nErrandHDay;rs_stat.m_LATE_TIMES=nLateTimes;rs_stat.m_EARLY_TIMES=nEarlyTimes;69 rs_stat.m_ABSENT_TIMES=nAbsentTimes;rs_stat.Update();//提交修改}else{//记录已存在修改数据rs_stat.Edit();rs_stat.m_WORK_HOUR=nWorkHour;rs_stat.m_OVER_HOUR=nOverHour;rs_stat.m_LEAVE_HDAY=nLeaveHDay;rs_stat.m_ERRAND_HDAY=nErrandHDay;rs_stat.m_LATE_TIMES=nLateTimes;rs_stat.m_EARLY_TIMES=nEarlyTimes;rs_stat.m_ABSENT_TIMES=nAbsentTimes;rs_stat.Update();//提交修改}rs_stat.Close();//关闭数据表i++;//已统计员工数加1m_cProgress.SetPos(i);//显示统计进度rs_person.MoveNext();//跳到下一个员工记录}rs_person.Close();//关闭员工表CStatRSrs_stat(&db);//构造统计数据表UpdateList(rs_stat);//更新列表框}69