打卡接口
This commit is contained in:
parent
50ed7ea9ec
commit
509404994a
|
@ -0,0 +1,9 @@
|
|||
from django_filters import rest_framework as filters
|
||||
from apps.hrm.models import ClockRecord
|
||||
|
||||
class ClockRecordFilterSet(filters.FilterSet):
|
||||
create_time_start = filters.DateFilter(field_name="create_time", lookup_expr='gte')
|
||||
create_time_end = filters.DateFilter(field_name="create_time", lookup_expr='lte')
|
||||
class Meta:
|
||||
model = ClockRecord
|
||||
fields = ['create_by', 'create_time_start', 'create_time_end']
|
|
@ -36,8 +36,12 @@ class Employee(CommonAModel):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
# class Attendance(CommonADModel):
|
||||
# """
|
||||
# 出勤记录
|
||||
# """
|
||||
|
||||
class ClockRecord(CommonADModel):
|
||||
"""
|
||||
打卡记录
|
||||
"""
|
||||
ClOCK_WORK1 = 10
|
||||
type_choice = (
|
||||
(ClOCK_WORK1, '上班打卡'),
|
||||
)
|
||||
type = models.PositiveSmallIntegerField('打卡类型', choices=type_choice, default=ClOCK_WORK1)
|
|
@ -1,7 +1,7 @@
|
|||
from apps.system.models import User
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework import serializers
|
||||
from .models import Employee
|
||||
from .models import ClockRecord, Employee
|
||||
from apps.system.serializers import UserListSerializer, UserSimpleSerializer
|
||||
from django.db.models.query import Prefetch
|
||||
|
||||
|
@ -23,3 +23,13 @@ class EmployeeSerializer(ModelSerializer):
|
|||
|
||||
class FaceLoginSerializer(serializers.Serializer):
|
||||
base64 = serializers.CharField()
|
||||
|
||||
|
||||
class FaceClockCreateSerializer(serializers.Serializer):
|
||||
base64 = serializers.CharField()
|
||||
|
||||
class ClockRecordListSerializer(serializers.ModelSerializer):
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
class Meta:
|
||||
model = ClockRecord
|
||||
fields = '__all__'
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
from django.conf import settings
|
||||
import uuid
|
||||
import face_recognition
|
||||
import os
|
||||
from apps.hrm.models import Employee
|
||||
from apps.system.models import User
|
||||
|
||||
class HRMService:
|
||||
|
||||
def face_compare_from_base64(cls, base64_data):
|
||||
filename = str(uuid.uuid4())
|
||||
filepath = settings.BASE_DIR +'/temp/' + 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)[0]
|
||||
os.remove(filepath)
|
||||
except:
|
||||
os.remove(filepath)
|
||||
return None, '头像解码失败'
|
||||
|
||||
# 匹配人脸库
|
||||
user_faces = Employee.objects.filter(face_data__isnull=False, user__is_active=True).values('user', 'face_data')
|
||||
user_l = []
|
||||
face_l = []
|
||||
for i in user_faces:
|
||||
user_l.append(i['user'])
|
||||
face_l.append(i['face_data'])
|
||||
|
||||
results = face_recognition.compare_faces(face_l, unknown_face_encoding, tolerance=0.5)
|
||||
for index, value in enumerate(results):
|
||||
if value:
|
||||
# 识别成功
|
||||
user = User.objects.get(id=user_l[index])
|
||||
return user, ''
|
||||
return None, '识别失败'
|
|
@ -1,11 +1,12 @@
|
|||
from django.db.models import base
|
||||
from rest_framework import urlpatterns
|
||||
from apps.hrm.views import EmployeeViewSet, FaceLogin
|
||||
from apps.hrm.views import ClockRecordViewSet, EmployeeViewSet, FaceLogin
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('employee', EmployeeViewSet, basename='employee')
|
||||
router.register('clock_record', ClockRecordViewSet, basename='clock_record')
|
||||
urlpatterns = [
|
||||
path('facelogin/', FaceLogin.as_view()),
|
||||
path('', include(router.urls)),
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
from django.shortcuts import render
|
||||
from pytz import timezone
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.viewsets import ModelViewSet, GenericViewSet
|
||||
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin
|
||||
from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin
|
||||
from apps.hrm.filters import ClockRecordFilterSet
|
||||
from apps.hrm.services import HRMService
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
from apps.hrm.models import Employee
|
||||
from apps.hrm.serializers import EmployeeSerializer, FaceLoginSerializer
|
||||
from apps.hrm.models import ClockRecord, Employee
|
||||
from apps.hrm.serializers import ClockRecordListSerializer, EmployeeSerializer, FaceClockCreateSerializer, FaceLoginSerializer
|
||||
import face_recognition
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
@ -12,8 +15,9 @@ import logging
|
|||
from rest_framework.generics import CreateAPIView
|
||||
from rest_framework import status
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from rest_framework import exceptions
|
||||
from apps.system.models import User
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
logger = logging.getLogger('log')
|
||||
|
||||
|
||||
|
@ -50,9 +54,51 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix
|
|||
except:
|
||||
logger.error('人脸识别出错')
|
||||
|
||||
import uuid
|
||||
|
||||
class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
打卡记录
|
||||
"""
|
||||
perms_map = {'get':'*', 'post':'*'}
|
||||
authentication_classes = []
|
||||
queryset = ClockRecord.objects.select_related('create_by').all()
|
||||
serializer_class = ClockRecordListSerializer
|
||||
filterset_class = ClockRecordFilterSet
|
||||
ordering = ['-pk']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'create':
|
||||
return FaceClockCreateSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
base64_data = base64.urlsafe_b64decode(tran64(request.data.get('base64').replace(' ', '+')))
|
||||
user, msg = HRMService.face_compare_from_base64(base64_data)
|
||||
if user:
|
||||
now = timezone.now()
|
||||
if 7<=now.hour<=9:
|
||||
ins, created = ClockRecord.objects.get_or_create(
|
||||
create_by=request.user, create_time__hour__in = [7,8],
|
||||
create_time__year=now.year, create_time__month=now.month, create_time__day=now.day,
|
||||
defaults={
|
||||
'type':ClockRecord.ClOCK_WORK1,
|
||||
'create_by':user,
|
||||
'create_time':now
|
||||
})
|
||||
if not created:
|
||||
ins.create_time = now
|
||||
ins.save()
|
||||
# 设为在岗
|
||||
user.is_atwork = True
|
||||
user.save()
|
||||
return Response(UserSimpleSerializer(instance=user).data)
|
||||
return Response('打卡失败', status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response(msg, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
|
||||
|
||||
import base64
|
||||
import os
|
||||
|
||||
def tran64(s):
|
||||
missing_padding = len(s) % 4
|
||||
|
@ -70,41 +116,13 @@ class FaceLogin(CreateAPIView):
|
|||
"""
|
||||
人脸识别登录
|
||||
"""
|
||||
# serializer = FaceLoginSerializer(data=request.data)
|
||||
# serializer.is_valid(raise_exception=True)
|
||||
filename = str(uuid.uuid4())
|
||||
filepath = settings.BASE_DIR +'/temp/' + filename +'.png'
|
||||
with open(filepath, 'wb') as f:
|
||||
data = tran64(request.data.get('base64').replace(' ', '+'))
|
||||
f.write(base64.urlsafe_b64decode(data))
|
||||
# picture_of_me = face_recognition.load_image_file(settings.BASE_DIR +'/temp/me.png')
|
||||
# my_face_encoding = face_recognition.face_encodings(picture_of_me)[0]
|
||||
#results = face_recognition.compare_faces([my_face_encoding], unknown_face_encoding, tolerance=0.2)
|
||||
try:
|
||||
unknown_picture = face_recognition.load_image_file(filepath)
|
||||
unknown_face_encoding = face_recognition.face_encodings(unknown_picture)[0]
|
||||
os.remove(filepath)
|
||||
except:
|
||||
os.remove(filepath)
|
||||
return Response('头像解码失败', status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 匹配人脸库
|
||||
user_faces = Employee.objects.filter(face_data__isnull=False, user__is_active=True).values('user', 'face_data')
|
||||
user_l = []
|
||||
face_l = []
|
||||
for i in user_faces:
|
||||
user_l.append(i['user'])
|
||||
face_l.append(i['face_data'])
|
||||
|
||||
results = face_recognition.compare_faces(face_l, unknown_face_encoding, tolerance=0.5)
|
||||
for index, value in enumerate(results):
|
||||
if value:
|
||||
# 识别成功
|
||||
user = User.objects.get(id=user_l[index])
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return Response({
|
||||
'refresh': str(refresh),
|
||||
'access': str(refresh.access_token),
|
||||
'username':user.username
|
||||
})
|
||||
return Response('未找到对应用户', status=status.HTTP_400_BAD_REQUEST)
|
||||
base64_data = base64.urlsafe_b64decode(tran64(request.data.get('base64').replace(' ', '+')))
|
||||
user, msg = HRMService.face_compare_from_base64(base64_data)
|
||||
if user:
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return Response({
|
||||
'refresh': str(refresh),
|
||||
'access': str(refresh.access_token),
|
||||
'username':user.username
|
||||
})
|
||||
return Response(msg, status=status.HTTP_400_BAD_REQUEST)
|
|
@ -9,6 +9,7 @@ from apps.mtm.serializers import MaterialSimpleSerializer
|
|||
from django.db import transaction
|
||||
|
||||
|
||||
|
||||
class WareHouseSerializer(serializers.ModelSerializer):
|
||||
create_by_ = UserSimpleSerializer('create_by', read_only=True)
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2022-01-21 05:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('system', '0003_auto_20210812_0909'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='is_atwork',
|
||||
field=models.BooleanField(default=False, verbose_name='当前在岗'),
|
||||
),
|
||||
]
|
|
@ -116,6 +116,7 @@ class User(AbstractUser):
|
|||
superior = models.ForeignKey(
|
||||
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
|
||||
roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')
|
||||
is_atwork = models.BooleanField('当前在岗', default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '用户信息'
|
||||
|
|
Loading…
Reference in New Issue