Xin chào các bạn, bài viết hôm nay mình sẻ tiếp tục hướng dẫn các bạn cách tải dữ liệu chấm công từ máy chấm công trong lập trình C# winform.
Bạn đang xem: Lập trình máy chấm công

Trong bài viết này, chương trình demo của mình đang kết nối với máy chấm công Ronald Jack, một thương hiệu máy chấm công phổ biến trên thị trường.
Máy chấm công này có cung cấp cho chúng ta thư viện Interop.zkemkeeper để làm việc với máy chấm công.
Với thư viện, này chúng ta có thể làm nhiều việc trên máy chấm công: thêm nhân viên mới, xóa nhân viên, khóa nhân viên...
Xem thêm: Căng ThẳNg VớI 6 Phim Hay NhấT Trên Hbo, Cinemax, Star Movies
Tuy nhiên trong bài viết này, mình chỉ demo cách tải dữ liệu chấm công trên máy về GridView trên Winform.
Dưới đây là giao diện demo ứng dụng tools tải dữ liệu chấm công:

Phần mềm này, mình tích hợp chạy đa luồng, nên thời gian tải dữ liệu trên nhiều máy sẽ rất nhanh, như hình demo các bạn thấy.
Thông số port mặc định của máy thường là: 4370, nếu máy của bạn cấu hình trên port khác, các bạn có thể thay đổi port ở code bên dưới.
Đầu tiên các bạn tạo cho mình một class AttLogHelper.cs
using System;using System.Collections.Generic;using System.Data;using System.IO;using System.Linq;using System.Text;using System.Threading.Tasks;using zkemkeeper;namespace AttLog{ public static class AttLogHelper { public const int TCP_PORT = 4370; private const int CONNECT_TIMEOUT = 4000; private const int DATA_FILE_FLAG = 1; // Log data file private const int RECORD_COUNT_FLAG = 6; // Log data file private static int iMachineNumber = 1;//In fact,when you are using the tcp/ip communication,this parameter will be ignored,that is any integer will all right.Here we use 1. private static readonly Random m_random = new Random(); private static readonly string HOB_TEMP_CHAMCONG_DIR = Path.GetTempPath() + "hob_chamcong\\"; //1 dòng dữ liệu LOG máy chấm công cố định là 16 byte private const int ROW_LOG_BYTE_LENGTH = 16; //1 dòng dữ liệu USER máy chấm công cố định là 28 byte private const int ROW_USER_BYTE_LENGTH = 28; private const string CHAMCONG_LOG_FILENAME = "extlog.dat"; private const string CHAMCONG_USER_FILENAME = "user.dat"; //file lưu mã nhân viên - seri thẻ private const long MAX_SERI = 4294967295; //return false nghĩa là dữ liệu máy chấm công có lỗi cấu trúc public static bool ParseLog2Datatable(ref byte<> buff, DataTable outDt) { int manv = 0; DateTime ngaygio = default(DateTime); int startIndex = 0; var Today = DateTime.Now; DataRow row = default(DataRow); outDt.Clear(); outDt.Columns.Add("manv", typeof(int)); outDt.Columns.Add("ngaygio", typeof(DateTime)); //1 dòng dữ liệu LOG máy chấm công cố định là 16 byte //buff.Length > 0 AndAlso if (buff.Length % ROW_LOG_BYTE_LENGTH == 0) { for (var r = 0; r 0 AndAlso if (buff.Length % ROW_USER_BYTE_LENGTH == 0) { for (var r = 0; r 0) { buff = new byte
using DevExpress.XtraEditors;using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;using System.Windows.Forms;using zkemkeeper;namespace AttLog{ public partial class Form1 : DevExpress.XtraEditors.XtraForm { private int _soMayChon; DataTable dataTableResult; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { var dataTable = new DataTable(); dataTable.Columns.Add("ip"); dataTable.Columns.Add("tinhtrang"); dataTable.Columns.Add("noidung"); dataTable.Rows.Add("172.16.0.91"); dataTable.Rows.Add("172.16.0.92"); dataTable.Rows.Add("172.16.0.93"); dataTable.Rows.Add("172.16.0.94"); gridControl1.DataSource = dataTable; dataTableResult = new DataTable(); dataTableResult.Columns.Add("manv"); dataTableResult.Columns.Add("ngaygio"); gridControl2.DataSource = dataTableResult; } private void ZKEM_download_chamcong(IProgress progress) { gridView1.CloseEditor(); gridView1.PostEditor(); var selectedRows = gridView1.GetSelectedRows(); _soMayChon = selectedRows.Count(); int countFinish = 0; BeginInvoke(new Action(() => { btn_DownloadAtt.Enabled = false; foreach (var r in selectedRows) { gridView1.SetRowCellValue(r, "tinhtrang", ""); gridView1.SetRowCellValue(r, "noidung", ""); } })); Parallel.ForEach(selectedRows, async rowHandle => { string deviceIp = Convert.ToString(gridView1.GetDataRow(rowHandle)<"ip">); TinhTrangKetNoi(rowHandle, "Đang kết nối ZKEM..."); CZKEM izkem = await AttLogHelper.Connect(deviceIp); if (izkem != null) { int recordCount = AttLogHelper.getRecordCount(izkem); if (recordCount == 0) { TinhTrangKetNoi(rowHandle, "Máy không có dữ liệu"); } else { TinhTrangKetNoi(rowHandle, "Đã kết nối. Đang tải..."); byte<> data = AttLogHelper.downloadDataFile(izkem); izkem.Disconnect(); if (data != null) { var dt = new DataTable(); if (AttLogHelper.ParseLog2Datatable(ref data, dt)) { gridControl2.BeginInvoke(new Action(() => { foreach(DataRow dr in dt.Rows) { var workRow = dataTableResult.NewRow(); workRow<0> = dr<"manv">; workRow<1> = dr<"ngaygio">; dataTableResult.Rows.Add(workRow); } })); NoidungKetNoi(rowHandle, "Tìm thấy " + dt.Rows.Count + " dòng"); } } else { TinhTrangKetNoi(rowHandle, "Tải file chấm công thất bại"); } } } else { TinhTrangKetNoi(rowHandle, "Lỗi kết nối. Thử lại sau."); } Interlocked.Increment(ref countFinish); var percent = Convert.ToInt32(Convert.ToDouble(countFinish) / _soMayChon * 100d); progress.Report(percent); }); } private void TinhTrangKetNoi(int rowHandle, string msg) { gridControl1.BeginInvoke((Action)(() => { gridView1.SetRowCellValue(rowHandle, "tinhtrang", msg); })); } private void NoidungKetNoi(int rowHandle, string msg) { gridControl1.BeginInvoke((Action)(() => { gridView1.SetRowCellValue(rowHandle, "noidung", msg); })); } private async void btnDownload_Click(object sender, EventArgs e) { if (gridView1.SelectedRowsCount > 0) { progressBarControl1.EditValue = 0; var progress = new Progress(percent => { BeginInvoke(new Action(() => { progressBarControl1.EditValue = percent; if(percent == 100) { btn_DownloadAtt.Enabled = true; } })); }); await Task.Run(() => ZKEM_download_chamcong(progress)); } else { XtraMessageBox.Show("Bạn vui lòng chọn các máy chấm công để tải dữ liệu kết nối."); } } }}Thanks for watching!