新闻详情

新闻详情

首页 / 资讯中心 / 详情

手写实现考勤统计软件,3步解决复制代码跑不通痛点

发布时间:2026/10/25 7:26:47来源:尧图网络
手写实现考勤统计软件,3步解决复制代码跑不通痛点
手写实现考勤统计软件,3步解决复制代码跑不通痛点 刚把网上下载的考勤代码拷进项目,直接 npm run dev?结果终端炸出一串 Module not found 或者 Cannot read properties of undefined。别慌,这种“复制来的代码跑不通不知道怎么调”的坑,90%的新手都踩过。原因很简单:那些博主只给了核心逻辑,却漏掉了环境依赖、数据初始化这些“隐形地基”。今天咱们不抄作业,直接手写实现一套极简的考勤统计软件后端。不依赖重型框架,只用 Python 标准库和 SQLite,确保你每一步都看得懂、跑得通,彻底搞懂数据是怎么从打卡记录变成统计报表的。 项目目标与核心逻辑拆解 很多新手一上来就想做“完美系统”,结果陷在 UI 和权限里出不来。咱们这次的目标很明确:能跑通最小闭环。具体指标如下:数据录入:支持通过接口模拟员工打卡(上班/下班)。 数据清洗:自动识别迟到、早退、缺卡,处理跨天加班逻辑。 统计输出:生成每日/每月考勤摘要,包含出勤天数、异常次数。 持久化:数据存入 SQLite,重启不丢失。为什么选 Python + SQLite?因为这是调试成本最低的组合。当代码报错时,你能快速定位是逻辑错了还是数据库配置错了,而不是在 Spring Boot 的 Bean 注入或 Node.js 的异步回调里迷路。 目录结构设计原则 别被复杂的微服务架构吓到。对于单体考勤系统,扁平化目录最利于排查问题。建议结构如下: attendance_system/ ├── main.py # 程序入口,启动服务 ├── models.py # 数据模型定义 (SQLAlchemy ORM) ├── services.py # 核心业务逻辑 (考勤规则引擎) ├── database.py # 数据库连接与初始化 ├── utils.py # 工具函数 (时间处理、日志) ├── requirements.txt # 依赖清单 └── data/ # SQLite 数据库文件存放处关键点:services.py 是灵魂。所有“迟到怎么算”、“加班怎么折算”的逻辑都放在这里,而不是散落在接口代码里。这样当你发现统计结果不对时,只需要打开这一个文件就能找到根源。 核心代码实现:从数据库到规则引擎 1. 数据库层:避开“表不存在”的坑 很多复制代码报错是因为 create_all() 没执行,或者文件路径写死成了绝对路径。看这段 database.py: import os from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker# 动态获取当前文件所在目录,防止路径错误 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) DB_PATH = os.path.join(BASE_DIR, 'data', 'attendance.db')# 确保 data 文件夹存在,否则报错 if not os.path.exists(os.path.join(BASE_DIR, 'data')):os.makedirs(os.path.join(BASE_DIR, 'data'))engine = create_engine(f'sqlite:///{DB_PATH}', echo=False) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base()def init_db():启动时调用,确保表结构已创建Base.metadata.create_all(bind=engine)逐行解读:os.path.abspath(__file__):这是解决“在 A 盘能跑,换到 B 盘就报错”的关键。永远不要硬编码路径。 os.makedirs:如果目录不存在,程序会崩溃。提前创建文件夹是防止 OperationalError 的最简单手段。2. 数据模型:定义打卡实体 在 models.py 中,我们需要两张表:Employee(员工)和 ClockRecord(打卡记录)。 from sqlalchemy import Column, Integer, String, DateTime, ForeignKey from sqlalchemy.orm import relationship from datetime import datetime from .database import Baseclass Employee(Base):__tablename__ = 'employees'id = Column(Integer, primary_key=True, index=True)name = Column(String(50), unique=True, index=True)department = Column(String(50))# 关联打卡记录records = relationship(ClockRecord, back_populates=employee)class ClockRecord(Base):__tablename__ = 'clock_records'id = Column(Integer, primary_key=True, index=True)employee_id = Column(Integer, ForeignKey('employees.id'))clock_time = Column(DateTime) # 打卡具体时间clock_type = Column(String(10)) # 'in' 上班, 'out' 下班employee = relationship(Employee, back_populates=records)注意:clock_type 用字符串 'in'/'out' 比用数字更直观,调试时看日志一眼就能明白状态。 3. 业务逻辑:手写考勤规则引擎 这是最容易出 Bug 的地方。网上很多代码直接相减时间,忽略了跨月、跨天、节假日。我们手写一个简化的规则引擎,重点处理迟到和缺卡。 from datetime import datetime, timedelta from .models import Employee, ClockRecord from .database import SessionLocalclass AttendanceService:@staticmethoddef check_attendance(employee_id: int, date: datetime):检查某天某人的考勤状态规则:1. 09:00 前打卡算正常,之后算迟到2. 18:00 后打卡算正常,之前算早退3. 缺少上班卡算缺卡db = SessionLocal()try:# 查询该员工当天的所有打卡记录start_of_day = date.replace(hour=0, minute=0, second=0, microsecond=0)end_of_day = date.replace(hour=23, minute=59, second=59, microsecond=999999)records = db.query(ClockRecord).filter(ClockRecord.employee_id == employee_id,ClockRecord.clock_time = start_of_day,ClockRecord.clock_time = end_of_day).all()status = {employee_id: employee_id,date: date.strftime(%Y-%m-%d),late: False,early_leave: False,missing: False,work_hours: 0.0}in_time = Noneout_time = Nonefor rec in records:if rec.clock_type == 'in' and (in_time is None or rec.clock_time in_time):in_time = rec.clock_timeif rec.clock_type == 'out' and (out_time is None or rec.clock_time out_time):out_time = rec.clock_time# 规则判断standard_in = start_of_day.replace(hour=9, minute=0)standard_out = start_of_day.replace(hour=18, minute=0)if in_time is None:status[missing] = Trueelse:if in_time standard_in:status[late] = Trueif out_time is None:# 如果还没打下班卡,暂时不算早退,但工时无法计算passelse:if out_time standard_out:status[early_leave] = True# 计算工时if in_time and out_time:status[work_hours] = (out_time - in_time).total_seconds() / 3600return statusfinally:db.close()避坑指南:时区陷阱:datetime.now() 返回的是本地时间。如果你的服务器在 UTC,而你在国内看日志,时间会差 8 小时。务必在 utils.py 中统一使用 datetime.now(timezone.utc) 或强制指定时区。 多次打卡:代码中用了 in_time is None or rec.clock_time in_time 来取最早的一次上班卡。这是为了防止员工误触重复打卡导致时间混乱。运行与测试:如何验证代码真的通了 写完代码别急着欢呼,必须手动测试。我们不用复杂的单元测试框架,直接写个 test_manual.py 模拟流程。 from datetime import datetime from .database import init_db, SessionLocal from .models import Employee, ClockRecord from .services import AttendanceServicedef run_test():init_db()db = SessionLocal()# 1. 初始化测试数据emp = db.query(Employee).filter(Employee.name == TestUser).first()if not emp:emp = Employee(name=TestUser, department=IT)db.add(emp)db.commit()db.refresh(emp)# 清空旧数据db.query(ClockRecord).filter(ClockRecord.employee_id == emp.id).delete()db.commit()today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)# 2. 模拟打卡:09:30 上班 (迟到), 18:30 下班 (正常)db.add(ClockRecord(employee_id=emp.id, clock_time=today.replace(hour=9, minute=30), clock_type='in'))db.add(ClockRecord(employee_id=emp.id, clock_time=today.replace(hour=18, minute=30), clock_type='out'))db.commit()# 3. 执行统计result = AttendanceService.check_attendance(emp.id, today)print(f测试结果: {result})# 预期输出: late: True, early_leave: False, missing: Falseassert result[late] == True, 应该判定为迟到assert result[work_hours] 8, 工时应大于8小时print(✅ 测试通过!逻辑正确。)db.close()if __name__ == __main__:run_test()调试技巧: 如果在 check_attendance 里返回的数据不符合预期,不要猜。在 for rec in records 循环里加一行 print(rec.clock_time, rec.clock_type)。你会看到数据库里到底存了什么时间,什么类型。90% 的“逻辑错误”其实是“数据没存进去”或“时间格式不对”。 优化扩展与生产环境建议 目前这个系统能跑,但离生产环境还差几块砖:并发安全:SQLite 在写操作频繁时会锁库。如果未来用户量大,建议迁移到 PostgreSQL。参考 PostgreSQL 官方文档 中关于 MVCC(多版本并发控制)的章节,理解为什么它比 MySQL 的 InnoDB 在某些高并发读场景下表现更稳定。 缓存层:每天第一次查询某人的考勤时,结果可以缓存在 Redis 中 1 分钟。避免同一秒内多个请求重复查库。 日志审计:不要只用 print。引入 logging 模块,将每次打卡操作、规则判断结果写入文件。当 HR 投诉“明明没迟到为什么算迟到”时,日志就是你的救命稻草。 API 化:使用 FastAPI 将 AttendanceService 包装成 REST 接口。FastAPI 的类型提示功能可以自动校验请求参数,防止前端传错时间格式。小结 手写实现考勤统计软件的核心,不在于用了多高级的算法,而在于对数据流向的掌控。从 database.py 的路径配置,到 models.py 的字段定义,再到 services.py 的规则引擎,每一层都在解决“代码跑不通”的具体问题。 当你再次面对那些复制来的、满屏红字的代码时,不要盲目复制。先问自己三个问题:数据存在哪? 时间是怎么处理的? 边界条件(如缺卡、跨天)考虑了吗?你在项目里踩过这个坑吗?比如时间戳转换出错,或者数据库连接池耗尽?评论区聊聊,我们一起避坑。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

【外设】之大彩串口显示屏 2026/10/25 3:20:41

【外设】之大彩串口显示屏

大彩串口屏初步使用 1 .官网下载 STM32 屏幕 GUI 设计资料 http://www.gz-dc.com/category/typeid/4112 找到 STM32 Keil 工程,移植相关代码因项目而异进行移植,由于项目简单,本人只对用到的指令接口进行修改。 比如:注意事项&…

阅读更多 →
无法下载Windows系统iso文件 2026/10/25 3:43:49

无法下载Windows系统iso文件

当我遇到这个问题的时候,我打开了一个网站: 登录 然后我打算下载的时候: 突然那个官方的连接就可以下载了:

阅读更多 →
【清华代码熊】DeepSeek V4.1 Flash 后训练详解 2026/10/25 4:02:17

【清华代码熊】DeepSeek V4.1 Flash 后训练详解

📌 上期解析了 DeepSeek V4.1 Flash 模型架构改进,本期解析 DeepSeek V4.1 Flash 预训练/后训练技术: 🌟 预训练:45T 文本 多模态混合语料、直接训练 sparse attention(取消 DeepSeek V4 的 dense 冷启动&…

阅读更多 →
Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ... 2026/10/25 5:03:13

Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ...

文章主要内容和创新点 主要内容 本文聚焦于多模态大语言模型(MLLM)强化学习(RL)训练中的效率问题,提出了一个名为Shuffle-R1的框架。研究发现,当前RL训练存在两个关键缺陷: 优势值坍缩(Advantage Collapsing):批次中大多数优势值集中在零附近,导致有效梯度信号被淹…

阅读更多 →
PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction 2026/10/25 3:54:32

PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction

一、文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现个人身份信息(PII)脱敏的研究,旨在解决传统脱敏方法(如基于规则的系统、领域特定命名实体识别(NER)模型)泛化能力差、跨格式/跨语境适应性弱的问题。 研究通过全面评估多种LLM架构(包括密集型LLM(D-LLM…

阅读更多 →
LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model 2026/10/25 5:32:24

LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model

文章主要内容和创新点 主要内容 本文聚焦于二进制图像-文本相关性评估任务(判断图像与文本“相关”或“不相关”),针对该任务中文本格式多样、相关性定义随场景变化等挑战,提出了基于多模态大语言模型(MLLM)的解决方案LLaVA-RE。 模型设计:LLaVA-RE基于LLaVA 1.5架构,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉