feat: 查看门禁权限并支持删除

This commit is contained in:
caoqianming 2023-10-09 11:09:31 +08:00
parent b4cc887f79
commit b479db9f89
8 changed files with 247 additions and 98 deletions

View File

@ -17,14 +17,25 @@ from rest_framework.exceptions import ParseError
from django.conf import settings
class EmployeeShortSerializer(CustomModelSerializer):
belong_dept_name = serializers.CharField(
source='belong_dept.name', read_only=True)
class Meta:
model = Employee
fields = ['id', 'name', 'belong_dept_name', 'user', 'third_info']
class EmployeeSimpleSerializer(CustomModelSerializer):
belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True)
belong_dept_name = serializers.CharField(
source='belong_dept.name', read_only=True)
post_name = serializers.CharField(source='post.name', read_only=True)
location = serializers.SerializerMethodField()
class Meta:
model = Employee
fields = ['id', 'type', 'name', 'belong_dept', 'belong_dept_name', 'post', 'post_name', 'photo', 'third_info', 'number', 'id_number', 'location']
fields = ['id', 'type', 'name', 'belong_dept', 'belong_dept_name', 'post',
'post_name', 'photo', 'third_info', 'number', 'id_number', 'location']
def get_location(self, obj):
key_str = 'ep_{}'.format(obj.id)
@ -40,7 +51,8 @@ class EmployeeSimpleSerializer(CustomModelSerializer):
class EmployeeCreateUpdateSerializer(CustomModelSerializer):
id_number = serializers.CharField(label="身份证号", validators=[check_id_number_e])
id_number = serializers.CharField(
label="身份证号", validators=[check_id_number_e])
class Meta:
model = Employee
@ -72,7 +84,8 @@ class EmployeeCreateUpdateSerializer(CustomModelSerializer):
instance = super().update(instance, validated_data)
if old_photo != instance.photo: # 如果照片有变动,需要更新人脸库
# 使用的是face_recongition
face_data, msg = HrmService.get_facedata_from_img_x(settings.BASE_DIR + instance.photo)
face_data, msg = HrmService.get_facedata_from_img_x(
settings.BASE_DIR + instance.photo)
in_face_data = instance.face_data
if face_data:
if isinstance(in_face_data, dict):
@ -104,17 +117,19 @@ class EmployeeCreateUpdateSerializer(CustomModelSerializer):
if instance.type in ['employee', 'remployee']:
start_time = None
end_time = None
if instance.third_info.get('dh_face_card', None) is None and instance.type == 'employee': # 如果是正式员工,给长时间期限
# 如果是正式员工,给长时间期限
if instance.third_info.get('dh_face_card', None) is None and instance.type == 'employee':
start_time = now
end_time = now + timedelta(days=7300)
if instance.job_state in [20, 30] and old_job_state == 10: # 离职或退休
start_time = now
end_time = now + timedelta(hours=8)
elif instance.job_state == 10 and old_job_state in [20, 30] and instance.type == 'employee': # 正式员工重新在职
# 正式员工重新在职
elif instance.job_state == 10 and old_job_state in [20, 30] and instance.type == 'employee':
start_time = now
end_time = now + timedelta(days=7300)
HrmService.sync_dahua_employee(ep=instance, old_photo=old_photo,
start_time=start_time, end_time=end_time)
start_time=start_time, end_time=end_time)
return instance
@ -124,7 +139,8 @@ class EmployeeImproveSerializer(CustomModelSerializer):
class Meta:
model = Employee
fields = ['photo', 'id_number', 'email', 'gender', 'signature', 'photo_f', 'signature_f', 'phone']
fields = ['photo', 'id_number', 'email', 'gender',
'signature', 'photo_f', 'signature_f', 'phone']
extra_kwargs = {
'number': {'required': True},
'photo': {'required': True},
@ -147,7 +163,8 @@ class ChannelAuthoritySerializer(serializers.Serializer):
class EmployeeSerializer(CustomModelSerializer):
belong_dept_ = DeptSimpleSerializer(source='belong_dept', read_only=True)
user_ = UserSimpleSerializer(source='user', read_only=True)
belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True)
belong_dept_name = serializers.CharField(
source='belong_dept.name', read_only=True)
post_name = serializers.CharField(source='post.name', read_only=True)
blt_ = serializers.SerializerMethodField()
photo_f = MyFilePathField(source='photo', read_only=True)
@ -161,7 +178,7 @@ class EmployeeSerializer(CustomModelSerializer):
def get_blt_(self, obj):
if hasattr(obj, 'blt'):
from apps.third.serializers import TDeviceSimpleSerializer
return TDeviceSimpleSerializer(instance=obj.blt).data
return TDeviceSimpleSerializer(instance=obj.blt).data
# if hasattr(obj, 'tdevice'):
# from apps.third.serializers import TDeviceSimpleSerializer
# return TDeviceSimpleSerializer(instance=obj.tdevice).data
@ -197,6 +214,7 @@ class ClockRecordListSerializer(serializers.ModelSerializer):
model = ClockRecord
fields = '__all__'
class ClockRecordSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = ClockRecord
@ -218,7 +236,8 @@ class CertificateCreateUpdateSerializer(CustomModelSerializer):
class CertificateSerializer(CustomModelSerializer):
employee_name = serializers.CharField(source='employee.name', read_only=True)
employee_name = serializers.CharField(
source='employee.name', read_only=True)
file_f = MyFilePathField(source='file', read_only=True)
class Meta:
@ -228,4 +247,4 @@ class CertificateSerializer(CustomModelSerializer):
class CorrectSerializer(serializers.Serializer):
start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()
end_time = serializers.DateTimeField()

View File

@ -34,7 +34,7 @@ class HrmService:
Returns:
_type_: _description_
"""
if not settings.DAHUA_ENABLED: # 如果大华没启用, 直接返回
if not settings.DAHUA_ENABLED: # 如果大华没启用, 直接返回
return
dh_id = ep.third_info.get('dh_id', None)
dh_photo = ep.third_info.get('dh_photo', None)
@ -68,7 +68,8 @@ class HrmService:
}]
}
if ep.photo != old_photo and ep.photo:
_, res = dhClient.request(**dhapis['person_img_upload'], file_path_rela=ep.photo)
_, res = dhClient.request(
**dhapis['person_img_upload'], file_path_rela=ep.photo)
dh_photo = res["fileUrl"]
json_data.update(
{
@ -98,7 +99,8 @@ class HrmService:
"email": ep.email,
"sex": 1 if ep.gender == '' else 2
}
_, res = dhClient.request(**dhapis['person_img_upload'], file_path_rela=ep.photo)
_, res = dhClient.request(
**dhapis['person_img_upload'], file_path_rela=ep.photo)
dh_photo = res["fileUrl"]
json_data.update(
{
@ -129,16 +131,20 @@ class HrmService:
if start_time is None: # 如果时间段未提供,跳过更新操作
pass
else:
startDate = timezone.localtime(start_time).strftime("%Y-%m-%d %H:%M:%S")
endDate = timezone.localtime(end_time).strftime("%Y-%m-%d %H:%M:%S")
startDate = timezone.localtime(
start_time).strftime("%Y-%m-%d %H:%M:%S")
endDate = timezone.localtime(
end_time).strftime("%Y-%m-%d %H:%M:%S")
json_data = {
"cardNumber": cardNumber,
"startDate": startDate,
"endDate": endDate,
"departmentId": departmentId,
}
_, res = dhClient.request(**dhapis['card_update'], json=json_data)
cls.save(ep, data={'dh_face_card_start': startDate, 'dh_face_card_end': endDate})
_, res = dhClient.request(
**dhapis['card_update'], json=json_data)
cls.save(
ep, data={'dh_face_card_start': startDate, 'dh_face_card_end': endDate})
return cardNumber
else:
_, res = dhClient.request(**dhapis['card_gen_id'])
@ -147,10 +153,13 @@ class HrmService:
if start_time is None: # 如果未规定时间范围, 默认1小时
now = datetime.now()
startDate = now.strftime("%Y-%m-%d %H:%M:%S")
endDate = (now+timedelta(minutes=60)).strftime("%Y-%m-%d %H:%M:%S")
endDate = (now+timedelta(minutes=60)
).strftime("%Y-%m-%d %H:%M:%S")
else:
startDate = timezone.localtime(start_time).strftime("%Y-%m-%d %H:%M:%S")
endDate = timezone.localtime(end_time).strftime("%Y-%m-%d %H:%M:%S")
startDate = timezone.localtime(
start_time).strftime("%Y-%m-%d %H:%M:%S")
endDate = timezone.localtime(
end_time).strftime("%Y-%m-%d %H:%M:%S")
json_data = {
"id": cardId,
"cardNumber": cardNumber,
@ -180,7 +189,9 @@ class HrmService:
from apps.third.models import TDevice
dh_face_card = ep.third_info.get('dh_face_card', None)
if dh_dchannels:
pass
# 只分配系统里有的
dh_dchannels = list(TDevice.objects.filter(
code__in=dh_dchannels).values_list('code', flat=True))
else:
# 查找可授予的门禁通道号
dh_dchannels = list(TDevice.objects.filter(type=TDevice.DEVICE_DCHANNEL,
@ -201,7 +212,8 @@ class HrmService:
while ind < 8:
time.sleep(6)
try:
dhClient.request(**dhapis['card_door_authority'], json=json_data)
dhClient.request(
**dhapis['card_door_authority'], json=json_data)
break
except Exception as e:
ind = ind + 1
@ -220,6 +232,13 @@ class HrmService:
# elif is_ok == 'error':
# raise APIException(**DH_REQUEST_ERROR)
cls.save(ep, data={'dh_dchannels': dh_dchannels})
from apps.third.models import DoorAuth
DoorAuth.objects.filter(employee=ep).delete()
drs = []
for i in dh_dchannels:
drs.append(
DoorAuth(employee=ep, dchannel=TDevice.objects.get(code=i)))
DoorAuth.objects.bulk_create(drs)
return dh_dchannels
@classmethod
@ -243,10 +262,11 @@ class HrmService:
nodeCode = data['info']['extend']['acsChannelCode']
swip_time = data['info']['extend']['swingTime']
e_type = data['info']['extend']['enterOrExit']
cls.swipe_next(nodeCode, id_number, swip_time, e_type, data['info']['extend'])
cls.swipe_next(nodeCode, id_number, swip_time,
e_type, data['info']['extend'])
@classmethod
def swipe_offline(cls, data:dict):
def swipe_offline(cls, data: dict):
"""离线刷卡推送记录处理
"""
for i in data['infoArray']:
@ -256,9 +276,9 @@ class HrmService:
swip_time = i['swingTime']
e_type = i['enterOrExit']
cls.swipe_next(nodeCode, id_number, swip_time, e_type, i)
@classmethod
def swipe_next(cls, nodeCode: str, id_number: str, swip_time: str, e_type:int, detail:dict):
def swipe_next(cls, nodeCode: str, id_number: str, swip_time: str, e_type: int, detail: dict):
from apps.rpm.models import Rpj
from apps.vm.models import Visit
@ -267,15 +287,17 @@ class HrmService:
state=Visit.V_WORKING)
Rpj.objects.filter(state=Rpj.RPJ_ENTER, remployees__employee__id_number=id_number).update(
state=Rpj.RPJ_WORKING)
# 打卡处理
device = TDevice.objects.filter(code=nodeCode).first()
ep = Employee.objects.filter(id_number=id_number, type__in=["employee", "remployee"]).first()
ep = Employee.objects.filter(id_number=id_number, type__in=[
"employee", "remployee"]).first()
if device and device.is_clock and ep:
tzinfo = tz.gettz('Asia/Shanghai')
s_time_f = datetime.strptime(swip_time, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo)
s_time_f = datetime.strptime(
swip_time, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo)
first_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day,
hour=0, minute=0, second=0, tzinfo=tzinfo)
hour=0, minute=0, second=0, tzinfo=tzinfo)
end_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day,
hour=23, minute=59, second=59, tzinfo=tzinfo)
@ -288,13 +310,13 @@ class HrmService:
card_type = 20
elif e_type == 3:
time_10_x = datetime(year=s_time_f.year, month=s_time_f.month,
day=s_time_f.day, hour=7, minute=20, second=0, tzinfo=tzinfo)
day=s_time_f.day, hour=7, minute=20, second=0, tzinfo=tzinfo)
time_10_y = datetime(year=s_time_f.year, month=s_time_f.month,
day=s_time_f.day, hour=11, minute=0, second=0, tzinfo=tzinfo)
day=s_time_f.day, hour=11, minute=0, second=0, tzinfo=tzinfo)
time_20_x = datetime(year=s_time_f.year, month=s_time_f.month,
day=s_time_f.day, hour=16, minute=0, second=0, tzinfo=tzinfo)
day=s_time_f.day, hour=16, minute=0, second=0, tzinfo=tzinfo)
time_20_y = datetime(year=s_time_f.year, month=s_time_f.month,
day=s_time_f.day, hour=18, minute=10, second=0, tzinfo=tzinfo)
day=s_time_f.day, hour=18, minute=10, second=0, tzinfo=tzinfo)
if time_10_x < s_time_f < time_10_y:
card_type = 10
elif time_20_x < s_time_f < time_20_y:
@ -302,9 +324,10 @@ class HrmService:
if card_type == 30:
note = '非打卡时间范围'
trigger = 'panel'
# 先直接创建记录
cr = ClockRecord.objects.filter(employee=ep, create_time=s_time_f).first()
cr = ClockRecord.objects.filter(
employee=ep, create_time=s_time_f).first()
if cr:
pass
else:
@ -312,7 +335,7 @@ class HrmService:
cr.employee = ep
cr.create_time = s_time_f
cr.type = card_type
cr.exception_type = None
cr.exception_type = None
cr.trigger = trigger
cr.detail = detail
cr.note = note
@ -323,34 +346,38 @@ class HrmService:
cr_10_q = ClockRecord.objects.filter(
type=10, employee=ep, create_time__gte=first_time, create_time__lte=end_time)
first_obj = cr_10_q.order_by('create_time').first()
cr_10_q.exclude(id=first_obj.id).update(type=30, exception_type=None)
cr_10_q.exclude(id=first_obj.id).update(
type=30, exception_type=None)
elif card_type == 20:
# 查找当天的出门记录
cr_20_q = ClockRecord.objects.filter(
type=20, employee=ep, create_time__gte=first_time, create_time__lte=end_time)
last_obj = cr_20_q.order_by('-create_time').first()
cr_20_q.exclude(id=last_obj.id).update(type=30, exception_type=None)
cr_20_q.exclude(id=last_obj.id).update(
type=30, exception_type=None)
# 判断是否有异常
# 找到最近的上下打卡时间不一定是当天的
cr_e = ClockRecord.objects.filter(create_time__lt=last_obj.create_time, employee=ep, type__in=[10, 20]).order_by('-create_time').first()
cr_e = ClockRecord.objects.filter(create_time__lt=last_obj.create_time, employee=ep, type__in=[
10, 20]).order_by('-create_time').first()
if cr_e and last_obj:
time_d = last_obj.create_time - cr_e.create_time
if cr_e.type == 10:
if time_d < timedelta(hours=7):
if time_d < timedelta(hours=7):
last_obj.exception_type = ClockRecord.E_TYPE_LESS
last_obj.save()
elif time_d > timedelta(hours=14):
elif time_d > timedelta(hours=14):
last_obj.exception_type = ClockRecord.E_TYPE_MORE
last_obj.save()
elif time_d > timedelta(hours=10):
elif time_d > timedelta(hours=10):
last_obj.exception_type = ClockRecord.E_TYPE_ADD
last_obj.save()
elif cr_e.type == 20:
last_obj.exception_type = ClockRecord.E_TYPE_MISS
last_obj.save()
last_obj.exception_type = ClockRecord.E_TYPE_MISS
last_obj.save()
# 记录在岗情况
last_obj_t = ClockRecord.objects.filter(employee=ep, type__in=[10,20]).order_by('-create_time').first()
last_obj_t = ClockRecord.objects.filter(
employee=ep, type__in=[10, 20]).order_by('-create_time').first()
if last_obj_t:
update_fields = {'last_check_time': last_obj_t.create_time}
if last_obj_t.type == 10:
@ -358,48 +385,48 @@ class HrmService:
else:
update_fields['is_atwork'] = False
Employee.objects.filter(id=ep.id).update(**update_fields)
# 此处可触发安全帽事件逻辑
@classmethod
def get_facedata_from_img_x(cls, img_path):
import face_recognition
try:
picture_of_me = face_recognition.load_image_file(img_path)
my_face_encoding = face_recognition.face_encodings(picture_of_me, num_jitters=2)[0]
my_face_encoding = face_recognition.face_encodings(
picture_of_me, num_jitters=2)[0]
face_data_list = my_face_encoding.tolist()
return face_data_list, ''
except:
return None, '人脸数据获取失败请重新上传图片'
@classmethod
def face_compare_from_base64(cls, base64_data):
import face_recognition
filename = str(uuid.uuid4())
filepath = settings.BASE_DIR +'/temp/face_' + filename +'.png'
filepath = settings.BASE_DIR + '/temp/face_' + filename + '.png'
with open(filepath, 'wb') as f:
f.write(base64_data)
try:
unknown_picture = face_recognition.load_image_file(filepath)
unknown_face_encoding = face_recognition.face_encodings(unknown_picture, num_jitters=2)[0]
unknown_face_encoding = face_recognition.face_encodings(
unknown_picture, num_jitters=2)[0]
os.remove(filepath)
except:
os.remove(filepath)
return None, '识别失败,请调整位置'
# 匹配人脸库
face_datas = cache.get('face_datas_dlib', None) # 使用的是face_datas_dlib作为key的
# 使用的是face_datas_dlib作为key的
face_datas = cache.get('face_datas_dlib', None)
if face_datas is None:
from apps.hrm.tasks import update_all_facedata_cache
update_all_facedata_cache()
face_datas = cache.get('face_datas_dlib')
results = face_recognition.compare_faces(face_datas['datas'],
unknown_face_encoding, tolerance=0.45)
face_distances = face_recognition.face_distance(face_datas['datas'], unknown_face_encoding)
results = face_recognition.compare_faces(face_datas['datas'],
unknown_face_encoding, tolerance=0.45)
face_distances = face_recognition.face_distance(
face_datas['datas'], unknown_face_encoding)
best_match_index = np.argmin(face_distances)
if results[best_match_index]:
epId = face_datas['eps'][best_match_index]
@ -408,7 +435,7 @@ class HrmService:
# first_match_index = results.index(True)
# # 识别成功
# ep = Employee.objects.get(id=face_datas['eps'][first_match_index])
# return ep, ''
# return ep, ''
return None, '人脸未匹配,请调整位置'
@classmethod
@ -416,7 +443,7 @@ class HrmService:
from apps.utils.face import face_find
# from deepface import DeepFace
img_name = str(uuid.uuid4())
img_path = settings.BASE_DIR +'/temp/face_' + img_name +'.jpg'
img_path = settings.BASE_DIR + '/temp/face_' + img_name + '.jpg'
with open(img_path, 'wb') as f:
f.write(base64_data)
# db_path = os.path.join(settings.BASE_DIR, 'media/face')
@ -443,7 +470,8 @@ class HrmService:
def get_facedata_from_img(cls, img_path):
try:
from deepface import DeepFace
embedding_objs = DeepFace.represent(img_path=img_path, model_name='Facenet')
embedding_objs = DeepFace.represent(
img_path=img_path, model_name='Facenet')
return embedding_objs[0]["embedding"], ''
except Exception as e:
return None, '人脸数据获取失败请重新上传图片'
return None, '人脸数据获取失败请重新上传图片'

View File

@ -0,0 +1,30 @@
# Generated by Django 3.2.12 on 2023-10-09 02:54
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('hrm', '0015_clockrecord_note'),
('third', '0008_alter_tdevice_employee'),
]
operations = [
migrations.CreateModel(
name='DoorAuth',
fields=[
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('dchannel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='third.tdevice', verbose_name='关联门通道')),
('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrm.employee', verbose_name='关联用户')),
],
options={
'abstract': False,
},
),
]

View File

@ -31,7 +31,8 @@ class TDevice(BaseModel):
(DEVICE_PANEL, '面板机')
)
type = models.PositiveSmallIntegerField('设备类型', choices=DEVICE_CHOICE)
code = models.CharField('设备唯一标识', max_length=50, db_index=True, unique=True)
code = models.CharField('设备唯一标识', max_length=50,
db_index=True, unique=True)
name = models.CharField('名称', max_length=50, null=True, blank=True)
location = models.JSONField('位置信息', default=dict,
null=False, blank=True)
@ -39,13 +40,15 @@ class TDevice(BaseModel):
verbose_name='所在区', null=True, blank=True)
areas = models.ManyToManyField(Area, verbose_name='覆盖区',
related_name='tareas', blank=True)
obj_cate = models.CharField('绑定对象', max_length=20, help_text='people/...', null=True, blank=True)
obj_cate = models.CharField(
'绑定对象', max_length=20, help_text='people/...', null=True, blank=True)
employee = models.OneToOneField(Employee, verbose_name='当前绑定人员', on_delete=models.SET_NULL,
null=True, blank=True, related_name='blt')
is_clock = models.BooleanField('是否打卡设备', default=False)
access_list = models.JSONField('自动下发人员类型', default=list,
null=False, blank=True, help_text='employee/remployee/visitor/driver')
mtask_uid = models.CharField('监控任务ID', max_length=100, null=True, blank=True) # 废弃字段
mtask_uid = models.CharField(
'监控任务ID', max_length=100, null=True, blank=True) # 废弃字段
# algos = models.ManyToManyField('ecm.eventcate', through='ecm.algochannel', blank=True)
third_info = models.JSONField('三方信息', default=dict,
null=False, blank=True)
@ -62,9 +65,12 @@ class BltBind(BaseModel):
)
type = models.PositiveSmallIntegerField('绑定类型', default=10, help_text='10(绑定)/20(解绑)',
choices=BIND_TYPE_CHOICES)
obj_cate = models.CharField('绑定对象', max_length=20, help_text='people/...', null=True, blank=True)
blt = models.ForeignKey(TDevice, verbose_name='关联标签', on_delete=models.CASCADE)
employee = models.ForeignKey(Employee, verbose_name='关联人员', on_delete=models.CASCADE, null=True, blank=True)
obj_cate = models.CharField(
'绑定对象', max_length=20, help_text='people/...', null=True, blank=True)
blt = models.ForeignKey(TDevice, verbose_name='关联标签',
on_delete=models.CASCADE)
employee = models.ForeignKey(
Employee, verbose_name='关联人员', on_delete=models.CASCADE, null=True, blank=True)
class Tlog(BaseModel):
@ -83,3 +89,10 @@ class Tlog(BaseModel):
errors = models.TextField(null=True, blank=True)
params = models.JSONField(null=True, blank=True)
body = models.JSONField(null=True, blank=True)
class DoorAuth(BaseModel):
employee = models.ForeignKey(
Employee, verbose_name='关联用户', on_delete=models.CASCADE)
dchannel = models.ForeignKey(
TDevice, verbose_name='关联门通道', on_delete=models.CASCADE)

View File

@ -1,8 +1,8 @@
from rest_framework import serializers
from apps.am.models import Area
from apps.hrm.serializers import EmployeeSimpleSerializer
from apps.third.models import BltBind, TDevice, Tlog
from apps.hrm.serializers import EmployeeSimpleSerializer, EmployeeShortSerializer
from apps.third.models import BltBind, TDevice, Tlog, DoorAuth
from apps.utils.serializers import CustomModelSerializer
from django.core.cache import cache
@ -23,6 +23,7 @@ class TDeviceSerializer(CustomModelSerializer):
def get_mtask_(self, obj):
return cache.get('vchannel_' + obj.code, {})
class TDeviceUpdateSerializer(CustomModelSerializer):
class Meta:
model = TDevice
@ -30,7 +31,8 @@ class TDeviceUpdateSerializer(CustomModelSerializer):
def update(self, instance, validated_data):
if validated_data.get('access_list', []):
validated_data['access_list'] = ['employee', 'remployee', 'visitor']
validated_data['access_list'] = [
'employee', 'remployee', 'visitor']
return super().update(instance, validated_data)
@ -48,10 +50,14 @@ class RequestCommonSerializer(serializers.Serializer):
('delete', 'delete')
)
url = serializers.CharField(label='请求地址', required=False)
method = serializers.ChoiceField(label='请求方法', choices=method_choice, required=False)
params = serializers.JSONField(label='请求参数', required=False, allow_null=True)
json = serializers.JSONField(label='请求body(json格式)', required=False, allow_null=True)
code = serializers.CharField(label='请求短标识', required=False, allow_null=True)
method = serializers.ChoiceField(
label='请求方法', choices=method_choice, required=False)
params = serializers.JSONField(
label='请求参数', required=False, allow_null=True)
json = serializers.JSONField(
label='请求body(json格式)', required=False, allow_null=True)
code = serializers.CharField(
label='请求短标识', required=False, allow_null=True)
class BindAreaSerializer(serializers.Serializer):
@ -90,7 +96,8 @@ class BltSerializer(serializers.ModelSerializer):
class BltQuerySerializer(serializers.ModelSerializer):
depts = serializers.ListField(child=serializers.CharField(), label="部门ID列表", required=False)
depts = serializers.ListField(
child=serializers.CharField(), label="部门ID列表", required=False)
class Meta:
model = TDevice
@ -107,4 +114,14 @@ class BltBindCreateSerializer(serializers.ModelSerializer):
class BltCreatesSerializer(serializers.Serializer):
macs = serializers.ListField(child=serializers.CharField(), label='标签mac列表')
macs = serializers.ListField(
child=serializers.CharField(), label='标签mac列表')
class DoorAuthSerializer(CustomModelSerializer):
employee_ = EmployeeShortSerializer(source='employee', read_only=True)
dchannel_ = TDeviceSimpleSerializer(source='dchannel', read_only=True)
class Meta:
model = DoorAuth
fields = '__all__'

View File

@ -68,6 +68,10 @@ dhapis = {
"url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/doorAuthority",
"method": "post"
},
"card_door_authority_delete": {
"url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/doorAuthority/deleteSingleCardPrivilege",
"method": "post"
},
"mq_subscribe": {
"url": "/evo-apigw/evo-event/1.0.0/subscribe/mqinfo",
"method": "post"

View File

@ -2,7 +2,7 @@ from email.mime import base
from django.urls import path, include
from rest_framework import routers
from apps.third.views import DahuaTestView, DhCommonViewSet, SpTestView, SpeakerViewSet, XxCommonViewSet, XxTestView
from apps.third.views_d import BltViewSet, TDeviceViewSet, TlogViewSet
from apps.third.views_d import BltViewSet, TDeviceViewSet, TlogViewSet, DoorAuthViewSet
API_BASE_URL = 'api/third/'
HTML_BASE_URL = 'third/'
@ -14,6 +14,7 @@ router.register('speaker', SpeakerViewSet, basename='api_speaker')
router.register('tdevice', TDeviceViewSet, basename='tdevice')
router.register('tlog', TlogViewSet, basename='tlog')
router.register('tdevice/blt', BltViewSet, basename='blt')
router.register('doorauth', DoorAuthViewSet, basename='doorauth')
urlpatterns = [
path(API_BASE_URL, include(router.urls)),
path(API_BASE_URL + 'dahua/test/', DahuaTestView.as_view()),

View File

@ -1,6 +1,6 @@
from apps.third.filters import TDeviceFilterSet
from apps.third.models import BltBind, TDevice, Tlog
from apps.third.serializers import BindAreaSerializer, BltBindCreateSerializer, BltQuerySerializer, BltSerializer, LabelLocationSerializer, TDeviceSerializer, TDeviceUpdateSerializer, TlogSerializer
from apps.third.models import BltBind, TDevice, Tlog, DoorAuth
from apps.third.serializers import BindAreaSerializer, BltBindCreateSerializer, BltQuerySerializer, BltSerializer, LabelLocationSerializer, TDeviceSerializer, TDeviceUpdateSerializer, TlogSerializer, DoorAuthSerializer
from apps.utils.viewsets import CustomGenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from apps.third.dahua import dhClient
@ -131,13 +131,15 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
"""
三方设备接口
"""
perms_map = {'get': '*', 'put': 'tdevice.update', 'delete': 'tdevice.delete'}
perms_map = {'get': '*', 'put': 'tdevice.update',
'delete': 'tdevice.delete'}
queryset = TDevice.objects.all()
serializer_class = TDeviceSerializer
update_serializer_class = TDeviceUpdateSerializer
ordering = ['-create_time']
filterset_class = TDeviceFilterSet
select_related_fields = ['employee', 'area', 'employee__post', 'employee__belong_dept']
select_related_fields = ['employee', 'area',
'employee__post', 'employee__belong_dept']
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
@ -170,7 +172,7 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
'includeSubOwnerCodeFlag': True,
'channelCodeList': codes,
'pageSize': len(codes)
}
}
_, res = dhClient.request(**dhapis['channel_list'], json=json)
codes_dict = {}
for i in res['pageData']:
@ -211,7 +213,7 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
# ckey = 'vchannel_' + id
# cache.delete(ckey)
# return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'},
serializer_class=Serializer)
@transaction.atomic
@ -227,7 +229,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
_, res = xxClient.request(**xxapis['blt_list'], json=json)
blt_list = res['recordList']
for i in blt_list:
TDevice.objects.get_or_create(code=i['mac'], defaults={"code": i['mac'], "type": TDevice.DEVICE_BLT})
TDevice.objects.get_or_create(code=i['mac'], defaults={
"code": i['mac'], "type": TDevice.DEVICE_BLT})
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'},
@ -254,7 +257,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
td = TDevice(code=i['sn'], type=TDevice.DEVICE_SPEAKER)
td.name = i['name']
td.save()
TDevice.objects.filter(type=TDevice.DEVICE_SPEAKER).exclude(code__in=t_l).delete() # 移除不需要的
TDevice.objects.filter(type=TDevice.DEVICE_SPEAKER).exclude(
code__in=t_l).delete() # 移除不需要的
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'},
@ -280,10 +284,12 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
if td:
pass
else:
td = TDevice(code=i['channelCode'], type=TDevice.DEVICE_VCHANNEL)
td = TDevice(code=i['channelCode'],
type=TDevice.DEVICE_VCHANNEL)
td.name = i['channelName']
td.save()
TDevice.objects.filter(type=TDevice.DEVICE_VCHANNEL).exclude(code__in=t_l).delete()
TDevice.objects.filter(type=TDevice.DEVICE_VCHANNEL).exclude(
code__in=t_l).delete()
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'},
@ -307,7 +313,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
if td:
pass
else:
td = TDevice(code=i['channelCode'], type=TDevice.DEVICE_DCHANNEL)
td = TDevice(code=i['channelCode'],
type=TDevice.DEVICE_DCHANNEL)
td.name = i['channelName']
# td.access_list = ['employee', 'remployee', 'visitor']
td.save()
@ -325,7 +332,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
code = vdata['code']
blt = TDevice.objects.filter(code=code, type=TDevice.DEVICE_BLT).first()
blt = TDevice.objects.filter(
code=code, type=TDevice.DEVICE_BLT).first()
if blt:
if vdata['type'] == BltBind.BLT_BIND and vdata['employee']:
if blt.employee:
@ -385,13 +393,14 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
request.data.update({
'unitTypeList': ["1"],
'includeSubOwnerCodeFlag': True
})
})
_, res = dhClient.request(**dhapis['channel_list'], json=request.data)
codes = []
if res.get('pageData', None):
for i in res['pageData']:
codes.append(i['channelCode'])
tds_info = TDeviceSerializer(instance=TDevice.objects.filter(code__in=codes), many=True).data
tds_info = TDeviceSerializer(
instance=TDevice.objects.filter(code__in=codes), many=True).data
tds_dict = {}
for i in tds_info:
tds_dict[i['code']] = i
@ -414,7 +423,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
codes = []
for i in res['rows']:
codes.append(i['sn'])
tds_info = TDeviceSerializer(instance=TDevice.objects.filter(code__in=codes), many=True).data
tds_info = TDeviceSerializer(
instance=TDevice.objects.filter(code__in=codes), many=True).data
tds_dict = {}
for i in tds_info:
tds_dict[i['code']] = i
@ -435,13 +445,14 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
request.data.update({
'unitTypeList': ["7"],
'includeSubOwnerCodeFlag': True
})
})
_, res = dhClient.request(**dhapis['channel_list'], json=request.data)
codes = []
if res.get('pageData', None):
for i in res['pageData']:
codes.append(i['channelCode'])
tds_info = TDeviceSerializer(instance=TDevice.objects.filter(code__in=codes), many=True).data
tds_info = TDeviceSerializer(
instance=TDevice.objects.filter(code__in=codes), many=True).data
tds_dict = {}
for i in tds_info:
tds_dict[i['code']] = i
@ -527,3 +538,29 @@ class TlogViewSet(ListModelMixin, CustomGenericViewSet):
queryset = Tlog.objects.all()
serializer_class = TlogSerializer
filterset_fields = ['result', 'id']
class DoorAuthViewSet(ListModelMixin, DestroyModelMixin, CustomGenericViewSet):
"""
list: 门禁权限
门禁权限
"""
perms_map = {'get': '*', 'delete': 'doorauth.delete'}
queryset = DoorAuth.objects.all()
serializer_class = DoorAuthSerializer
filterset_fields = ['dchannel', 'employee']
select_related_fields = ['dchannel', 'employee']
search_fields = ['employee__name']
@transaction.atomic
def perform_destroy(self, instance):
dh_face_card = instance.employee.third_info['dh_face_card']
rdict = {
"cardNumber": dh_face_card,
"cardPrivilegeDetails": [
{"privilegeType": 1, "resouceCode": instance.dchannel.code},
]
}
dhClient.request(**dhapis['card_door_authority_delete'], json=rdict)
instance.delete()