Appointment.appoint.status_control 源代码

from datetime import datetime, timedelta

from Appointment.config import appointment_config as CONFIG
from Appointment.models import Appoint
from Appointment.appoint.judge import appoint_violate
from Appointment.utils.log import logger, get_user_logger
from Appointment.extern.wechat import MessageType, notify_appoint


def _adjusted_rate(original_rate: float, appoint: Appoint) -> float:
    '''获取用于调整不同情况下的合格率要求'''
    rate = original_rate
    if appoint.Room.Rid in {'B109A', 'B207'}:   # 公共区域
        return 0
    elif appoint.Room.Rid.startswith('R'):      # 俄文楼
        return 0
    elif appoint.Room.Rid == 'B214':            # 暂时无法识别躺姿
        rate -= 0.15                # 建议在0.1-0.2之间 前者最严 后者最宽松
    elif appoint.Room.Rid == 'B107B':           # 无法监控摄像头正下方
        rate -= 0.05                # 建议在0-0.1之间 因为主要是识别出的人数问题
    elif appoint.Room.Rid == 'B217':
        if appoint.Astart.hour >= 20 :          # 电影关灯导致识别不准确
            rate -= 0.05            # 建议在0-0.1之间 因为主要是识别出的人数问题

    MIN31 = timedelta(minutes=31)
    if appoint.Atype == Appoint.Type.TEMPORARY: # 临时预约不检查摄像头
        return 0
    if appoint.Atype == Appoint.Type.LONGTERM:  # 长期预约不检查摄像头
        return 0
    if appoint.Afinish - appoint.Astart < MIN31:    # 短预约早退晚到影响更大
        rate -= 0.01             # 建议在0-0.1之间 基本取消了
    if appoint.Areason == Appoint.Reason.R_LATE:    # 迟到需要额外保证使用率
        rate += 0.05             # 建议在0.2-0.4之间 极端可考虑0.5 目前仅测试
    return rate


[文档] def start_appoint(appoint_id: int): '''预约开始,切换状态''' try: appoint = Appoint.objects.get(Aid=appoint_id) except: return logger.exception(f"预约{appoint_id}意外消失") if appoint.Astatus == Appoint.Status.APPOINTED: # 顺利开始 appoint.Astatus = Appoint.Status.PROCESSING appoint.save() logger.info(f"预约{appoint_id}成功开始: 状态变为进行中") elif appoint.Astatus == Appoint.Status.PROCESSING: # 已经开始 logger.info(f"预约{appoint_id}在检查时已经开始") elif appoint.Astatus != Appoint.Status.CANCELED: # 状态异常,本该不存在这个任务 logger.error(f"预约{appoint_id}的状态异常: {appoint.get_status()}")
def _teminate_handler(appoint: Appoint): if appoint.Astatus == Appoint.Status.CONFIRMED: # 可能已经判定通过,如公共区域和俄文楼 rid = appoint.Room.Rid if rid[:1] != 'R' and rid not in {'B109A', 'B207'}: logger.warning(f"预约{appoint.pk}提前合格: {rid}房间") elif appoint.Astatus != Appoint.Status.CANCELED: # 状态异常,多半是已经判定过了 logger.warning(f"预约{appoint.pk}提前终止: {appoint.get_status()}")
[文档] def finish_appoint(appoint_id: int): ''' 结束预约 - 接受单个预约id - 可以处理任何状态的预约 - 对于非终止状态,判断人数是否合格,并转化为终止状态 要注意的是,由于定时任务可能执行多次,第二次的时候可能已经终止 ''' try: appoint: Appoint = Appoint.objects.get(Aid=appoint_id) except: return logger.exception(f"预约{appoint_id}意外消失") # 如果处于非终止状态,只需检查人数判断是否合格 if appoint.Astatus in Appoint.Status.Terminals(): return _teminate_handler(appoint) # 希望接受的非终止状态只有进行中,但其他状态也同样判定是否合格 if appoint.Astatus != Appoint.Status.PROCESSING: get_user_logger(appoint).error( f"预约{appoint_id}结束时状态为{appoint.get_status()}:照常检查是否合格") # 摄像头出现超时问题,直接通过 if datetime.now() - appoint.Room.Rlatest_time > timedelta(minutes=15): appoint.Astatus = Appoint.Status.CONFIRMED # waiting appoint.save() get_user_logger(appoint).info(f"预约{appoint_id}的状态已确认: 顺利完成") return # 检查人数是否足够 adjusted_rate = _adjusted_rate(CONFIG.camera_qualify_rate, appoint) need_num = appoint.Acamera_check_num * adjusted_rate - 0.01 check_failed = appoint.Acamera_ok_num < need_num if check_failed: # 迟到的预约通知在这里处理。如果迟到不扣分,删掉这个if的内容即可 # 让下面那个camera check的if判断是否违规。 if appoint.Areason == Appoint.Reason.R_LATE: reason = Appoint.Reason.R_LATE else: reason = Appoint.Reason.R_TOOLITTLE if appoint_violate(appoint, reason): appoint.refresh_from_db() notify_appoint(appoint, MessageType.VIOLATED, appoint.get_status(), students_id=[appoint.get_major_id()]) else: # 通过 appoint.Astatus = Appoint.Status.CONFIRMED appoint.save() logger.info(f"预约{appoint_id}人数合格,已通过")