From 509404994a54bf56f4abe3ccccaea68902271a7e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 13:41:54 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=93=E5=8D=A1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/hrm/filters.py | 9 ++ hb_server/apps/hrm/models.py | 14 ++- hb_server/apps/hrm/serializers.py | 12 +- hb_server/apps/hrm/services.py | 37 ++++++ hb_server/apps/hrm/urls.py | 3 +- hb_server/apps/hrm/views.py | 106 ++++++++++-------- hb_server/apps/inm/serializers.py | 1 + .../system/migrations/0004_user_is_atwork.py | 18 +++ hb_server/apps/system/models.py | 1 + 9 files changed, 150 insertions(+), 51 deletions(-) create mode 100644 hb_server/apps/hrm/filters.py create mode 100644 hb_server/apps/hrm/services.py create mode 100644 hb_server/apps/system/migrations/0004_user_is_atwork.py diff --git a/hb_server/apps/hrm/filters.py b/hb_server/apps/hrm/filters.py new file mode 100644 index 0000000..40c9b45 --- /dev/null +++ b/hb_server/apps/hrm/filters.py @@ -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'] \ No newline at end of file diff --git a/hb_server/apps/hrm/models.py b/hb_server/apps/hrm/models.py index 5f95387..490237e 100644 --- a/hb_server/apps/hrm/models.py +++ b/hb_server/apps/hrm/models.py @@ -36,8 +36,12 @@ class Employee(CommonAModel): def __str__(self): return self.name -# class Attendance(CommonADModel): -# """ -# 出勤记录 -# """ - \ No newline at end of file +class ClockRecord(CommonADModel): + """ + 打卡记录 + """ + ClOCK_WORK1 = 10 + type_choice = ( + (ClOCK_WORK1, '上班打卡'), + ) + type = models.PositiveSmallIntegerField('打卡类型', choices=type_choice, default=ClOCK_WORK1) \ No newline at end of file diff --git a/hb_server/apps/hrm/serializers.py b/hb_server/apps/hrm/serializers.py index 7a14400..429cc40 100644 --- a/hb_server/apps/hrm/serializers.py +++ b/hb_server/apps/hrm/serializers.py @@ -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__' diff --git a/hb_server/apps/hrm/services.py b/hb_server/apps/hrm/services.py new file mode 100644 index 0000000..14f5eb1 --- /dev/null +++ b/hb_server/apps/hrm/services.py @@ -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, '识别失败' \ No newline at end of file diff --git a/hb_server/apps/hrm/urls.py b/hb_server/apps/hrm/urls.py index 293124c..55c2e55 100644 --- a/hb_server/apps/hrm/urls.py +++ b/hb_server/apps/hrm/urls.py @@ -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)), diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index e4b7b3e..0f87cd3 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -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) \ No newline at end of file + 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) \ No newline at end of file diff --git a/hb_server/apps/inm/serializers.py b/hb_server/apps/inm/serializers.py index e983108..766a164 100644 --- a/hb_server/apps/inm/serializers.py +++ b/hb_server/apps/inm/serializers.py @@ -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) diff --git a/hb_server/apps/system/migrations/0004_user_is_atwork.py b/hb_server/apps/system/migrations/0004_user_is_atwork.py new file mode 100644 index 0000000..b512387 --- /dev/null +++ b/hb_server/apps/system/migrations/0004_user_is_atwork.py @@ -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='当前在岗'), + ), + ] diff --git a/hb_server/apps/system/models.py b/hb_server/apps/system/models.py index c773fcf..e77eae3 100644 --- a/hb_server/apps/system/models.py +++ b/hb_server/apps/system/models.py @@ -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 = '用户信息'