C#winform上下班打卡系统Demo
C# winform上下班打卡系统Demo
系统效果如图所示

7个label控件(lblUsername、lblLoggedInEmployeeId、lab_IP、lblCheckOutTime、lblCheckInTime、lab_starttime、lab_endtime)、3个按钮、1个dataGridView控件、2个groupBox控件
C#代码实现
using System;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Windows.Forms;namespace WindowsFormsApp1
{public partial class 员工打卡 : Form{private string loggedInUsername;private string loggedInEmployeeId;private string connectionString = "server=127.0.0.1;uid=sa;pwd=xyz@0123456;database=test";public 员工打卡(string username, string employeeId){InitializeComponent();loggedInUsername = username;loggedInEmployeeId = employeeId;CheckTodaysPunchInRecord();}[DllImport("user32.dll")]public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);[DllImport("user32.dll")]public static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);// 禁用窗口大小改变private const uint SC_SIZE = 0xF000;private const uint MF_BYCOMMAND = 0x0000;private const uint MF_GRAYED = 0x0001;protected override void OnLoad(EventArgs e){base.OnLoad(e);IntPtr hMenu = GetSystemMenu(this.Handle, false);if (hMenu != IntPtr.Zero){EnableMenuItem(hMenu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);}}private void 员工打卡_Load(object sender, EventArgs e){lblUsername.Text = "当前登录用户:" + loggedInUsername;lblLoggedInEmployeeId.Text = "工号:" + loggedInEmployeeId.ToString();// 设置日期控件的显示格式为年-月-日startTime.Format = DateTimePickerFormat.Custom;startTime.CustomFormat = "yyyy-MM-dd";// 设置日期控件的显示格式为年-月-日endTime.Format = DateTimePickerFormat.Custom;endTime.CustomFormat = "yyyy-MM-dd";//不显示出dataGridView1的最后一行空白dataGridView1_Result.AllowUserToAddRows = false;// 设置数据和列名居中对齐dataGridView1_Result.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;dataGridView1_Result.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;// 设置列名加粗dataGridView1_Result.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font(dataGridView1_Result.ColumnHeadersDefaultCellStyle.Font, FontStyle.Bold);// 设置列宽自适应dataGridView1_Result.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;LoadData();GetIP();}private void GetIP(){// 获取本机IP地址IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());foreach (IPAddress ip in ipHost.AddressList){if (ip.AddressFamily == AddressFamily.InterNetwork){lab_IP.Text = "IP地址:" + ip.ToString(); // 添加到label1的Text属性中}}}private void btnCheckIn_Click(object sender, EventArgs e){if (IsPunchInRecordExists()){MessageBox.Show("你已打过上班卡。", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk);return;}DateTime currentTime = DateTime.Now;string punchInTime = currentTime.ToString("yyyy-MM-dd HH:mm:ss");string status = currentTime.TimeOfDay < new TimeSpan(8, 30, 0) ? "正常" : "迟到";InsertPunchInRecord(punchInTime, status);lblCheckInTime.Text = punchInTime;lblCheckInTime.Visible = true;// 刷新DataGridView显示最新打卡记录RefreshDataGridView();}private bool IsPunchInRecordExists(){DateTime currentDate = DateTime.Now.Date;string query = $"SELECT COUNT(*) FROM PunchIn WHERE emp_code='{loggedInEmployeeId}' AND punch_in_time >= '{currentDate}'";using (SqlConnection connection = new SqlConnection(connectionString)){connection.Open();using (SqlCommand command = new SqlCommand(query, connection)){int count = (int)command.ExecuteScalar();return count > 0;}}}private void RefreshDataGridView(){// 执行查询语句string query = $@"SELECT a.id,a1.username AS 用户名,a.emp_code AS 工号,CONVERT(VARCHAR(19), a.punch_in_time, 120) AS 上班打卡时间,a.status AS 上班打卡状态,CONVERT(VARCHAR(19), b.punch_out_time, 120) AS 下班打卡时间,b.status AS 下班打卡状态FROM (SELECT * FROM Employee) a1LEFT JOIN PunchIn a ON a1.emp_code = a.emp_codeLEFT JOIN PunchOut b ON a.emp_code = b.emp_code AND CONVERT(DATE, a.punch_in_time) = CONVERT(DATE, b.punch_out_time)AND b.punch_out_time = (SELECT MAX(punch_out_time)FROM PunchOutWHERE emp_code = a.emp_code AND CONVERT(DATE, punch_out_time) = CONVERT(DATE, a.punch_in_time))WHERE a.emp_code = '{loggedInEmployeeId}' AND MONTH(a.punch_in_time) = MONTH(GETDATE()) AND YEAR(a.punch_in_time) = YEAR(GETDATE())ORDER BY a.id, a.emp_code, a.punch_in_time";Console.WriteLine("执行的SQL语句是:" + query);// 执行查询并获取结果// 你可以使用适合你数据库的查询方法DataTable dataTable = ExecuteQuery(query);// 将查询结果绑定到DataGridView的数据源dataGridView1_Result.DataSource = dataTable;}private DataTable ExecuteQuery(string query){// 创建连接和命令对象并执行查询using (SqlConnection connection = new SqlConnection(connectionString)){connection.Open();using (SqlCommand command = new SqlCommand(query, connection)){// 创建适配器并填充数据到DataTableSqlDataAdapter adapter = new SqlDataAdapter(command);DataTable dataTable = new DataTable();adapter.Fill(dataTable);return dataTable;}}}private void InsertPunchInRecord(string punchInTime, string status){string query = $"INSERT INTO PunchIn (emp_code, punch_in_time, status) VALUES ('{loggedInEmployeeId}', '{punchInTime}', '{status}')";using (SqlConnection connection = new SqlConnection(connectionString)){connection.Open();using (SqlCommand command = new SqlCommand(query, connection)){command.ExecuteNonQuery();}}}private void CheckTodaysPunchInRecord(){DateTime currentDate = DateTime.Now.Date;string query = $"SELECT punch_in_time FROM PunchIn WHERE emp_code='{loggedInEmployeeId}' AND punch_in_time >= '{currentDate}'";using (SqlConnection connection = new SqlConnection(connectionString)){connection.Open();using (SqlCommand command = new SqlCommand(query, connection)){object result = command.ExecuteScalar();if (result != null){string punchInTime = ((DateTime)result).ToString("yyyy-MM-dd HH:mm:ss");lblCheckInTime.Text = punchInTime;lblCheckInTime.Visible = true;}}}}private void btnCheckOut_Click(object sender, EventArgs e){DateTime currentTime = DateTime.Now;string punchOutTime = currentTime.ToString("yyyy-MM-dd HH:mm:ss");if (IsInvalidPunchOutTime(currentTime)){MessageBox.Show("21点30到23:59:59点打下班卡无效。");return;}string status = currentTime.TimeOfDay < new TimeSpan(18, 0, 0) ? "早退" : "正常"; // 判断下班打卡时间是否在18:00之前InsertPunchOutRecord(punchOutTime, status);lblCheckOutTime.Text = punchOutTime;lblCheckOutTime.Visible = true;// 刷新DataGridView显示最新打卡记录RefreshDataGridView();}private bool IsInvalidPunchOutTime(DateTime currentTime){TimeSpan startTime = new TimeSpan(21, 30, 0);TimeSpan endTime = new TimeSpan(23, 59, 59);TimeSpan currentTimeOfDay = currentTime.TimeOfDay;return currentTimeOfDay >= startTime && currentTimeOfDay <= endTime;}private void InsertPunchOutRecord(string punchOutTime, string status){string query = $"INSERT INTO PunchOut (emp_code, punch_out_time, status) VALUES ('{loggedInEmployeeId}', '{punchOutTime}', '{status}')";using (SqlConnection connection = new SqlConnection(connectionString)){connection.Open();using (SqlCommand command = new SqlCommand(query, connection)){command.ExecuteNonQuery();}}}private void btn_Serch_Click(object sender, EventArgs e){// 获取所选时间范围DateTime startDate = startTime.Value.Date;DateTime endDate = endTime.Value.Date.AddDays(1).AddSeconds(-1);// 构建 SQL 查询语句string query = $@"SELECT a.id,a1.username AS 用户名,a.emp_code AS 工号,CONVERT(VARCHAR(19), a.punch_in_time, 120) AS 上班打卡时间,a.status AS 上班打卡状态,CONVERT(VARCHAR(19), b.punch_out_time, 120) AS 下班打卡时间,b.status AS 下班打卡状态FROM (SELECT * FROM Employee) a1LEFT JOIN PunchIn a ON a1.emp_code = a.emp_codeLEFT JOIN PunchOut b ON a.emp_code = b.emp_code AND CONVERT(DATE, a.punch_in_time) = CONVERT(DATE, b.punch_out_time)AND b.punch_out_time = (SELECT MAX(punch_out_time)FROM PunchOutWHERE emp_code = a.emp_code AND CONVERT(DATE, punch_out_time) = CONVERT(DATE, a.punch_in_time))WHERE a.punch_in_time BETWEEN @StartDate AND @EndDateAND a.emp_code = '{loggedInEmployeeId}'ORDER BY a.id, a.emp_code, a.punch_in_time";using (SqlConnection connection = new SqlConnection(connectionString)){using (SqlCommand command = new SqlCommand(query, connection)){// 添加查询参数command.Parameters.AddWithValue("@StartDate", startDate);command.Parameters.AddWithValue("@EndDate", endDate);Console.WriteLine("查询的SQL语句:" + query);// 打开数据库连接connection.Open();// 创建数据适配器和数据表SqlDataAdapter adapter = new SqlDataAdapter(command);DataTable table = new DataTable();// 填充数据表adapter.Fill(table);// 关闭数据库连接connection.Close();// 绑定数据表到 DataGridView 控件dataGridView1_Result.DataSource = table;}}}private void LoadData(){// 获取所选时间范围DateTime startDate = startTime.Value.Date;DateTime endDate = endTime.Value.Date.AddDays(1).AddSeconds(-1);string query = $@"SELECT a.id,a1.username AS 用户名,a.emp_code AS 工号,CONVERT(VARCHAR(19), a.punch_in_time, 120) AS 上班打卡时间,a.status AS 上班打卡状态,CONVERT(VARCHAR(19), b.punch_out_time, 120) AS 下班打卡时间,b.status AS 下班打卡状态FROM (SELECT * FROM Employee) a1LEFT JOIN PunchIn a ON a1.emp_code = a.emp_codeLEFT JOIN PunchOut b ON a.emp_code = b.emp_code AND CONVERT(DATE, a.punch_in_time) = CONVERT(DATE, b.punch_out_time)AND b.punch_out_time = (SELECT MAX(punch_out_time)FROM PunchOutWHERE emp_code = a.emp_code AND CONVERT(DATE, punch_out_time) = CONVERT(DATE, a.punch_in_time))WHERE a.punch_in_time BETWEEN @StartDate AND @EndDateAND a.emp_code = '{loggedInEmployeeId}'ORDER BY a.id, a.emp_code, a.punch_in_time";Console.WriteLine("开始时间:" + startDate);Console.WriteLine("结束时间:" + endDate);using (SqlConnection connection = new SqlConnection(connectionString)){using (SqlCommand command = new SqlCommand(query, connection)){// 添加查询参数command.Parameters.AddWithValue("@StartDate", startDate);command.Parameters.AddWithValue("@EndDate", endDate);Console.WriteLine("一加载时获取数据查询的SQL语句:" + query);// 打开数据库连接connection.Open();// 创建数据适配器和数据表SqlDataAdapter adapter = new SqlDataAdapter(command);DataTable table = new DataTable();// 填充数据表adapter.Fill(table);// 关闭数据库连接connection.Close();// 绑定数据表到 DataGridView 控件dataGridView1_Result.DataSource = table;}}}}
}相关文章:
C#winform上下班打卡系统Demo
C# winform上下班打卡系统Demo 系统效果如图所示 7个label控件(lblUsername、lblLoggedInEmployeeId、lab_IP、lblCheckOutTime、lblCheckInTime、lab_starttime、lab_endtime)、3个按钮、1个dataGridView控件、2个groupBox控件 C#代码实现 using System; using System.Dat…...
P1 Qt的认识及环境配置
目录 前言 01 下载Qt Creator windows下载安装包拷贝到Linux Linux直接下载 02 Linux 安装Qt 前言 🎬 个人主页:ChenPi 🐻推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ 🔥 推荐专栏2: 《Linux C应用编程(概念类…...
单元测试Nunit的几种断言
Nunit提供了一些辅助函数用于确定好某个被测试函数是否正常工作。通常把这些函数称为断言 断言是单元测试最基本的组成部分。因此,NUnit程序库以Assert类的静态方法的形式提供了不同形式的多种断言 1. Assert.AreEqual:比较两个值是否相等。用于比较数…...
前端中的响应式布局与各个端适配
什么是响应式布局? 响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。在移动互联网高度发达的今天,我们在桌面浏览器上开发的网页已经无法满足在移动设备上查看的需求。传统的开发方式是PC端开发一套页面,手机端再开发一套页面。但是…...
2023年5个自动化EDA库推荐
EDA或探索性数据分析是一项耗时的工作,但是由于EDA是不可避免的,所以Python出现了很多自动化库来减少执行分析所需的时间。EDA的主要目标不是制作花哨的图形或创建彩色的图形,而是获得对数据集的理解,并获得对变量之间的分布和相关…...
7-1 查找书籍
给定n本书的名称和定价,本题要求编写程序,查找并输出其中定价最高和最低的书的名称和定价。 输入格式: 输入第一行给出正整数n(<10),随后给出n本书的信息。每本书在一行中给出书名,即长度不超过30的字…...
【无线网络技术】——无线广域网(学习笔记)
📖 前言:无线广域网(WWAN)是指覆盖全国或全球范围内的无线网络,提供更大范围内的无线接入,与无线个域网、无线局域网和无线城域网相比,它更加强调的是快速移动性。典型的无线广域网:蜂窝移动通信系统和卫星…...
【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、springboot分层架构、IDEA修改快捷键、vue代码风格
项目笔记为项目总结笔记,若有错误欢迎指出哟~ 【项目专栏】 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(1)spring boot项目搭建、vue项目搭建、微信小程序项目搭建 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、sp…...
NGINX相关配置
全局配置 NGINX配置信息 nginx 官方帮助文档:http://nginx.org/en/docs/Nginx的配置文件的组成部分: 主配置文件:/conf/nginx.conf(/nginx/conf/nginx.conf) 子配置文件: include conf.d/*.conf#事件驱动相关的配置 同步 event { worker_…...
如何将idea中导入的文件夹中的项目识别为maven项目
问题描述 大家经常遇到导入某个文件夹的时候,需要将某个子文件夹识别为maven项目 解决方案...
CleanMyMac4.16中文最新版本下载
当很多人还在为电脑运行缓慢、工作问题不能快速得到解决而烦恼的时候,我已经使用过了多款系统清理工具,并找到了最适合我的那一款。我的电脑是超耐用的Mac book,接下来给大家介绍三种在众多苹果电脑清理软件的排名较高的软件。 一、Maintena…...
谷歌正式发布最强 AI 模型 Gemini
2023年12月6日,谷歌公司宣布推出其被认为是规模最大、功能最强大的人工智能模型 Gemini。 Gemini将分为三个不同的套件:Gemini Ultra、Gemini Pro和Gemini Nano。 Gemini Ultra被认为具备最强大的能力,Gemini Pro则可扩展至多任务&#x…...
无人机语音中继电台 U-ATC118
简介 甚高频无线电中继通讯系统使用经过适航认证的机载电台连接数字网络传输模块,通过网络远程控制无缝实现无人机操作员与塔台直接语音通话。无人机操作员可以从地面控制站远程操作机载电台进行频率切换、静噪开关、PTT按钮,电台虚拟面板与真实面板布局…...
两种测量方式的自适应卡尔曼滤波数据融合
文章目录 测试效果代码CMakeLists.txt参考测试效果 代码 #include <iostream> #include <Eigen/Dense> #include...
.Net6支持的操作系统版本(.net8已来,你还在用.netframework4.5吗)
机缘 不知不觉,.NET8都已经面世,而我们一直还停留在.netframework4.5开发阶段,最近准备抽空研究一下.Net6,一是为了提高技术积累,一方面想着通过这次的学习,看有没有可能将老的FX版本替换到.Net6开发上,经过查找官方资料,对.Net6支持的系统版本做一个分享,方便大家后期…...
CopyOnWriteArraySet怎么用
简介 CopyOnWriteArraySet是一个线程安全的无序集合,它基于“写时复制”的思想实现。它继承自AbstractSet,可以将其理解成线程安全的HashSet。 CopyOnWriteArraySet在读取操作比较频繁、写入操作相对较少的情况下可以提高程序的性能和可靠性。它的线程…...
uniapp得app云打包问题
获取appid,具体可以查看详情 也可以配置图标,获取直接生成即可 发行 打包配置 自有证书测试使用时候不需要使用 编译打包 最后找到安装包apk安装到手机 打包前,图片命名使用要非中文,否则无法打包成功会报错...
Linux bin包生成
需求背景: 在实际项目时我们很少把源码用个tar给到客户,这样显得很不专业,且有的时候我们提供补丁,那么这个时候我们提供一个补丁的bin包可以直接安装运行就显得很高大上了。 物料准备 准备一台liunx,虚拟机亦可&am…...
Java多人聊天
服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class Server{public static ServerSocket server_socket;public static ArrayList<Socket> socketListnew ArrayList<Socket>(); public static void main(String []args){try{…...
自动驾驶:传感器初始标定
手眼标定 机器人手眼标定AxxB(eye to hand和eye in hand)及平面九点法标定 Ax xB问题求解,旋转和平移分步求解法 手眼标定AXXB求解方法(文献总结) 基于靶的方法 相机标定 (1) ApriTag (2) 棋盘格:cv::f…...
ESP32-S2物联网实战:IPv6配置与Adafruit IO双向通信
1. 项目概述与核心价值如果你手头有一块ESP32-S2开发板,并且已经厌倦了仅仅让它连上Wi-Fi、点个灯,想让它真正“活”起来,成为一个能融入现代互联网、能与云端自由对话的智能节点,那么这篇文章就是为你准备的。我们将深入两个在物…...
Simple Runtime Window Editor:突破游戏窗口限制的终极解决方案
Simple Runtime Window Editor:突破游戏窗口限制的终极解决方案 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否曾为游戏内置分辨率选项太少而烦恼?是否想在窗口模式下获得全屏游戏…...
Nix构建确定性AI编程环境:解决Cursor编辑器依赖冲突难题
1. 项目概述:当代码编辑器遇上Nix的确定性魔法 最近在折腾开发环境时,我遇到了一个老生常谈但又无比头疼的问题:团队里新来的同事怎么也跑不起来我本地运行得好好的一个代码辅助工具链。依赖版本冲突、系统库路径不对、甚至是因为他用的macO…...
深度解析:Performance-Fish如何通过四级缓存架构实现《环世界》400%性能优化
深度解析:Performance-Fish如何通过四级缓存架构实现《环世界》400%性能优化 【免费下载链接】Performance-Fish Performance Mod for RimWorld 项目地址: https://gitcode.com/gh_mirrors/pe/Performance-Fish Performance-Fish是《环世界》(Rim…...
【限时公开】后印象派专属--ar 16:9 --style raw --stylize 800参数组合包(含塞尚构图/修拉点彩/劳特累克动态线共12套已验证prompt模板)
更多请点击: https://intelliparadigm.com 第一章:后印象派艺术精神与Midjourney风格迁移的本质逻辑 后印象派并非对印象派的简单延续,而是对主观表达、结构重构与象征张力的自觉回归——梵高旋转的星云、塞尚凝练的几何体、高更原始的色域&…...
Linuxbonding链路生产排障流程
Linuxbonding链路生产排障流程这是一篇面向中级 Linux 使用者的技术文章,主题聚焦在bonding链路,重点讨论链路聚合、冗余切换和接口状态。在真实生产环境中,bonding链路相关问题往往不会以单一错误形式出现,而是混杂在日志、权限、…...
Qdrant Python客户端全解析:从向量数据库连接到AI应用开发实战
1. 项目概述:从向量数据库到客户端,现代AI应用落地的关键拼图如果你最近在折腾大语言模型应用,或者想给自己的产品加上一个“智能大脑”,那你大概率已经听过“向量数据库”这个词了。简单来说,它就像一个专门为AI模型设…...
DriveBench:面向真实驾驶场景的长序列多智能体交互基准测试框架
1. 项目概述:从“世界基准”到“驾驶基准”的演进如果你在自动驾驶或者计算机视觉领域摸爬滚打过几年,一定对“基准测试”(Benchmark)这个词又爱又恨。爱的是,它提供了一个相对公平的擂台,让不同算法、不同…...
Obsidian智能模板终极指南:3步打造高效笔记自动化系统
Obsidian智能模板终极指南:3步打造高效笔记自动化系统 【免费下载链接】Templater A template plugin for obsidian 项目地址: https://gitcode.com/gh_mirrors/te/Templater Templater插件是Obsidian生态系统中功能最强大的智能模板解决方案,它能…...
Switch便携投影底座DIY:3D打印与硬件改造实战指南
1. 项目概述:当Switch遇上投影,一场桌面上的大屏革命作为一个折腾过不少游戏机外设的玩家,我一直在想,有没有办法让Switch的“便携”属性再进化一步?官方底座接电视固然爽,但总被一根线缆束缚在客厅。直到我…...
