From fe52b60badfa5e8996cc63b36467601e5a466579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=B9=E5=89=8D=E6=98=8E?= <909355014@qq.com> Date: Wed, 29 Jun 2022 09:48:27 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BF=E5=AE=A2=E6=8E=A5=E5=8F=A3v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/auth1/urls.py | 3 +- apps/auth1/views.py | 5 +- apps/ecm/models.py | 3 ++ apps/system/views.py | 1 + apps/vm/migrations/0001_initial.py | 80 ++++++++++++++++++++++++++++++ apps/vm/migrations/__init__.py | 0 apps/vm/models.py | 12 ++++- apps/vm/serializers.py | 9 +++- apps/vm/urls.py | 15 ++++++ apps/vm/views.py | 58 +++++++++++++++++++++- server/urls.py | 1 + 11 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 apps/vm/migrations/0001_initial.py create mode 100644 apps/vm/migrations/__init__.py create mode 100644 apps/vm/urls.py diff --git a/apps/auth1/urls.py b/apps/auth1/urls.py index 22c06a89..ca3245b2 100755 --- a/apps/auth1/urls.py +++ b/apps/auth1/urls.py @@ -1,3 +1,4 @@ +from atexit import register from django.urls import path from rest_framework_simplejwt.views import (TokenObtainPairView, TokenRefreshView) @@ -10,5 +11,5 @@ urlpatterns = [ path(API_BASE_URL + 'token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), path(API_BASE_URL + 'token/black/', TokenBlackView.as_view(), name='token_black'), path(API_BASE_URL + 'login/', LoginView.as_view(), name='session_login'), - path(API_BASE_URL + 'logout/', LogoutView.as_view(), name='session_logout') + path(API_BASE_URL + 'logout/', LogoutView.as_view(), name='session_logout'), ] diff --git a/apps/auth1/views.py b/apps/auth1/views.py index 7d9b85ec..f51efee6 100755 --- a/apps/auth1/views.py +++ b/apps/auth1/views.py @@ -7,9 +7,12 @@ from django.contrib.auth import authenticate, login, logout from rest_framework.generics import CreateAPIView from rest_framework.permissions import IsAuthenticated from apps.auth1.errors import USERNAME_OR_PASSWORD_WRONG +from rest_framework.exceptions import ParseError + from apps.auth1.serializers import LoginSerializer +from apps.system.models import User # Create your views here. @@ -46,7 +49,7 @@ class LoginView(CreateAPIView): password=vdata.get('password')) if user is not None: login(request, user) - return Response() + return Response(status=201) raise ParseError(**USERNAME_OR_PASSWORD_WRONG) diff --git a/apps/ecm/models.py b/apps/ecm/models.py index a2122112..74ce8b33 100644 --- a/apps/ecm/models.py +++ b/apps/ecm/models.py @@ -39,8 +39,11 @@ class NotifySetting(CommonAModel): (40, '属地部门以上') ) event_cate = models.ForeignKey(EventCate, verbose_name='关联事件种类', on_delete=models.CASCADE) + obj_cate = models.CharField('提醒对象', max_length=20, help_text='post岗位/user用户/var变量') post = models.ForeignKey(Post, verbose_name='提醒岗位', on_delete=models.CASCADE, null=True, blank=True) + user = models.ForeignKey(User, verbose_name='提醒用户', + on_delete=models.CASCADE, null=True, blank=True) filter_recipient = models.PositiveSmallIntegerField('提醒人员过滤', null=True, blank=True) filter_area_level = models.PositiveSmallIntegerField('区域级别过滤', null=True, blank=True) sms_enable = models.BooleanField('短信通知', default=False) diff --git a/apps/system/views.py b/apps/system/views.py index d02a6091..100af8ec 100755 --- a/apps/system/views.py +++ b/apps/system/views.py @@ -427,6 +427,7 @@ class UserViewSet(CustomModelViewSet): data = { 'id': user.id, 'username': user.username, + 'type': user.type, 'name': user.name, 'posts': user.posts.values_list('name', flat=True), 'avatar': user.avatar, diff --git a/apps/vm/migrations/0001_initial.py b/apps/vm/migrations/0001_initial.py new file mode 100644 index 00000000..1110f76d --- /dev/null +++ b/apps/vm/migrations/0001_initial.py @@ -0,0 +1,80 @@ +# Generated by Django 3.2.12 on 2022-06-29 01:46 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('hrm', '0002_auto_20220617_1124'), + ('system', '0005_auto_20220627_0836'), + ] + + operations = [ + migrations.CreateModel( + name='Visit', + 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='删除标记')), + ('purpose', models.PositiveSmallIntegerField(choices=[(10, '参观'), (20, '拜访'), (30, '面试'), (40, '开会')], verbose_name='来访事由')), + ('level', models.PositiveSmallIntegerField(choices=[(10, '一般'), (20, '重要')], verbose_name='访问级别')), + ('company', models.CharField(blank=True, max_length=100, null=True, verbose_name='来访单位')), + ('state', models.PositiveSmallIntegerField(choices=[(10, '创建中'), (20, '审批中'), (30, '待入厂'), (40, '进行中'), (50, '已完成')], default=10)), + ('name', models.CharField(max_length=50, verbose_name='来访概述')), + ('description', models.TextField(blank=True, null=True, verbose_name='来访详述')), + ('visit_time', models.DateTimeField(verbose_name='来访时间')), + ('leave_time', models.DateTimeField(verbose_name='离开时间')), + ('count_people', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='来访人数')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='visit_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='visit_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('receptionist', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, 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='visit_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Visitor', + 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='删除标记')), + ('name', models.CharField(max_length=20, verbose_name='姓名')), + ('phone', models.CharField(max_length=11, verbose_name='手机号')), + ('photo', models.CharField(max_length=1000, verbose_name='证件照')), + ('id_number', models.CharField(max_length=100, verbose_name='身份证号')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='visitor_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('employee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='hrm.employee', verbose_name='成员信息')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='visitor_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ('visit', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='vm.visit', verbose_name='最近所属访问项目')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Vpeople', + 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='删除标记')), + ('is_main', models.BooleanField(default=False, verbose_name='是否主访人')), + ('visit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='vm.visit', verbose_name='关联访问项目')), + ('visitor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='vm.visitor', verbose_name='访客')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/vm/migrations/__init__.py b/apps/vm/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/vm/models.py b/apps/vm/models.py index 0094ec96..0057c317 100644 --- a/apps/vm/models.py +++ b/apps/vm/models.py @@ -9,7 +9,7 @@ class Visit(CommonBModel): """ 访问项目 """ - VISIT_PURPOSE_CHOICES = ( + V_PURPOSE_CHOICES = ( (10, '参观'), (20, '拜访'), (30, '面试'), @@ -27,13 +27,21 @@ class Visit(CommonBModel): (40, '进行中'), (50, '已完成') ) - purpose = models.PositiveSmallIntegerField('来访事由') + V_LEVEL_CHOICES = ( + (10, '一般'), + (20, '重要') + ) + purpose = models.PositiveSmallIntegerField('来访事由', choices=V_PURPOSE_CHOICES) + level = models.PositiveSmallIntegerField('访问级别', choices=V_LEVEL_CHOICES) + company = models.CharField('来访单位', max_length=100, null=True, blank=True) state = models.PositiveSmallIntegerField(choices=V_STATE_CHOICES, default=10) name = models.CharField('来访概述', max_length=50) description = models.TextField('来访详述', null=True, blank=True) visit_time = models.DateTimeField('来访时间') leave_time = models.DateTimeField('离开时间') + count_people = models.PositiveSmallIntegerField('来访人数', null=True, blank=True) receptionist = models.ForeignKey(User, verbose_name='接待人', on_delete=models.CASCADE) + # create_by 创建人 class Visitor(CommonAModel): diff --git a/apps/vm/serializers.py b/apps/vm/serializers.py index 2c9d3bb1..a806a005 100644 --- a/apps/vm/serializers.py +++ b/apps/vm/serializers.py @@ -9,7 +9,7 @@ from rest_framework import serializers class VisitCreateUpdateSerializer(CustomModelSerializer): class Meta: model = Visit - fields = ['purpose', 'name', 'description', 'visit_time', 'leave_time', 'receptionist'] + fields = ['purpose', 'name', 'description', 'visit_time', 'leave_time', 'receptionist', 'company'] class VisitSerializer(CustomModelSerializer): @@ -23,7 +23,7 @@ class VisitorCreateSerializer(CustomModelSerializer): class Meta: model = Visitor - exclude = ['name', 'phone', 'photo', 'id_number'] + fields = ['name', 'phone', 'photo', 'id_number'] class VisitorSerializer(CustomModelSerializer): @@ -48,3 +48,8 @@ class VpeopleSerializer(CustomModelSerializer): class Meta: model = Vpeople fields = '__all__' + + +class VisitorRegisterSerializer(serializers.Serializer): + name = serializers.CharField(label="姓名") + username = serializers.CharField(label='用户名', min_length=6) \ No newline at end of file diff --git a/apps/vm/urls.py b/apps/vm/urls.py new file mode 100644 index 00000000..4f5fe40f --- /dev/null +++ b/apps/vm/urls.py @@ -0,0 +1,15 @@ + +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from apps.vm.views import VisitViewSet, VisitorViewSet, VpeopleViewSet + +API_BASE_URL = 'api/vm/' +HTML_BASE_URL = 'vm/' + +router = DefaultRouter() +router.register('visit', VisitViewSet, basename='visit') +router.register('visitor', VisitorViewSet, basename='visitor') +router.register('vpeople', VpeopleViewSet, basename='vpeople') +urlpatterns = [ + path(API_BASE_URL, include(router.urls)), +] diff --git a/apps/vm/views.py b/apps/vm/views.py index dee39dde..6143acc5 100644 --- a/apps/vm/views.py +++ b/apps/vm/views.py @@ -1,12 +1,17 @@ from django.shortcuts import render +from apps.hrm.models import Employee +from apps.system.models import User from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet, GenericViewSet from apps.vm.models import Visit, Visitor, Vpeople -from apps.vm.serializers import VisitCreateUpdateSerializer, VisitSerializer, VisitorCreateSerializer, VisitorSerializer, VpeopleCreateSerializer, VpeopleSerializer +from apps.vm.serializers import VisitCreateUpdateSerializer, VisitSerializer, VisitorCreateSerializer, VisitorRegisterSerializer, VisitorSerializer, VpeopleCreateSerializer, VpeopleSerializer from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.exceptions import ParseError from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin from apps.utils.mixins import CustomDestoryModelMixin +from django.contrib.auth.hashers import make_password +from rest_framework.permissions import IsAuthenticated +from django.db import transaction # Create your views here. @@ -23,6 +28,12 @@ class VisitViewSet(CustomModelViewSet): queryset = queryset.filter(create_by=user) return queryset + def create(self, request, *args, **kwargs): + user = self.request.user + if user.type == 'visitor' and not user.employee: + raise ParseError('请先完善个人信息') + return super().create(request, *args, **kwargs) + def update(self, request, *args, **kwargs): obj = self.get_object() if obj.state != Visit.V_CREATE: @@ -42,8 +53,51 @@ class VisitorViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Custo create_serializer_class = VisitorCreateSerializer serializer_class = VisitorSerializer + @action(methods=['post'], detail=False, + authentication_classes=[], permission_classes=[], + serializer_class=VisitorRegisterSerializer) + def register(self, request, *args, **kwargs): + """访客账户注册 -class VpeopleView(ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, CustomGenericViewSet): + 访客账户注册 + """ + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data + user = User.objects.get_queryset(all=True).filter(username=vdata['username']).first() + if user: + raise ParseError('账号已存在或禁用不可注册') + else: + password = make_password('0000') + user = User.objects.create(name=vdata['name'], + username=vdata['username'], + type='visitor', + password=password) + return Response({'user': user.id}, status=201) + + @action(methods=['post'], detail=False, permission_classes=[IsAuthenticated], + serializer_class=VisitorCreateSerializer) + @transaction.atomic + def improve_info(self, request, *args, **kwargs): + """完善个人信息 + + 完善个人信息 + """ + user = self.request.user + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data + epdata = vdata + epdata['type'] = 'visitor' + epdata['user'] = user + ep = Employee(**epdata) + ep.save() + vdata['employee'] = ep + Visitor(**vdata).save() + return Response() + + +class VpeopleViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, CustomGenericViewSet): perms_map = {'get': '*', 'post': 'visit:update', 'put': 'visit:update', 'delete': 'visit:update'} queryset = Vpeople.objects.all() create_serializer_class = VpeopleCreateSerializer diff --git a/server/urls.py b/server/urls.py index 04d3ccee..f8c3e745 100755 --- a/server/urls.py +++ b/server/urls.py @@ -54,6 +54,7 @@ urlpatterns = [ path('', include('apps.ecm.urls')), path('', include('apps.rpm.urls')), path('', include('apps.opm.urls')), + path('', include('apps.vm.urls')),