from apps.am.models import Access, Area from apps.am.tasks import cache_areas_info from apps.hrm.models import Employee from apps.system.models import User from apps.third.clients import xxClient from apps.third.models import TDevice from apps.third.tapis import xxapis from apps.utils.queryset import get_child_queryset2 from django.core.cache import cache import time import shapely.geometry def get_area_info_from_cache(target: str, cache: list): for i in cache: if i['id'] == target: return i return None class EcmService: """事件处理服务 """ ep_default_dict = { 'area_fix_id': None, # 当前所在固定区域ID 'time0': None, # 定位首次出现时间戳 "time1": None, # 首次在该区域时间戳 "time2": int(time.time()), # 当前时间戳 } def create_remind_and_speak(cls): """ 创建事件提醒并发送短信/微信/音响 """ pass @classmethod def dispatch_dahua_event(cls, data: dict): """分发大华事件进行处理 """ pass @classmethod def dispatch_xunxi_event(cls, data: dict): """分发寻息事件进行处理 """ if data.type == 'rail': if data.data.type == 1: # 围栏进入 cls.rail_in(data=data.data) elif data.data.type == 2: # 围栏离开 cls.rail_out(data=data.data) elif data.type == 'onKeyAlarm': # 一键呼救 cls.one_key_alarm(data=data) elif data.type == 'location': # 定位信息 cls.loc_change(data=data) elif data.type == 'onOffLine': if data.data.online: # 标签定位在线 pass else: # 标签定位离线 pass elif data.type == 'lowpower': # 低电量 cls.low_power(data=data.data) elif data.type == 'bltOnOffLineV2': if data.data.online: # 标签通信在线 pass else: # 标签通信离线 pass @classmethod def rail_in(cls, data): """围栏进入事件 """ # 找到所在围栏 area = Area.objects.filter(third_info__xx_rail__id=data['railId']).first() # 找到进入对象 blts = TDevice.objects.filter(code=data['userId']).first() if area and blts and blts.employee: # 如果是人 if area.type == Area.AREA_TYPE_FIX: # 更新人员位置信息缓存 key_str = f'ep_{blts.employee.id}' ep_loc_dict = cache.get_or_set( key_str, cls.ep_default_dict, timeout=None ) if ep_loc_dict['area_fix_id'] != area.id: # 如果区域未变化则不动 ep_loc_dict['time1'] = ep_loc_dict['time2'] ep_loc_dict['area_fix_id'] = area.id cache.set(key_str, ep_loc_dict) ep_blt = blts.employee # 标签绑定人员 if ep_blt: for i in Access.objects.filter(area=area).order_by('sort'): # 优先自定义权限过滤 if i.post: # 如果是按岗位设定的 eps_access = Employee.objects.filter(user__posts=i.post) if ep_blt in eps_access and i.type == Access.ACCESS_IN_YES: return elif ep_blt in eps_access and i.type == Access.ACCESS_IN_NO: # 触发非法进入事件 pass elif i.dept: # 如果是按部门设定的 if i.dept.type == 'dept': # 如果是内部部门 depts = get_child_queryset2(i.dept) if ep_blt.belong_dept in depts and i.type == Access.ACCESS_IN_YES: return elif ep_blt.belong_dept in depts and i.type == Access.ACCESS_IN_NO: # 触发非法进入事件 pass elif i.dept.type == 'rparty': # 如果是相关方 if ep_blt.belong_dept == i.dept and i.type == Access.ACCESS_IN_YES: return elif ep_blt.belong_dept == i.dept and i.type == Access.ACCESS_IN_NO: # 触发非法进入事件 pass elif i.employee: # 如果是按人设定的 if ep_blt == i.employee and i.type == Access.ACCESS_IN_YES: return elif ep_blt == i.employee and i.type == Access.ACCESS_IN_NO: # 触发非法进入事件 pass # 通用权限设置过滤 if ep_blt.type == 'employee' and area.employee_yes: return elif ep_blt.type == 'remployee' and area.remployee_yes: return elif ep_blt.type == 'visitor' and area.visitor_yes: return else: # 触发非法进入事件 pass elif area and (not blts): # 触发未知标签进入事件 pass @classmethod def rail_out(cls, data): pass @classmethod def low_power(cls, data): # 有绑定对象再提示低电量 blts = TDevice.objects.filter(code=data['userId']).first() if blts.employee: # 触发低电量提醒事件 pass @classmethod def one_key_alarm(cls, data): pass @classmethod def loc_change(cls, data): blts = TDevice.objects.filter(code=data['userId']).first() if blts.employee: # 从缓存查询人员位置信息 time2 = int(time.time()) key_str = f'ep_{blts.employee.id}' ep_loc_dict = cache.get_or_set( key_str, cls.ep_default_dict, timeout=None ) ep_loc_dict['time2'] = time2 # 从缓存里获取固定区域列表信息 area_fix_list = cache.get('area_fix_list', None) if not area_fix_list: area_fix_list = cache_areas_info() if ep_loc_dict.get('area_fix_id', None): # 如果存在所在固定区域 area_info = get_area_info_from_cache(ep_loc_dict['area_fix_id'], area_fix_list) if area_info: # 在该固定区域停留时间(分钟) stay_minute = int((ep_loc_dict['time2']-ep_loc_dict['time1'])/60) # 判断停留时间是否合理 # 先通过自定义权限过滤(暂未做) # 再经过通用设置过滤 if 0 < stay_minute < area_info['stay_minute_min']: # 触发离岗事件 return elif area_info['stay_minute_max'] < stay_minute: # 触发超时滞留事件 return else: for i in area_fix_list: if data['floorNo'] == i['floor_no']: point = shapely.geometry.Point(data['xMillimeter'], data['yMillimeter']) if i['poly_shape'].intersects(point): # 如果点在多边形中 ep_loc_dict['time1'] = time2 ep_loc_dict['are_id'] = i['area_fix_id'] ep_loc_dict['time2'] = time2 cache.set(key_str, ep_loc_dict)