You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Raspberry Pi的多用户考勤系统故障求助:多用户打卡逻辑异常

解决多用户考勤系统的状态混乱问题

核心问题分析

你用全局变量sign_in控制所有用户的打卡状态,这必然导致多用户场景下逻辑混乱——系统只会记住上一次操作的全局状态,而非每个用户独立的状态。必须改成从数据库读取当前用户的最新状态来判断打卡/退卡操作。

具体修改方案

  1. 移除全局状态变量:删掉sign_in和sign_out全局变量,每次读卡后单独查询当前用户的最新考勤记录。
  2. 查询用户最新状态:通过SQL获取该用户最后一条考勤记录的signed_in状态和clock_out值,以此判断操作类型。
  3. 分逻辑处理打卡/退卡:
    • 若用户无考勤记录,或最后一条记录signed_in=0且clock_out不为空(上次已正常退卡),则新增打卡记录,写入clock_in并设signed_in=1。
    • 若最后一条记录signed_in=1(用户处于打卡状态),则更新该记录的clock_out字段,同时设signed_in=0。
  4. 修复数据库操作问题:用参数化查询避免SQL注入,所有数据库操作后执行db.commit()确保数据即时写入。

修改后的完整代码

#!/usr/bin/env python
import time
import datetime
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import drivers

# 数据库连接
db = mysql.connector.connect(
  host="localhost",
  user="xxx",
  passwd="xxx",
  database="attendancesystem"
)

cursor = db.cursor()
reader = SimpleMFRC522()
display = drivers.Lcd()

try:
  while True:
    display.lcd_clear()
    display.lcd_display_string("Transponder", 1)
    display.lcd_display_string("platzieren", 2)
    
    # 读取RFID卡
    id, text = reader.read()
    current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    # 查询用户信息
    cursor.execute("SELECT id, name FROM users WHERE rfid_uid = %s", (id,))
    user = cursor.fetchone()

    display.lcd_clear()
    if not user:
      display.lcd_display_string("Existiert nicht.", 1)
      time.sleep(2)
      continue

    user_id, user_name = user
    # 查询该用户最新的考勤记录
    cursor.execute("""
      SELECT signed_in, clock_out 
      FROM attendance 
      WHERE user_id = %s 
      ORDER BY id DESC 
      LIMIT 1
    """, (user_id,))
    latest_record = cursor.fetchone()

    # 处理打卡/退卡逻辑
    if not latest_record or (latest_record[0] == 0 and latest_record[1] is not None):
      # 无记录或已退卡,执行打卡
      cursor.execute("""
        INSERT INTO attendance (user_id, clock_in, signed_in) 
        VALUES (%s, %s, 1)
      """, (user_id, current_time))
      display.lcd_display_string(f"Angemeldet {user_name}", 1)
    elif latest_record[0] == 1:
      # 已打卡,执行退卡
      cursor.execute("""
        UPDATE attendance 
        SET clock_out = %s, signed_in = 0 
        WHERE user_id = %s 
        ORDER BY id DESC 
        LIMIT 1
      """, (current_time, user_id))
      display.lcd_display_string(f"Abgemeldet {user_name}", 1)
    else:
      # 异常状态(比如存在未完成的打卡记录)
      display.lcd_display_string("Fehler: Status", 1)
      display.lcd_display_string("ungültig", 2)

    # 提交数据库修改
    db.commit()
    time.sleep(2)

finally:
  GPIO.cleanup()
  cursor.close()
  db.close()

额外注意事项

  • 数据库索引优化:给attendance表的user_id字段加索引,加快最新记录的查询速度。
  • 异常处理:可给数据库操作添加try-except捕获异常,避免系统因数据库错误崩溃。
  • 资源释放:代码末尾关闭数据库游标和连接,避免资源泄漏。

内容的提问来源于stack exchange,提问作者M. Pablo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 01:03:05