Appointment.utils.utils 源代码

from datetime import timedelta, date, datetime

from django.http import HttpRequest
from django.db.models import Q, QuerySet

from Appointment.models import Room, Appoint, Participant

'''
YWolfeee:
utils.py中保存了一些比较杂碎的带有信息量的数据,例如对应表等。
微信消息的发送、日志的写入也在本文件中,使用前可以看一下代码的说明。
所有和scheduler无关、和互联网交互无关的工具函数,可以在本文件中实现。
'''

ip_room_dict = {
    "152": "B104",
    "155": "B104",
    "132": "B106",
    "153": "B106",
    "131": "B107A",
    "135": "B107B",
    "134": "B108",
    "151": "B108",
    "146": "B111",
    "149": "B111",
    "141": "B112",
    "148": "B112",
    # "138": "B114", # 不准 自习室
    "139": "B114",
    "144": "B118",
    "145": "B118",
    "140": "B119",
    "147": "B119",
    "129": "B205",
    "102": "B206",
    "106": "B206",
    "105": "B207",
    "107": "B207",
    "110": "B208",
    "111": "B208",
    "103": "B209",
    "108": "B209",
    "121": "B214",
    "128": "B214",  # 镜子 舞蹈室
    "119": "B215",
    "117": "B216",
    "124": "B216",  # 镜子 跑步机房
    "122": "B217",
    "126": "B217",
    "113": "B218",
    "120": "B220",
    "130": "B220",
    "112": "B221",  # 琴房 看不到门口谱子位置
    "123": "B221",  # 琴房 看不到小提琴位
    "118": "B222",
    "125": "B222",
}

door_room_dict = {
    "2020092016162884": "B104",
    "2020092016370963": "B106A",
    "2020092016422704": "B106B",
    "2020092016464351": "B107A",
    "2020092016550340": "B108A",
    "2020092017010542": "B108B",
    "2020092017070505": "B107B",
    "2020092017084647": "B000",  # 值班室
    "2020092017233640": "B112A",
    "2020092017234462": "B112B",
    "2020092017235201": "B111",
    "2020092017393941": "B114A",
    "2020092017475922": "B114B",
    "2020092017481264": "B118",
    "2020092017482150": "B119",
    "2020092018023538": "B218",
    "2020092018030345": "B220",
    "2020092018031303": "B221",
    "2020092018032470": "B222",
    "2020092018182960": "B214A",
    "2020092018184631": "B214B",
    "2020092018185928": "B216",
    "2020092018201454": "B217",
    "2020092018400410": "B209",
    "2020092018521223": "B205",
    "2020092018522586": "B206A",
    "2020092018523750": "B206B",
    "2020092018525770": "B208",
    "2022082709581351": "B216",
}

# 给定摄像头ip后三位,返回摄像头对应的Rid


[文档] def ip2room(ip): return ip_room_dict[ip]
# 给定房间门牌号id,返回对应的Rid
[文档] def door2room(door): return door_room_dict[door]
[文档] def check_temp_appoint(room: Room) -> bool: return '研讨' in room.Rtitle
# 获取当日预约总时长,不含长期预约和面试
[文档] def get_total_appoint_time(appointer: Participant, day: date, lock=False) -> timedelta: # 获取当日预约,不含长期预约和面试 appoints = appointer.appoint_list.filter(Astart__date=day).exclude( Atype__in=(Appoint.Type.LONGTERM, Appoint.Type.INTERVIEW) ).exclude( Astatus=Appoint.Status.CANCELED ) if lock: appoints = appoints.select_for_update() # 计算总时长 total_time = timedelta() for appoint in appoints: total_time += appoint.Afinish - appoint.Astart return total_time
# 获取预约者同时进行的预约,不含长期预约和面试
[文档] def get_overlap_appoints(appointer: Participant, start_time: datetime, finish_time: datetime) -> QuerySet[Appoint]: parallel_appoints = appointer.appoint_list.exclude( Atype__in=(Appoint.Type.LONGTERM, Appoint.Type.INTERVIEW) ).exclude( Astatus=Appoint.Status.CANCELED ).exclude( Q(Afinish__lte=start_time) | Q(Astart__gte=finish_time) ).all() return parallel_appoints
[文档] def get_conflict_appoints(appoint: Appoint, times: int = 1, interval: int = 1, week_offset: int = 0, exclude_this: bool = False, no_cross_day=False, lock=False) -> QuerySet[Appoint]: ''' 获取以时间排序的冲突预约,可以加锁,但不负责开启事务,不应抛出异常 :param appoint: 需要检测的第一个预约 :type appoint: Appoint :param times: 检测次数, defaults to 1 :type times: int, optional :param interval: 每次间隔的周数, defaults to 1 :type interval: int, optional :param week_offset: 第一次检测时间距离提供预约的周数, defaults to 0 :type week_offset: int, optional :param exclude_this: 排除检测的预约, defaults to False :type exclude_this: bool, optional :param no_cross_day: 是否假设预约都不跨天,可以简化查询, defaults to False :type no_cross_day: bool, optional :param lock: 查询时上锁, defaults to False :type lock: bool, optional :return: 时间升序排序的冲突预约集 :rtype: QuerySet[Appoint] ''' # 获取该房间的所有有效预约 activate_appoints = Appoint.objects.not_canceled().filter(Room=appoint.Room) if lock: activate_appoints = activate_appoints.select_for_update() # 空的Q对象进行与和或运算的结果都是另一个操作数 conditions = Q() if no_cross_day: conditions &= Q( # 开始比当前的结束时间早,结束比当前的开始时间晚 Astart__time__lt=appoint.Afinish.time(), Afinish__time__gt=appoint.Astart.time(), ) date_range = [ appoint.Astart.date() + timedelta(weeks=week + week_offset) for week in range(0, times * interval, interval) ] conditions &= Q( Astart__date__in=date_range, Afinish__date__in=date_range, ) else: for week in range(0, times * interval, interval): conditions |= Q( # 开始比当前的结束时间早 Astart__lt=appoint.Afinish + \ timedelta(weeks=week + week_offset), # 结束比当前的开始时间晚 Afinish__gt=appoint.Astart + \ timedelta(weeks=week + week_offset), ) # 检查时预约还不应创建,冲突预约可以包含自身 if conditions == Q(): conflict_appoints = activate_appoints.none() else: conflict_appoints = activate_appoints.filter(conditions) if exclude_this: conflict_appoints = conflict_appoints.exclude(pk=appoint.pk) return conflict_appoints.order_by('Astart', 'Afinish')
[文档] def to_feedback_url(request: HttpRequest) -> str: """ 检查预约记录是否可以申诉。 如果可以,向session添加传递到反馈填写界面的信息。 最终函数返回跳转到的url。 :param request: http请求 :type request: HttpRequest :return: 即将跳转到的url :rtype: str """ # 首先检查预约记录是否存在 try: Aid = request.POST['feedback'] appoint: Appoint = Appoint.objects.get(Aid=Aid) except: raise AssertionError("预约记录不存在!") # 然后检查预约记录是否可申诉 assert appoint.Astatus in ( Appoint.Status.VIOLATED, Appoint.Status.JUDGED, ), "该预约记录不可申诉!" appoint_student = appoint.major_student.name appoint_room = str(appoint.Room) appoint_start = appoint.Astart.strftime('%Y年%m月%d日 %H:%M') appoint_finish = appoint.Afinish.strftime('%H:%M') appoint_reason = appoint.get_status() # 向session添加信息 request.session['feedback_type'] = '地下室预约问题反馈' request.session['feedback_url'] = appoint.get_admin_url() request.session['feedback_content'] = '\n'.join(( f'申请人:{appoint_student}', f'房间:{appoint_room}', f'预约时间:{appoint_start} - {appoint_finish}', f'违规原因:{appoint_reason}', )) # 最终返回填写feedback的url return '/feedback/?argue'