From 509404994a54bf56f4abe3ccccaea68902271a7e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 13:41:54 +0800 Subject: [PATCH 01/12] =?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 = '用户信息' From ad0599ec66ce2979538e2a0ddc071f5041abac53 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 13:45:57 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E6=89=93=E5=8D=A1=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E8=8C=83=E5=9B=B4=E8=AE=BE=E7=BD=AE=E5=AE=BD,=E4=BB=A5?= =?UTF-8?q?=E4=BE=9B=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/hrm/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index 0f87cd3..fb49034 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -76,9 +76,9 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): user, msg = HRMService.face_compare_from_base64(base64_data) if user: now = timezone.now() - if 7<=now.hour<=9: + if 8<=now.hour<=17: ins, created = ClockRecord.objects.get_or_create( - create_by=request.user, create_time__hour__in = [7,8], + create_by=request.user, create_time__hour__range = [8,18], create_time__year=now.year, create_time__month=now.month, create_time__day=now.day, defaults={ 'type':ClockRecord.ClOCK_WORK1, @@ -92,7 +92,7 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): user.is_atwork = True user.save() return Response(UserSimpleSerializer(instance=user).data) - return Response('打卡失败', status=status.HTTP_400_BAD_REQUEST) + return Response('非打卡时间范围', status=status.HTTP_400_BAD_REQUEST) return Response(msg, status=status.HTTP_400_BAD_REQUEST) From 2261cf162761b83ae07a092c95161fce53bd9fed Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 13:49:18 +0800 Subject: [PATCH 03/12] =?UTF-8?q?user=20list=20=E5=A2=9E=E5=8A=A0is=5Fatwo?= =?UTF-8?q?rk=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/system/serializers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/system/serializers.py b/hb_server/apps/system/serializers.py index 10636ea..8d644b3 100644 --- a/hb_server/apps/system/serializers.py +++ b/hb_server/apps/system/serializers.py @@ -141,7 +141,9 @@ class UserListSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['id', 'name', 'phone', 'email', 'position', - 'username', 'is_active', 'date_joined', 'dept_name', 'dept', 'roles', 'avatar', 'roles_name'] + 'username', 'is_active', 'date_joined', + 'dept_name', 'dept', 'roles', 'avatar', + 'roles_name', 'is_atwork'] @staticmethod def setup_eager_loading(queryset): From 988dc29ef6e6a484dd924eb7e6a45371253d8d0b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 13:59:38 +0800 Subject: [PATCH 04/12] clock record post perm --- hb_server/apps/hrm/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index fb49034..6b83098 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -18,6 +18,7 @@ from rest_framework_simplejwt.tokens import RefreshToken from rest_framework import exceptions from apps.system.models import User from apps.system.serializers import UserSimpleSerializer +from rest_framework.permissions import AllowAny logger = logging.getLogger('log') @@ -61,6 +62,7 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): """ perms_map = {'get':'*', 'post':'*'} authentication_classes = [] + permission_classes = [AllowAny] queryset = ClockRecord.objects.select_related('create_by').all() serializer_class = ClockRecordListSerializer filterset_class = ClockRecordFilterSet From 7b81a34d8930dfa8284b4827d3e4c7b2653588d6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 14:04:39 +0800 Subject: [PATCH 05/12] face cinoare from base64 bug --- hb_server/apps/hrm/services.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hb_server/apps/hrm/services.py b/hb_server/apps/hrm/services.py index 14f5eb1..7cdc013 100644 --- a/hb_server/apps/hrm/services.py +++ b/hb_server/apps/hrm/services.py @@ -7,6 +7,7 @@ from apps.system.models import User class HRMService: + @classmethod def face_compare_from_base64(cls, base64_data): filename = str(uuid.uuid4()) filepath = settings.BASE_DIR +'/temp/' + filename +'.png' From 832f58d35febfcf1ac8673a8017a453678a1c934 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 14:16:31 +0800 Subject: [PATCH 06/12] clock record bug --- hb_server/apps/hrm/services.py | 3 ++- hb_server/apps/hrm/views.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/hrm/services.py b/hb_server/apps/hrm/services.py index 7cdc013..a80cb8e 100644 --- a/hb_server/apps/hrm/services.py +++ b/hb_server/apps/hrm/services.py @@ -22,7 +22,8 @@ class HRMService: return None, '头像解码失败' # 匹配人脸库 - user_faces = Employee.objects.filter(face_data__isnull=False, user__is_active=True).values('user', 'face_data') + 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: diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index 6b83098..ca60ee6 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -1,5 +1,5 @@ from django.shortcuts import render -from pytz import timezone +from django.utils import timezone from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin From f30c2b974131096c365a47330cc179ab1962d57f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 14:43:09 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E6=89=93=E5=8D=A1=E8=AE=B0=E5=BD=95=20ti?= =?UTF-8?q?mzone=20localtime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/hrm/tasks.py | 8 ++++++++ hb_server/apps/hrm/views.py | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 hb_server/apps/hrm/tasks.py diff --git a/hb_server/apps/hrm/tasks.py b/hb_server/apps/hrm/tasks.py new file mode 100644 index 0000000..bd4449b --- /dev/null +++ b/hb_server/apps/hrm/tasks.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import, unicode_literals + +from celery import shared_task + + +@shared_task +def x(): + print('ok') \ No newline at end of file diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index ca60ee6..10b4b06 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -74,14 +74,16 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): 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 8<=now.hour<=17: + now = timezone.localtime() + if 8<=now.hour<=17: + base64_data = base64.urlsafe_b64decode(tran64( + request.data.get('base64').replace(' ', '+'))) + user, msg = HRMService.face_compare_from_base64(base64_data) + if user: ins, created = ClockRecord.objects.get_or_create( create_by=request.user, create_time__hour__range = [8,18], - create_time__year=now.year, create_time__month=now.month, create_time__day=now.day, + create_time__year=now.year, create_time__month=now.month, + create_time__day=now.day, defaults={ 'type':ClockRecord.ClOCK_WORK1, 'create_by':user, @@ -94,8 +96,9 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): 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) + return Response(msg, status=status.HTTP_400_BAD_REQUEST) + return Response('非打卡时间范围', status=status.HTTP_400_BAD_REQUEST) + From db87609ad6cfaf1579fa531bc0e763050812d94c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 14:46:02 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apps/hrm/migrations/0004_clockrecord.py | 32 +++++++++++++++++++ hb_server/apps/hrm/views.py | 5 +-- 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 hb_server/apps/hrm/migrations/0004_clockrecord.py diff --git a/hb_server/apps/hrm/migrations/0004_clockrecord.py b/hb_server/apps/hrm/migrations/0004_clockrecord.py new file mode 100644 index 0000000..97ae889 --- /dev/null +++ b/hb_server/apps/hrm/migrations/0004_clockrecord.py @@ -0,0 +1,32 @@ +# Generated by Django 3.2.9 on 2022-01-21 06:45 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('hrm', '0003_employee_face_data'), + ] + + operations = [ + migrations.CreateModel( + name='ClockRecord', + fields=[ + ('id', models.BigAutoField(auto_created=True, 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='删除标记')), + ('type', models.PositiveSmallIntegerField(choices=[(10, '上班打卡')], default=10, verbose_name='打卡类型')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='clockrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='clockrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index 10b4b06..9c533d0 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -74,8 +74,9 @@ class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): return super().get_serializer_class() def create(self, request, *args, **kwargs): - now = timezone.localtime() - if 8<=now.hour<=17: + now = timezone.now() + now_local = timezone.localtime() + if 8<=now_local.hour<=17: base64_data = base64.urlsafe_b64decode(tran64( request.data.get('base64').replace(' ', '+'))) user, msg = HRMService.face_compare_from_base64(base64_data) From fcc6cfbade3fe16d56c64ae09f56aafbebe4a490 Mon Sep 17 00:00:00 2001 From: shilixia <2309368887@qq.com> Date: Fri, 21 Jan 2022 15:19:42 +0800 Subject: [PATCH 09/12] shebei --- hb_client/src/api/equipment.js | 10 +- hb_client/src/api/wpm.js | 12 +- hb_client/src/router/index.js | 12 +- hb_client/src/views/em/detection.vue | 591 ++++++----- hb_client/src/views/em/equipment.vue | 16 +- hb_client/src/views/em/record.vue | 79 +- hb_client/src/views/mtm/productprocess.vue | 13 +- hb_client/src/views/qm/processtest.vue | 79 -- hb_client/src/views/qm/product.vue | 2 +- hb_client/src/views/qm/unproduct.vue | 294 ++++++ hb_client/src/views/sam/order.vue | 4 +- hb_client/src/views/sam/sales.vue | 2 +- hb_client/src/views/wpm/operationdo.vue | 53 +- hb_client/src/views/wpm/productjy.vue | 1075 +++++++++----------- 14 files changed, 1210 insertions(+), 1032 deletions(-) create mode 100644 hb_client/src/views/qm/unproduct.vue diff --git a/hb_client/src/api/equipment.js b/hb_client/src/api/equipment.js index 2eadc6b..d4707e9 100644 --- a/hb_client/src/api/equipment.js +++ b/hb_client/src/api/equipment.js @@ -36,34 +36,34 @@ export function deleteEquipment(id, data) { } export function getEquipmentrecordList(query) { return request({ - url: '/em/equipmentrecord/', + url: '/em/echeck_record/', method: 'get', params: query }) } export function getEquipmentrecordAll() { return request({ - url: '/em/equipmentrecord/', + url: '/em/echeck_record/', method: 'get' }) } export function createEquipmentrecord(data) { return request({ - url: '/em/equipmentrecord/', + url: '/em/echeck_record/', method: 'post', data }) } export function updateEquipmentrecord(id, data) { return request({ - url: `/em/equipmentrecord/${id}/`, + url: `/em/echeck_record/${id}/`, method: 'put', data }) } export function deleteEquipmentrecord(id, data) { return request({ - url: `/em/equipmentrecord/${id}/`, + url: `/em/echeck_record/${id}/`, method: 'delete', data }) diff --git a/hb_client/src/api/wpm.js b/hb_client/src/api/wpm.js index 76affca..5653ac6 100644 --- a/hb_client/src/api/wpm.js +++ b/hb_client/src/api/wpm.js @@ -357,4 +357,14 @@ export function getCard(id) { url: `/wpm/wproduct/${id}/card/`, method: 'GET', }) -} \ No newline at end of file +} + +//指派发货订单 + +export function toorder(data) { + return request({ + url: '/wpm/wproduct/to_order/', + method: 'post', + data + }) +} diff --git a/hb_client/src/router/index.js b/hb_client/src/router/index.js index f849876..61be661 100644 --- a/hb_client/src/router/index.js +++ b/hb_client/src/router/index.js @@ -273,12 +273,6 @@ export const asyncRoutes = [ name: 'record', component: () => import('@/views/em/record'), meta: { title: '校准检定记录', icon: 'example', perms: ['em_record'] } - }, - { - path: 'detection ', - name: 'detection ', - component: () => import('@/views/em/detection'), - meta: { title: '运维记录', icon: 'example', perms: ['em_detection'] } } ] }, @@ -399,6 +393,12 @@ export const asyncRoutes = [ name: 'producttest', component: () => import('@/views/qm/producttest'), meta: { title: '成品检验', icon: 'example', perms: ['index_manage'] } + }, + { + path: 'unproduct', + name: 'unproduct', + component: () => import('@/views/qm/unproduct'), + meta: { title: '不合格品', icon: 'example', perms: ['index_manage'] } } ] diff --git a/hb_client/src/views/em/detection.vue b/hb_client/src/views/em/detection.vue index 4091991..c45bf3c 100644 --- a/hb_client/src/views/em/detection.vue +++ b/hb_client/src/views/em/detection.vue @@ -2,109 +2,116 @@
- 新增设备 - - 搜索 - 重置 -
- + 新增设备 + + 搜索 + 重置 +
- + - + - + - + - + - + - + - + + + + + + + + - + - - + + - + - - + + - + - + - + - - - + @@ -33,14 +35,17 @@ @@ -58,9 +63,12 @@ 批量入库 - + >批量入库 + + 批量选择订单 + + - - - + + - + @@ -88,19 +95,32 @@ {{ actstate_[scope.row.act_state] }} - - - + + + + + + + + + + + @@ -115,8 +135,17 @@ - - + + - + @@ -187,18 +183,20 @@ /> - - - + + + - + @@ -230,164 +221,11 @@ 确 定 - - + - - + - + + + + + + + + + + + + From e53024c9bc399cdd10f4921947f654d394f5caea Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 16:13:32 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E4=BA=BA=E8=84=B8=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=94=A8=E7=BC=93=E5=AD=98=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/hrm/services.py | 29 ++++++++++++++-------- hb_server/apps/hrm/signals.py | 6 ++++- hb_server/apps/hrm/tasks.py | 27 +++++++++++++++++++-- hb_server/apps/hrm/views.py | 44 ++++++++++++++-------------------- hb_server/server/settings.py | 4 ++-- 5 files changed, 69 insertions(+), 41 deletions(-) diff --git a/hb_server/apps/hrm/services.py b/hb_server/apps/hrm/services.py index a80cb8e..8cfb277 100644 --- a/hb_server/apps/hrm/services.py +++ b/hb_server/apps/hrm/services.py @@ -3,7 +3,9 @@ import uuid import face_recognition import os from apps.hrm.models import Employee +from apps.hrm.tasks import update_all_user_facedata_cache from apps.system.models import User +from django.core.cache import cache class HRMService: @@ -22,18 +24,25 @@ class HRMService: 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']) + face_datas = cache.get('face_datas') + face_users = cache.get('face_users') + if face_datas is None: + update_all_user_facedata_cache() - results = face_recognition.compare_faces(face_l, unknown_face_encoding, tolerance=0.5) + results = face_recognition.compare_faces(face_datas, unknown_face_encoding, tolerance=0.5) for index, value in enumerate(results): if value: # 识别成功 - user = User.objects.get(id=user_l[index]) + user = User.objects.get(id=face_users[index]) return user, '' - return None, '识别失败' \ No newline at end of file + return None, '识别失败' + + def get_facedata_from_img(cls, img_rpath): + try: + photo_path = settings.BASE_DIR + img_rpath + picture_of_me = face_recognition.load_image_file(photo_path) + my_face_encoding = face_recognition.face_encodings(picture_of_me)[0] + face_data_list = my_face_encoding.tolist() + return face_data_list + except: + return None \ No newline at end of file diff --git a/hb_server/apps/hrm/signals.py b/hb_server/apps/hrm/signals.py index a2a7312..7e8c922 100644 --- a/hb_server/apps/hrm/signals.py +++ b/hb_server/apps/hrm/signals.py @@ -2,8 +2,12 @@ from django.db.models.signals import post_save from apps.system.models import User from django.dispatch import receiver from apps.hrm.models import Employee +from django.conf import settings +import face_recognition +import logging +logger = logging.getLogger('log') @receiver(post_save, sender=User) def createEmployee(sender, instance, created, **kwargs): if created: - Employee.objects.get_or_create(user=instance) \ No newline at end of file + Employee.objects.get_or_create(user=instance) diff --git a/hb_server/apps/hrm/tasks.py b/hb_server/apps/hrm/tasks.py index bd4449b..d5d5a9f 100644 --- a/hb_server/apps/hrm/tasks.py +++ b/hb_server/apps/hrm/tasks.py @@ -1,8 +1,31 @@ from __future__ import absolute_import, unicode_literals from celery import shared_task +from apps.hrm.models import Employee +from apps.system.models import User +from django.core.cache import cache @shared_task -def x(): - print('ok') \ No newline at end of file +def update_all_user_not_atwork(): + """ + 将所有员工设为非在岗状态 + """ + User.objects.all().update(is_atwork=False) + +@shared_task +def update_all_user_facedata_cache(): + """ + 更新人脸数据缓存 + """ + facedata_queyset = Employee.objects.filter(face_data__isnull=False, + user__is_active=True).values('user', 'face_data') + face_users = [] + face_datas = [] + for i in facedata_queyset: + face_users.append(i['user']) + face_datas.append(i['face_data']) + cache.set('face_users', face_users, timeout=None) + cache.set('face_datas', face_datas, timeout=None) + + \ No newline at end of file diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index 9c533d0..e41ee48 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -8,10 +8,9 @@ from apps.hrm.services import HRMService from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin 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 -import logging + + + from rest_framework.generics import CreateAPIView from rest_framework import status from rest_framework_simplejwt.tokens import RefreshToken @@ -19,20 +18,8 @@ from rest_framework import exceptions from apps.system.models import User from apps.system.serializers import UserSimpleSerializer from rest_framework.permissions import AllowAny -logger = logging.getLogger('log') -def load_face_data(username:int, path:str): - """ - 将某用户face_encoding加载进缓存 - """ - face_datas = cache.get_or_set('face_datas', {}, timeout=None) - photo_path = settings.BASE_DIR + path - picture_of_me = face_recognition.load_image_file(photo_path) - my_face_encoding = face_recognition.face_encodings(picture_of_me)[0] - face_datas[username] = my_face_encoding - cache.set('face_datas', face_datas, timeout=None) - return my_face_encoding # Create your views here. class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMixin, RetrieveModelMixin, GenericViewSet): @@ -44,16 +31,21 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix serializer_class = EmployeeSerializer ordering = ['-pk'] - def perform_update(self, serializer): - instance = serializer.save(update_by = self.request.user) - try: - photo_path = settings.BASE_DIR + instance.photo - picture_of_me = face_recognition.load_image_file(photo_path) - my_face_encoding = face_recognition.face_encodings(picture_of_me)[0] - instance.face_data = my_face_encoding.tolist() - instance.save() - except: - logger.error('人脸识别出错') + def update(self, request, *args, **kwargs): + partial = kwargs.pop('partial', False) + instance = self.get_object() + data = request.data + serializer = self.get_serializer(instance, data=data, partial=partial) + serializer.is_valid(raise_exception=True) + photo = data.get('photo', None) + if instance.photo != photo: + f_l = HRMService.get_facedata_from_img(photo) + if f_l: + serializer.save(update_by=request.user, face_data = f_l) + return Response() + return Response('头像识别失败', status=status.HTTP_400_BAD_REQUEST) + serializer.save(update_by=request.user) + return Response() class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): diff --git a/hb_server/server/settings.py b/hb_server/server/settings.py index cc780f3..5cf9d99 100644 --- a/hb_server/server/settings.py +++ b/hb_server/server/settings.py @@ -194,7 +194,7 @@ AUTHENTICATION_BACKENDS = ( # CACHES = { # "default": { # "BACKEND": "django_redis.cache.RedisCache", -# "LOCATION": "redis://redis:6379/1", +# "LOCATION": "redis://127.0.0.1:6379/0", # "OPTIONS": { # "CLIENT_CLASS": "django_redis.client.DefaultClient", # "PICKLE_VERSION": -1 @@ -203,7 +203,7 @@ AUTHENTICATION_BACKENDS = ( # } # celery配置,celery正常运行必须安装redis -CELERY_BROKER_URL = "redis://redis:6379/0" # 任务存储 +CELERY_BROKER_URL = "redis://127.0.0.1:6379/1" # 任务存储 CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行300个任务就会被销毁,可防止内存泄露 CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区 CELERY_ENABLE_UTC = True # 启动时区设置 From 743d7ce862be40310d15e013a3723ccd51829e12 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 16:21:21 +0800 Subject: [PATCH 11/12] =?UTF-8?q?employee=20list=20=E5=8E=BB=E9=99=A4face?= =?UTF-8?q?=5Fdata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/hrm/serializers.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/hb_server/apps/hrm/serializers.py b/hb_server/apps/hrm/serializers.py index 429cc40..31eb30d 100644 --- a/hb_server/apps/hrm/serializers.py +++ b/hb_server/apps/hrm/serializers.py @@ -6,20 +6,9 @@ from apps.system.serializers import UserListSerializer, UserSimpleSerializer from django.db.models.query import Prefetch class EmployeeSerializer(ModelSerializer): - # user_ = UserListSerializer(source='user', read_only=True) class Meta: model = Employee - fields = '__all__' - # @staticmethod - # def setup_eager_loading(queryset): - # """ Perform necessary eager loading of data. """ - # queryset = queryset.select_related('user', 'user__dept') - # # queryset = queryset.prefetch_related('user','user__dept') - # queryset = queryset.prefetch_related( - # Prefetch('user_', - # queryset=User.objects.filter(employee_user__isnull=True)) - # ) - # return queryset + exclude = ['face_data'] class FaceLoginSerializer(serializers.Serializer): base64 = serializers.CharField() From 65fe7f060b92093f42be344323121be0873ce5dc Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Jan 2022 16:35:37 +0800 Subject: [PATCH 12/12] =?UTF-8?q?equip=20simple=E5=A2=9E=E5=8A=A0type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/hrm/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hb_server/apps/hrm/views.py b/hb_server/apps/hrm/views.py index e41ee48..dafe59c 100644 --- a/hb_server/apps/hrm/views.py +++ b/hb_server/apps/hrm/views.py @@ -1,3 +1,4 @@ +from functools import update_wrapper from django.shortcuts import render from django.utils import timezone from rest_framework.response import Response @@ -5,6 +6,7 @@ from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin from apps.hrm.filters import ClockRecordFilterSet from apps.hrm.services import HRMService +from apps.hrm.tasks import update_all_user_facedata_cache from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.hrm.models import ClockRecord, Employee from apps.hrm.serializers import ClockRecordListSerializer, EmployeeSerializer, FaceClockCreateSerializer, FaceLoginSerializer @@ -42,6 +44,8 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix f_l = HRMService.get_facedata_from_img(photo) if f_l: serializer.save(update_by=request.user, face_data = f_l) + # 更新人脸缓存 + update_all_user_facedata_cache.delay() return Response() return Response('头像识别失败', status=status.HTTP_400_BAD_REQUEST) serializer.save(update_by=request.user)