作业过程中动态执行视频监控
This commit is contained in:
parent
811f96fe83
commit
1806eb80bb
|
@ -143,6 +143,11 @@ class TestViewSet(CustomGenericViewSet):
|
|||
ret = {}
|
||||
task = show.delay(*vdata.get('args', []), **vdata.get('kwargs', {}))
|
||||
ret['task_id'] = task.task_id
|
||||
# from celery.app.control import Control
|
||||
# from server.celery import app
|
||||
# celery_control = Control(app=app)
|
||||
# # 关闭作业监控任务
|
||||
# res = celery_control.revoke(task.task_id, terminate=True)
|
||||
return Response(ret)
|
||||
|
||||
@action(methods=['post'], detail=False, serializer_class=Serializer)
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2.12 on 2022-08-11 06:03
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('opm', '0002_initial'),
|
||||
('ecm', '0013_auto_20220810_1512'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='operation',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='opm.operation', verbose_name='关联作业'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventcate',
|
||||
name='opl_cates',
|
||||
field=models.ManyToManyField(to='opm.OplCate', verbose_name='关联许可证'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.2.12 on 2022-08-12 09:15
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('opm', '0002_initial'),
|
||||
('ecm', '0014_auto_20220811_1403'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='event',
|
||||
name='operation',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='opl',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='opm.opl', verbose_name='关联许可证'),
|
||||
),
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
from django.db import models
|
||||
from apps.am.models import Area
|
||||
from apps.hrm.models import Employee
|
||||
from apps.opm.models import Opl, OplCate
|
||||
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBModel
|
||||
from apps.system.models import Post, User
|
||||
from apps.third.models import TDevice
|
||||
|
@ -28,6 +29,7 @@ class EventCate(CommonAModel):
|
|||
default=Area.AREA_1)
|
||||
hanle_minute = models.PositiveSmallIntegerField('处理时间', default=0, help_text='超过处理时间事件状态变为超时未处理,0代表未配置')
|
||||
same_allow_minute = models.PositiveSmallIntegerField('允许时间', default=0, help_text='同一对象同事件多长时间内不再触发, 0代表一直触发')
|
||||
opl_cates = models.ManyToManyField(OplCate, verbose_name='关联许可证')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
@ -83,6 +85,7 @@ class Event(CommonBModel):
|
|||
area = models.ForeignKey(Area, verbose_name='发生区域', on_delete=models.CASCADE, null=True, blank=True)
|
||||
vchannel = models.ForeignKey(TDevice, verbose_name='抓拍设备', on_delete=models.CASCADE, null=True, blank=True)
|
||||
location = models.JSONField('事件点位坐标', default=dict, null=False, blank=True)
|
||||
opl = models.ForeignKey(Opl, verbose_name='关联许可证', on_delete=models.CASCADE, null=True, blank=True)
|
||||
obj_cate = models.CharField('发生对象', max_length=20, help_text='people(人员)/...')
|
||||
employee = models.ForeignKey(Employee, verbose_name='当事人',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
|
|
|
@ -78,6 +78,7 @@ class EventSerializer(serializers.ModelSerializer):
|
|||
area_ = AreaSerializer(source='area', read_only=True)
|
||||
cates_ = EventCateSimpleSerializer(source='cates', read_only=True, many=True)
|
||||
employee_ = EmployeeSerializer(source='employee', read_only=True)
|
||||
vchannel_ = TDeviceSimpleSerializer(source='vchannel', read_only=True)
|
||||
handle_user_name = serializers.CharField(source='handle_user.name', read_only=True)
|
||||
face_img = MyFilePathField()
|
||||
global_img = MyFilePathField()
|
||||
|
|
|
@ -77,7 +77,7 @@ def algo_handle(codes: list, data: dict):
|
|||
return ['helmet']
|
||||
|
||||
|
||||
def notify_event(event: Event):
|
||||
def notify_event(event: Event, voice_msg=''):
|
||||
"""事件后续处理:
|
||||
|
||||
Args:
|
||||
|
@ -87,7 +87,7 @@ def notify_event(event: Event):
|
|||
ep = event.employee
|
||||
obj_cate = event.obj_cate
|
||||
params = {'area': event.area.name, 'employee': '', 'event': ''}
|
||||
if obj_cate == 'people' and ep:
|
||||
if ep:
|
||||
ep_name = ep.name
|
||||
ep_type = '员工'
|
||||
if ep.type == 'rempoyee':
|
||||
|
@ -97,11 +97,14 @@ def notify_event(event: Event):
|
|||
params['employee'] = ep_type + ep_name
|
||||
elif obj_cate == 'people':
|
||||
params['employee'] = '未知人员'
|
||||
elif obj_cate == 'area':
|
||||
params['employee'] = '区域'
|
||||
for i in event.cates.all():
|
||||
params['event'] = params['event'] + i.name + ','
|
||||
event.voice_msg = '位于{}的{},{}请及时处理'.format(params['area'], params['employee'], params['event'])
|
||||
if params['employee']:
|
||||
event.voice_msg = '位于{}的{},{}请及时处理'.format(params['area'], params['employee'], params['event'])
|
||||
else:
|
||||
event.voice_msg = '在{}下,发生{}请及时处理'.format(params['area'], params['event'])
|
||||
if voice_msg:
|
||||
event.voice_msg = voice_msg
|
||||
event.save()
|
||||
# 喇叭播放
|
||||
Thread(target=save_voice_and_speak, args=(event,), daemon=True).start()
|
||||
|
@ -119,18 +122,19 @@ def save_voice_and_speak(event: Event):
|
|||
v_p, v_num = main_cate.voice_person, main_cate.voice_num
|
||||
_, event.voice, _ = generate_voice(event.voice_msg, v_p)
|
||||
event.save()
|
||||
if event.area: # 如果事件存在发生区域
|
||||
sps = list(TDevice.objects.filter(area=event.area, type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
|
||||
if len(sps) == 0: # 如果当前区域没有喇叭就找覆盖区的喇叭
|
||||
sps = list(TDevice.objects.filter(areas=event.area,
|
||||
type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
|
||||
# 查找固定喇叭
|
||||
for m in event.cates.all():
|
||||
for n in m.speakers.all():
|
||||
if n.code not in sps:
|
||||
sps.append(n.code)
|
||||
if sps:
|
||||
spClient.speak(event.voice, sps, v_num)
|
||||
if main_cate.speaker_on:
|
||||
if event.area: # 如果事件存在发生区域
|
||||
sps = list(TDevice.objects.filter(area=event.area, type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
|
||||
if len(sps) == 0: # 如果当前区域没有喇叭就找覆盖区的喇叭
|
||||
sps = list(TDevice.objects.filter(areas=event.area,
|
||||
type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
|
||||
# 查找固定喇叭
|
||||
for m in event.cates.all():
|
||||
for n in m.speakers.all():
|
||||
if n.code not in sps:
|
||||
sps.append(n.code)
|
||||
if sps:
|
||||
spClient.speak(event.voice, sps, v_num)
|
||||
|
||||
|
||||
def create_remind(event: Event, params: dict):
|
||||
|
@ -221,10 +225,10 @@ def dispatch_dahua_event(data: dict):
|
|||
event = None
|
||||
if alarm_type in [1001003, 1001000] and vchannel: # 内部人员/或陌生人报警
|
||||
# 查看加载的算法
|
||||
algo_codes = list(AlgoChannel.objects.filter(vchannel=vchannel).exclude(
|
||||
algo_codes = list(AlgoChannel.objects.filter(vchannel=vchannel, algo__self_algo=True).exclude(
|
||||
algo__code=None).order_by('algo__priority', 'algo__create_time').values_list('algo__code', flat=True))
|
||||
area = vchannel.area # 视频所在区域
|
||||
if algo_codes and area: # 如果加载了算法且视频通道绑定区域才继续
|
||||
if algo_codes: # 如果加载了算法才继续
|
||||
face_img_o = dhClient.get_full_pic(data['info']['alarmPicture'])
|
||||
global_img_o = dhClient.get_full_pic(data['info']['extend']['globalScenePicUrl'])
|
||||
obj_cate = 'people'
|
||||
|
@ -250,6 +254,59 @@ def dispatch_dahua_event(data: dict):
|
|||
'cate': i,
|
||||
'event': event
|
||||
})
|
||||
elif alarm_type in [302, 303] and vchannel:
|
||||
ec = EventCate.objects.filter(code=str(alarm_type)).first()
|
||||
event = None
|
||||
global_img_o = dhClient.get_full_pic(data['info']['alarmPicture'])
|
||||
happen_time = timestamp_to_time(int(data['info']['alarmDate']))
|
||||
if ec: # 先查看是否有定义该事件种类
|
||||
event = Event()
|
||||
event.global_img = save_dahua_pic(global_img_o)
|
||||
event.area = vchannel.area
|
||||
event.obj_cate = 'other'
|
||||
event.vchannel = vchannel
|
||||
event.happen_time = happen_time
|
||||
event.save()
|
||||
Eventdo.objects.get_or_create(cate=ec, event=event, defaults={
|
||||
'cate': ec,
|
||||
'event': event
|
||||
})
|
||||
# 查看加载的算法
|
||||
algo_codes = list(AlgoChannel.objects.filter(vchannel=vchannel, algo__self_algo=True).exclude(
|
||||
algo__code=None).order_by('algo__priority', 'algo__create_time').values_list('algo__code', flat=True))
|
||||
if algo_codes:
|
||||
ec_codes = algo_handle(algo_codes, data={}) # 算法处理
|
||||
if ec_codes:
|
||||
# 获取本次所有发生事件种类
|
||||
ecs = EventCate.objects.filter(code__in=ec_codes)
|
||||
obj_cate = 'other'
|
||||
ep = None
|
||||
if 'helmet' in ec_codes:
|
||||
# 如果存在安全帽事件
|
||||
# 尝试以图搜图找到当事人
|
||||
res = dhClient.face_search(path=global_img_o)
|
||||
if res and res[0]:
|
||||
ep = Employee.objects.filter(id_number=res[0]['identity']).first()
|
||||
if ep:
|
||||
obj_cate = 'people'
|
||||
if event is None: # 如果未创建事件
|
||||
event = Event()
|
||||
event.global_img = save_dahua_pic(global_img_o)
|
||||
event.area = vchannel.area
|
||||
event.obj_cate = obj_cate
|
||||
event.employee = ep
|
||||
event.vchannel = vchannel
|
||||
event.happen_time = happen_time
|
||||
event.save()
|
||||
else:
|
||||
event.obj_cate = obj_cate
|
||||
event.employee = ep
|
||||
event.save()
|
||||
for i in ecs:
|
||||
Eventdo.objects.get_or_create(cate=i, event=event, defaults={
|
||||
'cate': i,
|
||||
'event': event
|
||||
})
|
||||
if event:
|
||||
notify_event(event)
|
||||
|
||||
|
@ -450,7 +507,7 @@ def blt_online(data):
|
|||
blts = TDevice.objects.filter(code=data['userId']).first()
|
||||
if blts.employee:
|
||||
ep = blts.employee
|
||||
if ep.type == 'employee' and ep.is_at_work is False:
|
||||
if ep.type == 'employee' and ep.is_atwork is False:
|
||||
# 上班打卡
|
||||
now = timezone.now()
|
||||
cr_10 = ClockRecord.objects.filter(type=10, employee=ep, create_time__year=now.year,
|
||||
|
@ -468,7 +525,8 @@ def blt_online(data):
|
|||
cr_10.trigger = 'location'
|
||||
cr_10.detail = data
|
||||
cr_10.save()
|
||||
ep.is_at_work = True
|
||||
ep.is_atwork = True
|
||||
ep.last_check_time = now
|
||||
ep.save()
|
||||
|
||||
|
||||
|
@ -477,7 +535,7 @@ def blt_offline(data):
|
|||
# 定位离线
|
||||
if blts.employee:
|
||||
ep = blts.employee
|
||||
if ep.type == 'employee' and ep.is_at_work:
|
||||
if ep.type == 'employee' and ep.is_atwork:
|
||||
# 下班打卡
|
||||
now = timezone.now()
|
||||
cr_20 = ClockRecord.objects.filter(type=20, employee=ep, create_time__year=now.year,
|
||||
|
@ -495,7 +553,8 @@ def blt_offline(data):
|
|||
cr_20.trigger = 'location'
|
||||
cr_20.detail = data
|
||||
cr_20.save()
|
||||
ep.is_at_work = False
|
||||
ep.is_atwork = False
|
||||
ep.last_check_time = now
|
||||
ep.save()
|
||||
|
||||
|
||||
|
|
|
@ -6,11 +6,16 @@ from celery import shared_task
|
|||
|
||||
from apps.am.models import Area
|
||||
from apps.ecm.models import EventCate, Eventdo
|
||||
from apps.ecm.service import notify_event
|
||||
from apps.ecm.service import algo_handle, notify_event, save_dahua_pic
|
||||
from apps.hrm.models import Employee
|
||||
from apps.opm.models import Opl
|
||||
from apps.third.clients import xxClient
|
||||
from apps.third.clients import dhClient
|
||||
from apps.third.models import TDevice
|
||||
from apps.third.tapis import xxapis
|
||||
from django.utils import timezone
|
||||
import time
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -46,7 +51,8 @@ def handle_xx_event_3(name: str, area: Area):
|
|||
'cate': cate,
|
||||
'event': event
|
||||
})
|
||||
notify_event(event)
|
||||
voice_msg = area.name + '下有' + str(area.count) + '人,' + cate.name + ',请及时处理'
|
||||
notify_event(event, voice_msg=voice_msg)
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -67,3 +73,55 @@ def check_event_timeout():
|
|||
if cate.hanle_minute > 0 and (timezone.now()-i.create_time).seconds > cate.hanle_minute * 60:
|
||||
i.is_timeout = True
|
||||
i.save()
|
||||
|
||||
|
||||
@shared_task
|
||||
def snap_and_analyse(code: str, algo_codes: list, opl_id: str):
|
||||
global_img_o = dhClient.snap(code)
|
||||
happen_time = timezone.now()
|
||||
vchannel = TDevice.objects.filter(code=code).first()
|
||||
ec_codes = algo_handle(algo_codes, data={}) # 算法处理返回的事件结果
|
||||
if ec_codes:
|
||||
# 获取本次所有发生事件种类
|
||||
ecs = EventCate.objects.filter(code__in=ec_codes)
|
||||
obj_cate = 'other'
|
||||
ep = None
|
||||
if 'helmet' in ec_codes:
|
||||
# 如果存在安全帽事件
|
||||
# 尝试以图搜图找到当事人
|
||||
res = dhClient.face_search(path=global_img_o)
|
||||
if res and res[0]:
|
||||
ep = Employee.objects.filter(id_number=res[0]['identity']).first()
|
||||
if ep:
|
||||
obj_cate = 'people'
|
||||
event = Event()
|
||||
event.global_img = save_dahua_pic(global_img_o)
|
||||
if vchannel:
|
||||
event.vchannel = vchannel
|
||||
event.area = vchannel.area
|
||||
event.obj_cate = obj_cate
|
||||
event.employee = ep
|
||||
event.happen_time = happen_time
|
||||
event.opl = Opl.objects.get(id=opl_id)
|
||||
event.save()
|
||||
for i in ecs:
|
||||
Eventdo.objects.get_or_create(cate=i, event=event, defaults={
|
||||
'cate': i,
|
||||
'event': event
|
||||
})
|
||||
if event:
|
||||
notify_event(event)
|
||||
|
||||
|
||||
@shared_task
|
||||
def opl_task(vc_codes: list, opl_id: str):
|
||||
"""作业监控任务
|
||||
"""
|
||||
opl_cate = Opl.objects.get(id=opl_id).cate
|
||||
# 找到加载的算法
|
||||
algo_codes = list(EventCate.objects.filter(opl_cates=opl_cate).values_list('code', flat=True))
|
||||
while True:
|
||||
for i in vc_codes:
|
||||
snap_and_analyse.delay(i, algo_codes, opl_id)
|
||||
time.sleep(2)
|
||||
time.sleep(4)
|
||||
|
|
|
@ -75,7 +75,7 @@ class EventViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
|
|||
perms_map = {'get': '*'}
|
||||
queryset = Event.objects.all()
|
||||
serializer_class = EventSerializer
|
||||
select_related_fields = ['area', 'employee', 'handle_user']
|
||||
select_related_fields = ['area', 'employee', 'handle_user', 'vchannel']
|
||||
prefetch_related_fields = ['cates']
|
||||
filterset_class = EventFilterSet
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ class ClockRecordFilterSet(filters.FilterSet):
|
|||
|
||||
class Meta:
|
||||
model = ClockRecord
|
||||
fields = ['employee', 'create_time_start', 'create_time_end', 'year', 'month']
|
||||
fields = ['employee', 'create_time_start', 'create_time_end', 'year', 'month', 'type']
|
||||
|
||||
def filter_year(self, queryset, name, value):
|
||||
return queryset.filter(create_time_date__year=value)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.db import models
|
||||
from apps.system.models import Post, User
|
||||
|
||||
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBModel
|
||||
from apps.utils.models import BaseModel, CommonAModel, CommonBModel
|
||||
|
||||
|
||||
class Employee(CommonBModel):
|
||||
|
|
|
@ -114,7 +114,7 @@ class EmployeeNotWorkRemarkSerializer(ModelSerializer):
|
|||
|
||||
|
||||
class ClockRecordListSerializer(serializers.ModelSerializer):
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
employee_ = EmployeeSimpleSerializer(source='employee', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ClockRecord
|
||||
|
|
|
@ -201,7 +201,7 @@ class HrmService:
|
|||
if id_number:
|
||||
ep = Employee.objects.filter(id_number=id_number, type="employee").first()
|
||||
# 如果是内部员工创建上班打卡记录(更新)
|
||||
if ep and ep.is_at_work is False:
|
||||
if ep and ep.is_atwork is False:
|
||||
now = timezone.now()
|
||||
cr_10 = ClockRecord.objects.filter(type=10, employee=ep, create_time__year=now.year, create_time__month=now.month, create_time__day=now.day).first()
|
||||
if cr_10:
|
||||
|
@ -217,7 +217,8 @@ class HrmService:
|
|||
cr_10.trigger = 'door'
|
||||
cr_10.detail = data['info']['extend']
|
||||
cr_10.save()
|
||||
ep.is_at_work = True
|
||||
ep.is_atwork = True
|
||||
ep.last_check_time = now
|
||||
ep.save()
|
||||
elif data['info']['extend']['enterOrExit'] == "2":
|
||||
# 如果是出门
|
||||
|
@ -225,7 +226,7 @@ class HrmService:
|
|||
if id_number:
|
||||
ep = Employee.objects.filter(id_number=id_number, type="employee").first()
|
||||
# 如果是内部员工创建下班打卡记录(更新)
|
||||
if ep and ep.is_at_work:
|
||||
if ep and ep.is_atwork:
|
||||
now = timezone.now()
|
||||
cr_20 = ClockRecord.objects.filter(type=20, employee=ep, create_time__year=now.year, create_time__month=now.month, create_time__day=now.day).first()
|
||||
if cr_20:
|
||||
|
@ -241,5 +242,6 @@ class HrmService:
|
|||
cr_20.trigger = 'door'
|
||||
cr_20.detail = data['info']['extend']
|
||||
cr_20.save()
|
||||
ep.is_at_work = False
|
||||
ep.is_atwork = False
|
||||
ep.last_check_time = now
|
||||
ep.save()
|
||||
|
|
|
@ -208,6 +208,7 @@ class ClockRecordViewSet(ListModelMixin, CustomGenericViewSet):
|
|||
permission_classes = [AllowAny]
|
||||
queryset = ClockRecord.objects.all()
|
||||
select_related_fields = ['employee']
|
||||
search_fields = ['employee__name', 'employee__number']
|
||||
serializer_class = ClockRecordListSerializer
|
||||
filterset_class = ClockRecordFilterSet
|
||||
ordering = ['-pk']
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# Generated by Django 3.2.12 on 2022-08-12 09:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('third', '0009_tlog_errors'),
|
||||
('opm', '0002_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='operation',
|
||||
name='cates',
|
||||
field=models.ManyToManyField(through='opm.Opl', to='opm.OplCate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='operation',
|
||||
name='vchannels',
|
||||
field=models.ManyToManyField(to='third.TDevice', verbose_name='监控所用摄像头'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='opl',
|
||||
name='mtask_id',
|
||||
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='视频监控任务ID'),
|
||||
),
|
||||
]
|
|
@ -1,5 +1,6 @@
|
|||
from django.db import models
|
||||
from apps.system.models import User
|
||||
from apps.third.models import TDevice
|
||||
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBDModel
|
||||
|
||||
|
||||
|
@ -56,6 +57,8 @@ class Operation(CommonBDModel):
|
|||
coordinator = models.ForeignKey('system.user', verbose_name='业务部门协调员',
|
||||
on_delete=models.CASCADE)
|
||||
state_work = models.CharField('生产状态', max_length=20, help_text='运行/停机/检修')
|
||||
cates = models.ManyToManyField(OplCate, through='opm.opl')
|
||||
vchannels = models.ManyToManyField(TDevice, verbose_name='监控所用摄像头')
|
||||
|
||||
|
||||
class Opl(CommonBDModel):
|
||||
|
@ -114,6 +117,7 @@ class Opl(CommonBDModel):
|
|||
ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单',
|
||||
on_delete=models.CASCADE,
|
||||
null=True, blank=True)
|
||||
mtask_id = models.CharField('视频监控任务ID', max_length=200, null=True, blank=True)
|
||||
|
||||
|
||||
class OplWorker(BaseModel):
|
||||
|
|
|
@ -60,6 +60,7 @@ class OperationDetailSerializer(CustomModelSerializer):
|
|||
dept_bus_ = DeptSimpleSerializer(source='dept_bus', read_only=True)
|
||||
coordinator_ = UserSimpleSerializer(source='coordinator', read_only=True)
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
cates_ = OplCateSimpleSerializer(source='cates', read_only=True, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Operation
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
from apps.ecm.tasks import opl_task
|
||||
from apps.opm.models import Operation, Opl, OplWorker
|
||||
from apps.third.models import TDevice
|
||||
from apps.wf.models import Ticket, Transition
|
||||
|
||||
|
||||
|
@ -53,13 +55,35 @@ def bind_opl(ticket: Ticket, transition: Transition, new_ticket_data: dict):
|
|||
|
||||
|
||||
def opl_audit_end(ticket: Ticket):
|
||||
# 任务执行1
|
||||
opl = Opl.objects.get(ticket=ticket)
|
||||
|
||||
op = opl.operation
|
||||
if op.state == Operation.OP_AUDIT:
|
||||
op.state = Operation.OP_WORK
|
||||
op.state = Operation.OP_WAIT
|
||||
op.save()
|
||||
|
||||
# 授予相关工作人员区域进入权限
|
||||
# worker_ep_ids = list(OplWorker.objects.filter(opl=opl).values_list('worker__id', flat=True))
|
||||
# 发送通知
|
||||
|
||||
|
||||
def opl_start(ticket: Ticket):
|
||||
# 任务执行2 开始许可证作业
|
||||
opl = Opl.objects.get(ticket=ticket)
|
||||
|
||||
op = opl.operation
|
||||
if op.state == Operation.OP_WAIT:
|
||||
op.state = Operation.OP_WORK
|
||||
op.save()
|
||||
|
||||
# 给摄像头加载循环拍照算法
|
||||
# 找到作业点的摄像头, 如果指定摄像头就用指定的摄像头
|
||||
if op.vchannels:
|
||||
vc_codes = list(op.vchannels.all().values_list('code', flat=True))
|
||||
else:
|
||||
vc_codes = list(TDevice.objects.filter(type=TDevice.DEVICE_VCHANNEL, area=op.area).values_list('code', flat=True))
|
||||
opl_id = opl.id
|
||||
task = opl_task.delay(vc_codes, opl_id)
|
||||
opl.mtask_id = task.task_id
|
||||
opl.save()
|
||||
|
|
|
@ -4,16 +4,25 @@ from apps.opm.models import Operation, Opl
|
|||
from apps.utils.tasks import CustomTask
|
||||
from celery import shared_task
|
||||
|
||||
from apps.wf.models import State, Ticket
|
||||
from apps.wf.models import Ticket
|
||||
|
||||
|
||||
@shared_task(base=CustomTask)
|
||||
def opl_end(ticket_id):
|
||||
"""
|
||||
作业关闭时执行
|
||||
作业许可证关闭时执行
|
||||
"""
|
||||
ticket = Ticket.objects.get(id=ticket_id)
|
||||
operation = ticket.opl.operation
|
||||
opl = ticket.opl
|
||||
if opl.mtask_id:
|
||||
from celery.app.control import Control
|
||||
from server.celery import app
|
||||
celery_control = Control(app=app)
|
||||
# 关闭作业视频监控任务
|
||||
celery_control.revoke(opl.mtask_id, terminate=True)
|
||||
opl.mtask_id = None
|
||||
opl.save()
|
||||
operation = opl.operation
|
||||
opls = Opl.objects.filter(operation=operation)
|
||||
opls.filter(ticket=None).delete() # 删除无用许可证
|
||||
states = opls.values_list('ticket__state__type', flat=True)
|
||||
|
@ -24,19 +33,19 @@ def opl_end(ticket_id):
|
|||
operation.save()
|
||||
|
||||
|
||||
@shared_task(base=CustomTask)
|
||||
def opl_audit_start(ticket_id):
|
||||
operation = Opl.objects.get(ticket__id=ticket_id).operation
|
||||
if operation.state == Operation.OP_CREATE:
|
||||
operation.state = Operation.OP_AUDIT
|
||||
operation.save()
|
||||
# @shared_task(base=CustomTask)
|
||||
# def opl_audit_start(ticket_id):
|
||||
# operation = Opl.objects.get(ticket__id=ticket_id).operation
|
||||
# if operation.state == Operation.OP_CREATE:
|
||||
# operation.state = Operation.OP_AUDIT
|
||||
# operation.save()
|
||||
|
||||
|
||||
@shared_task(base=CustomTask)
|
||||
def opl_audit_end(ticket_id):
|
||||
opl = Opl.objects.get(ticket__id=ticket_id)
|
||||
operation = opl.operation
|
||||
if operation.state == Operation.OP_AUDIT:
|
||||
operation.state = Operation.OP_WORK
|
||||
operation.save()
|
||||
# @shared_task(base=CustomTask)
|
||||
# def opl_audit_end(ticket_id):
|
||||
# opl = Opl.objects.get(ticket__id=ticket_id)
|
||||
# operation = opl.operation
|
||||
# if operation.state == Operation.OP_AUDIT:
|
||||
# operation.state = Operation.OP_WORK
|
||||
# operation.save()
|
||||
# 授予区域或围栏权限
|
||||
|
|
|
@ -31,6 +31,7 @@ class OperationViewSet(CustomModelViewSet):
|
|||
serializer_class = OperationDetailSerializer
|
||||
retrieve_serializer_class = OperationDetailSerializer
|
||||
select_related_fields = ['area', 'dept_bus', 'dept_ter', 'coordinator']
|
||||
prefetch_related_fields = ['cates']
|
||||
filterset_fields = ['state', 'opl_operation__cate', 'area', 'create_by']
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
|
|
|
@ -10,7 +10,7 @@ from rest_framework.exceptions import APIException, ParseError
|
|||
from apps.third.errors import DH_REQUEST_ERROR
|
||||
from apps.third.models import Tlog
|
||||
from apps.utils.my_rsa import encrypt_data
|
||||
from apps.utils.tools import print_roundtrip
|
||||
from apps.utils.tools import convert_to_base64, print_roundtrip
|
||||
from django.utils.timezone import now
|
||||
from apps.third.tapis import dhapis
|
||||
|
||||
|
@ -135,13 +135,17 @@ class DhClient:
|
|||
返回完整访问地址
|
||||
"""
|
||||
json_data = {
|
||||
"deviceCode": "1000038",
|
||||
"operation": "generalJsonTransport",
|
||||
"params": "{\"method\":\"dev.snap\",\"id\":123,\"params\":{\"DevID\":\"1000038\",\"DevChannel\":0,\"PicNum\":1,\"SnapType\":1,\"CmdSrc\":0}}",
|
||||
"deviceCode": "1000093",
|
||||
"operation": "generalJsonTransport"
|
||||
}
|
||||
if '$' in code:
|
||||
d_code = code.split('$')[0]
|
||||
json_data['deviceCode'] = d_code
|
||||
json_data['params'] = '{\"method\":\"dev.snap\",\"id\":123,\"params\":{\"DevID\":\"' + \
|
||||
str(d_code) + '\",\"DevChannel\":0,\"PicNum\":1,\"SnapType\":1,\"CmdSrc\":0}}'
|
||||
_, res = self.request(**dhapis['dev_snap'], json=json_data)
|
||||
res = json.loads(res)
|
||||
return self.get_full_pic(res['params']['PicInfo'])
|
||||
|
||||
def get_password_token(self):
|
||||
_, res = self.request(**dhapis['oauth_key'])
|
||||
|
@ -156,3 +160,104 @@ class DhClient:
|
|||
})
|
||||
_, res2 = self.request(**dhapis['oauth_token'], json=res)
|
||||
return res2
|
||||
|
||||
def face_search(self, path: str):
|
||||
"""人像库检索
|
||||
|
||||
Args:
|
||||
path (str): 图片地址
|
||||
|
||||
返回第一个识别结果
|
||||
"""
|
||||
base64img = convert_to_base64(path)
|
||||
json_data = {
|
||||
"base64Img": base64img,
|
||||
"devType": 1,
|
||||
"deviceCodes": ["1000038"],
|
||||
"groupIds": ["100001"],
|
||||
"searchGroupType": 2,
|
||||
"threshold": "80"
|
||||
}
|
||||
_, res = self.request(**dhapis['face_search'], json=json_data)
|
||||
return res['pageData']
|
||||
# 返回的识别结果是从右往左
|
||||
"""
|
||||
"pageData": [
|
||||
{
|
||||
"id": null,
|
||||
"devId": "1000038",
|
||||
"channelId": null,
|
||||
"channelSeq": null,
|
||||
"channelName": null,
|
||||
"faceLibId": "1",
|
||||
"libImgUrl": "6ad010cf-ce45-11ec-9715-e4246c7d1635/20220805/63/dsf_8c2487c1-14a1-11ed-880a-e4246c7d1635_2551349_2624751.jpg",
|
||||
"faceImgUrl": null,
|
||||
"hitImgUrl": null,
|
||||
"identity": "342422199004040175",
|
||||
"name": "曹前明",
|
||||
"sex": "男",
|
||||
"nation": null,
|
||||
"bornYear": null,
|
||||
"age": null,
|
||||
"glasses": null,
|
||||
"fringe": null,
|
||||
"similarity": 99,
|
||||
"recTime": null,
|
||||
"mask": null,
|
||||
"beard": null,
|
||||
"glass": null,
|
||||
"maskStr": null,
|
||||
"beardStr": null,
|
||||
"glassStr": null,
|
||||
"featureStr": "其他 ",
|
||||
"groupName": "内部库1",
|
||||
"groupType": 3,
|
||||
"groupTypeStr": "内部库",
|
||||
"identityType": 1,
|
||||
"identityTypeStr": "身份证",
|
||||
"birthday": null,
|
||||
"searchGroupType": 2,
|
||||
"birthdayStr": "2022-07-14",
|
||||
"deviceName": "ivs服务器",
|
||||
"personCode": "123"
|
||||
},
|
||||
{
|
||||
"id": null,
|
||||
"devId": "1000038",
|
||||
"channelId": null,
|
||||
"channelSeq": null,
|
||||
"channelName": null,
|
||||
"faceLibId": "1",
|
||||
"libImgUrl": "6ad010cf-ce45-11ec-9715-e4246c7d1635/20220805/63/dsf_8c2487c1-14a1-11ed-880a-e4246c7d1635_2624751_2701750.jpg",
|
||||
"faceImgUrl": null,
|
||||
"hitImgUrl": null,
|
||||
"identity": "371324199502156548",
|
||||
"name": "石静",
|
||||
"sex": "女",
|
||||
"nation": null,
|
||||
"bornYear": null,
|
||||
"age": null,
|
||||
"glasses": null,
|
||||
"fringe": null,
|
||||
"similarity": 96,
|
||||
"recTime": null,
|
||||
"mask": null,
|
||||
"beard": null,
|
||||
"glass": null,
|
||||
"maskStr": null,
|
||||
"beardStr": null,
|
||||
"glassStr": null,
|
||||
"featureStr": "其他 ",
|
||||
"groupName": "内部库1",
|
||||
"groupType": 3,
|
||||
"groupTypeStr": "内部库",
|
||||
"identityType": 1,
|
||||
"identityTypeStr": "身份证",
|
||||
"birthday": null,
|
||||
"searchGroupType": 2,
|
||||
"birthdayStr": "2022-06-24",
|
||||
"deviceName": "ivs服务器",
|
||||
"personCode": "shijing"
|
||||
}
|
||||
]
|
||||
"""
|
||||
|
|
|
@ -115,6 +115,10 @@ dhapis = {
|
|||
"oauth_token": {
|
||||
"url": "/evo-apigw/evo-oauth/1.0.0/oauth/extend/token",
|
||||
"method": "post"
|
||||
},
|
||||
"face_search": {
|
||||
"url": "/evo-apigw/evo-face/faceSearch/third/faceSearchSync",
|
||||
"method": "post"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,13 +21,15 @@ from django.conf import settings
|
|||
|
||||
|
||||
class DahuaTestView(MyLoggingMixin, APIView):
|
||||
"""
|
||||
"""大华测试接口
|
||||
|
||||
大华测试接口
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
res = dhClient.get_password_token()
|
||||
res = dhClient.face_search(path='/media/2022/07/13/three.jpg')
|
||||
|
||||
return Response(res)
|
||||
|
||||
|
||||
|
|
|
@ -204,7 +204,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
|
|||
json = {
|
||||
"pageNum": 1,
|
||||
"pageSize": 1000,
|
||||
'channelTypeList': ["1"]
|
||||
'channelTypeList': ["1"],
|
||||
'includeSubOwnerCodeFlag': True
|
||||
}
|
||||
_, res = dhClient.request(**dhapis['channel_list'], json=json)
|
||||
if res.get('pageData', None):
|
||||
|
@ -229,7 +230,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
|
|||
json = {
|
||||
"pageNum": 1,
|
||||
"pageSize": 1000,
|
||||
'channelTypeList': ["7"]
|
||||
'channelTypeList': ["7"],
|
||||
'includeSubOwnerCodeFlag': True
|
||||
}
|
||||
_, res = dhClient.request(**dhapis['channel_list'], json=json)
|
||||
if res.get('pageData', None):
|
||||
|
@ -302,7 +304,10 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
|
|||
|
||||
视频通道列表
|
||||
"""
|
||||
request.data.update({'channelTypeList': ["1"]})
|
||||
request.data.update({
|
||||
'channelTypeList': ["1"],
|
||||
'includeSubOwnerCodeFlag': True
|
||||
})
|
||||
_, res = dhClient.request(**dhapis['channel_list'], json=request.data)
|
||||
codes = []
|
||||
if res.get('pageData', None):
|
||||
|
@ -349,7 +354,10 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
|
|||
|
||||
闸机通道列表
|
||||
"""
|
||||
request.data.update({'channelTypeList': ["7"]})
|
||||
request.data.update({
|
||||
'channelTypeList': ["7"],
|
||||
'includeSubOwnerCodeFlag': True
|
||||
})
|
||||
_, res = dhClient.request(**dhapis['channel_list'], json=request.data)
|
||||
codes = []
|
||||
if res.get('pageData', None):
|
||||
|
|
|
@ -2,6 +2,10 @@ import textwrap
|
|||
import random
|
||||
import string
|
||||
from datetime import datetime
|
||||
from django.conf import settings
|
||||
import base64
|
||||
import requests
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
def print_roundtrip(response, *args, **kwargs):
|
||||
|
@ -40,6 +44,19 @@ def timestamp_to_time(millis):
|
|||
return datetime.fromtimestamp(millis)
|
||||
|
||||
|
||||
def convert_to_base64(path: str):
|
||||
"""给定图片转base64
|
||||
|
||||
Args:
|
||||
path (str): 图片地址
|
||||
"""
|
||||
if path.startswith('http'): # 如果是网络图片
|
||||
return str(base64.b64encode(BytesIO(requests.get(url=path).content).read()), 'utf-8')
|
||||
else:
|
||||
with open(settings.BASE_DIR + path, 'rb') as f:
|
||||
return str(base64.b64encode(f.read()), 'utf-8')
|
||||
|
||||
|
||||
def p_in_poly(p, poly):
|
||||
px = p['x']
|
||||
py = p['y']
|
||||
|
|
|
@ -56,19 +56,23 @@ class VpeopleCreateSerializer(CustomModelSerializer):
|
|||
fields = ['visit', 'visitor', 'is_main']
|
||||
|
||||
def create(self, validated_data):
|
||||
if validated_data['visit'].state != Visit.V_CREATE:
|
||||
visit = validated_data['visit']
|
||||
visitor = validated_data['visitor']
|
||||
if visit.state != Visit.V_CREATE:
|
||||
raise ParseError('项目非创建状态不可新增成员')
|
||||
if validated_data['visit'].level == 10:
|
||||
visitor = validated_data['visitor']
|
||||
if visit.level == 10:
|
||||
if visitor.id_number and visitor.photo:
|
||||
pass
|
||||
else:
|
||||
raise ParseError('访客信息不全,请完善后再试')
|
||||
if Vpeople.objects.filter(visit=validated_data['visit'], visitor=validated_data['visitor']).exists():
|
||||
if Vpeople.objects.filter(visit=visit, visitor=visitor).exists():
|
||||
raise ParseError('该访客已选中')
|
||||
ins = super().create(validated_data)
|
||||
if ins.is_main:
|
||||
Vpeople.objects.filter(visit=validated_data['visit']).exclude(id=ins.id).update(is_main=False)
|
||||
Vpeople.objects.filter(visit=visit).exclude(id=ins.id).update(is_main=False)
|
||||
if visit.level == 10:
|
||||
visit.count_people = Vpeople.objects.filter(visit=visit).count()
|
||||
visit.save()
|
||||
return ins
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue