公司的中控指纹考勤机使用多年了,天天签到签出,从未想过它与IT何干(可能不喜欢被考勤机约制?),这天负责考勤的小伙说:可否用USB线将其8楼的电脑与一楼的考勤机连接,以便随时掌握考勤情况。

   用USB连接?异想天开:他的电脑与考勤机直线距离十几米,就算可以连接还要穿墙打洞的,工程预算可以买好几个考勤机了。但是可能有其他办法,如网络接口...,网上一查果然其中一项参数为:

                  通讯方式USB Device,RS232/485,TCP/IP

   我们的考勤机为中控U260指纹考勤机,考勤机安装在一楼大厅,大厅内敷设有网线连至公司局域网。基本条件已具备,开始考勤机开发第一步。


   1 考勤机入网

   从联网角度说,考勤机就是一台简陋的电脑(哑终端),只要正确地设置了IP,别人就能访问它。


   1.1 考勤机设置

在考勤机键盘上按 Menu 键进入机器的菜单项,液晶屏上显示信息如下:

145601887.jpg

145422162.jpg


   1.2 设置考勤管理软件

  考勤软件为中控《ZKTime5.0考勤管理系统》,中控考勤管理软件有好几个版本,核心部件(数据库结构、考勤机驱动、接口)都相同,只是升级改进了报表。考勤管理软件要取得考勤数据(签到、签出)需要取得考勤机IP地址。

153345788.jpg


尝试连接考勤机:

153903778.jpg

连接成功。

   闲着没事,看着考勤员操作考勤管理软件,当看到请假单处理过程时,我很意外:它不恰当地综合了多种数据处理方式:

员工在OA上录入假单-->考勤员打印纸质假单-->考勤员在考勤软件上手工录入假单


   还要打印纸质假单?为什么不直接导入假单数据?退一步,用复制粘贴也行呀!

   无奈,考勤软件录入请假单过程全部为导向式鼠标操作,复制粘贴碎片太多,不提供导入功能,杜绝了数据录入错误,也杜绝了大家"投机取巧"的念头。

   观察了一下考勤管理系统,虽然其处理程序已封装编译,但其数据库是access,决定从access入手,探索将OA电子假单导入途径。



   2. 假单导入

   2.1 考勤管理系统数据结构

175708879.jpg

《ZKTime5.0考勤管理系统》access数据结构见上图,《部门编码》、《员工资料》、《假别编码》为静态数据。《签到签出》为来自于考勤机的考勤记录,是《考勤报表》的主要数据,《假单》来自于考勤管理员手工录入,是《考勤报表》的辅助数据。


   2.2考勤假单结构

   user_spedat《假单》是我们关注的主要对象,只要将OA电子假单导入user_spedat即大功告成。下面我们考察一下user_spedat的数据在考勤系统中是怎样产生的。

   在考勤系统我们录入下面两条原始假单:

姓名假别起始时间结束时间请假原因
刘工补休2013-07-08 08:302013-07-12 17:3000170
严工事假2013-07-15 08:302013-07-15 09:3000171

表1 原始假单


   在access下观察user_spedat表增加了6条记录:

USER_SPEDAY假单

员工ID起始时间结束时间假别ID原因制单日期
USERIDSTARTSPECDAYENDSPECDAYDATEIDYUANYINGDATE
532013-07-08 08:302013-07-08 23:595001702013/7/22
532013-07-09 00:002013-07-09 23:595001702013/7/22
532013-07-10 00:002013-07-10 23:595001702013/7/22
532013-07-11 00:002013-07-11 23:595001702013/7/22
532013-07-12 00:002013-07-12 17:305001702013/7/22
352013-07-15 08:302013-07-15 09:304001712013/7/22

表2 user_spedat假单

这6条记录代表什么意义?

   先说简单的,user_spedat的最后一行表示:

 严工(员工号35)2013-07-15 08:30至2013-07-15 09:30请事假(假别号4)原因00171    

与原始假单结构基本相同。

   user_spedat的1-5行表示:

刘工(员工号52)2013-07-08 08:30至2013-07-12 17:30请补休假(假别号5)原因00170

user_spedat用5行表示了刘工的5天(8-12日)请假资料,我们看到对于有跨日的请假,考勤系统按日自动拆分请假日期,并自动填充每日的起始时间、结束时间(见表2的蓝色区域),并基本保持填充时间无缝连接(23:59--00:00只差一分钟)。


   2.3 假单导入方案

   至此请假单导入方案呼之欲出:

       (a)在OA系统,将请假单导出至Excle表

       (b)在access,将Excle表导入至临时表

       (c)在access,将临时表整理到user_spedat表

   了解OA、acces者都知道,步骤(a)、(b)只是举手之劳,对于步骤(c)还需进一步规划:

   (1) access中的临时表命名为《请假单》,结构同原始假单,另增加姓名id、假别id两个字段。

字段名称数据类型
请假单号文本
姓名id数字
姓名文本
假别id数字
假别文本
起始时间日期/时间
结束时间日期/时间

表3 临时表《请假单》结构


   (2)《请假单》整理到user_spedat《假单》的大致算法

       打开《请假单》as Q

       声明 tcb 填充起始时间

       声明 tce 填充结束时间

       do where Q.eof()

           tcb = Q.起始日期+00:00

           tce = Q.起始日期+23:59

           do where tce <     Q.结束时间

             (Q.姓名id,tcb,tce,Q.假别id,Q.请假单号)追加至user_spedat

              tcb日期增加1日

              tce日期增加1日

           enddo

           Q.下一记录

       enddo


   2.4 假单导入在access中的实现

   假单导入在access中的开发包括3项内容:

  • 创建临时表《请假单》用于暂存原始假单;

  • 制作假单导入程序,用于将外部原始假单导入《请假单》;

  • 制作假单整理程序,用于将《请假单》数据整理到符合考勤管理系统要求的user_spedat表。


    111241353.jpg


   (1)创建的临时表《请假单》结构见表3


   (2)假单导入程序

   假单导入程序采用了access宏,命名为[导入假单],绑定于窗口[导入假单]按钮。

   不是所有原始假单都能够被考勤管理系统接受,例如在考勤系统未定义的员工、假别等。[导入假单]宏对除了导入原始假单,还对原始假单做了预处理,对不符合条件的原始假单[导入假单]宏向考勤员提示,然将其删除,以便于假单整理。

111244339.jpg



   (3)假单整理过程

   由于需要逐条处理《请假单》,假单导入程序采用了access过程,绑定于窗口[整理假单]按钮。该过程的难点在于整理到user_spedat表的过程中,假单第一天为原始起始时间--填充结束时间;假单最后一天为填充起始时间--原始结束时间,参见表2。

Private Sub Command4_Click()

'本程序将形如下表的【请假单】

'请假单号    姓名id  姓名    假别id  假别    起始时间           结束时间

'30716-00168 53       刘工        4   补休    2013-07-17 8:30:00  2013-07-19 17:30:00

'

'整理到【USER_SPEDAY】,对于假期超过1日的假单,需要按日拆分填充

'USERID  STARTSPECDAY        ENDSPECDAY          DATEID  YUANYING

'53      2013-07-17 8:30:00  2013-07-17 23:59:00 4      30716-00168

'53      2013-07-18 0:00:01  2013-07-18 23:59:00 4      30716-00168

'53      2013-07-19 0:00:01  2013-07-19 17:30:00 4      30716-00168

'


Dim varSource As String

Dim cnn As New ADODB.Connection '设置连接对象实例

Dim rs1 As New ADODB.Recordset  '设置记录集对象实例,用于《请假单》

Dim rs2 As New ADODB.Recordset  '设置记录集对象实例,用于user_spedat


cnn.Open "provider=microsoft.jet.oledb.4.0;data source=D:\Program Files\att2000.mdb;"   '连接数据源

rs1.Open "SELECT * FROM 请假单", cnn   '打开来源记录集,游标只能向前移动

rs2.Open "SELECT * FROM USER_SPEDAY", cnn, , adLockOptimistic '打开目标记录集,游标只能向前移动,可更新


Dim bdt, edt As Date '填充起始时间,填充结束时间

Dim i As Integer '日数计数


Do While Not rs1.EOF

   i = 1

   bdt = rs1!起始时间

   edt = CDate(Left(CStr(rs1!起始时间), 10) + " 23:59:00")    '第一个填充结束时间


   Do While edt < rs1!结束时间

       rs2.MoveLast

       rs2.AddNew

       rs2!userid = rs1!姓名id

       rs2!STARTSPECDAY = bdt

       rs2!ENDSPECDAY = edt

       rs2!dateid = rs1!假别id

       rs2!YUANYING = rs1!请假单号

       rs2("date") = Date

       If i = 1 Then

           bdt = CDate(Left(CStr(bdt), 10) + " 00:00:01") '第一个中间起始时间

       End If

       bdt = DateAdd("d", 1, bdt)

       edt = DateAdd("d", 1, edt)

   Loop

   rs2.MoveLast

   rs2.AddNew

   rs2!userid = rs1!姓名id

   rs2!STARTSPECDAY = bdt

   rs2!ENDSPECDAY = rs1!结束时间

   rs2!dateid = rs1!假别id

   rs2!YUANYING = rs1!请假单号

   rs2!Date = Date


   rs1.MoveNext

Loop

MsgBox "假单导入完成"

rs2.Update

rs2.Close

rs1.Close

cnn.Close

End Sub