From 4a06a9d68a43b45501a6aadba3652d8e20efb251 Mon Sep 17 00:00:00 2001 From: zty Date: Tue, 9 Apr 2024 17:29:41 +0800 Subject: [PATCH] =?UTF-8?q?feature=20feat:=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=B5=84=E8=B4=A8=E6=83=85=E5=86=B5=E5=92=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0019_auditlog_qualification.py | 57 +++++++++++++ server/apps/information/models.py | 43 +++++++++- server/apps/information/serializers.py | 13 ++- server/apps/information/urls.py | 3 +- server/apps/information/views.py | 79 +++++++++++++++---- 5 files changed, 176 insertions(+), 19 deletions(-) create mode 100644 server/apps/information/migrations/0019_auditlog_qualification.py diff --git a/server/apps/information/migrations/0019_auditlog_qualification.py b/server/apps/information/migrations/0019_auditlog_qualification.py new file mode 100644 index 0000000..12cf05a --- /dev/null +++ b/server/apps/information/migrations/0019_auditlog_qualification.py @@ -0,0 +1,57 @@ +# Generated by Django 3.2.12 on 2024-04-09 06:02 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0023_alter_user_first_name'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('information', '0018_auto_20240407_1622'), + ] + + operations = [ + migrations.CreateModel( + name='Qualification', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('company_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='公司名称')), + ('name', models.CharField(blank=True, max_length=20, null=True, verbose_name='资质名称')), + ('quali_type', models.CharField(choices=[('国家级', '国家级'), ('省级', '省级')], max_length=20, verbose_name='资质类型')), + ('org', models.CharField(blank=True, max_length=20, null=True, verbose_name='发证单位')), + ('org_date', models.DateField(blank=True, null=True, verbose_name='发证日期')), + ('expiration_date', models.DateField(blank=True, null=True, verbose_name='截至日期')), + ('scope', models.TextField(blank=True, null=True, verbose_name='资质范围')), + ('number', models.IntegerField(blank=True, null=True, verbose_name='参数数量')), + ('cie_path', models.CharField(blank=True, max_length=100, null=True, verbose_name='证书路径')), + ('create_date', models.DateTimeField(auto_now_add=True, null=True)), + ('update_date', models.DateTimeField(auto_now=True, null=True)), + ('department', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='system.organization', verbose_name='所属单位')), + ], + options={ + 'verbose_name': '资质情况', + 'db_table': 'qfn_info', + }, + ), + migrations.CreateModel( + name='AuditLog', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('action', models.CharField(max_length=20, verbose_name='动作')), + ('instance_id', models.CharField(editable=False, max_length=20, verbose_name='记录ID')), + ('change_reason', models.CharField(default='', max_length=50, verbose_name='变更原因')), + ('change_time', models.DateTimeField(verbose_name='变更时间')), + ('val_new', models.JSONField(default=dict, verbose_name='变更后完整数据')), + ('difference', models.JSONField(default=list, verbose_name='变更情况')), + ('change_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='操作人')), + ], + options={ + 'verbose_name': '资质变更情况', + 'db_table': 'qfn_change_info', + }, + ), + ] diff --git a/server/apps/information/models.py b/server/apps/information/models.py index 5a7ec39..2ca2f60 100644 --- a/server/apps/information/models.py +++ b/server/apps/information/models.py @@ -1,6 +1,47 @@ from django.db import models from django.utils import timezone from apps.system.models import Organization +import uuid + +class Qualification(models.Model): + quali_options = (('国家级','国家级'),('省级','省级')) + company_name = models.CharField(max_length=20, verbose_name='公司名称', null=True, blank=True) + name = models.CharField(max_length=20, verbose_name='资质名称',null=True, blank=True) + quali_type = models.CharField(max_length=20, choices=quali_options, verbose_name='资质类型') + org = models.CharField(max_length=20, verbose_name='发证单位', null=True, blank=True) + org_date = models.DateField(verbose_name='发证日期', null=True, blank=True) + expiration_date = models.DateField(verbose_name='截至日期', null=True, blank=True) + scope = models.TextField(verbose_name='资质范围', null=True, blank=True) + number = models.IntegerField(verbose_name='参数数量', null=True, blank=True) + cie_path = models.CharField(max_length=100, verbose_name='证书路径', null=True, blank=True) + create_date = models.DateTimeField(auto_now_add=True, null=True) + update_date = models.DateTimeField(auto_now=True, null=True) + department = models.ForeignKey(Organization, on_delete=models.PROTECT, null=True, verbose_name='所属单位') + + def save(self, *args, **kwargs): + if not self.id: + self.create_date = timezone.now() + # update_date将自动设置为当前时间,因为auto_now=True + super(Qualification, self).save(*args, **kwargs) + + class Meta: + verbose_name = '资质情况' + db_table = 'qfn_info' + + +class AuditLog(models.Model): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + action = models.CharField('动作', max_length=20) + instance_id = models.CharField('记录ID', max_length=20, editable=False) + change_reason = models.CharField('变更原因', default='', max_length=50) + change_user = models.ForeignKey('system.user', on_delete=models.SET_NULL, verbose_name='操作人', null=True, blank=True) + change_time = models.DateTimeField('变更时间') + val_new = models.JSONField('变更后完整数据', default=dict) + difference = models.JSONField('变更情况', default=list) + + class Meta: + verbose_name = '资质变更情况' + db_table = 'qfn_change_info' class AbilityReview(models.Model): @@ -30,7 +71,7 @@ class AbilityReview(models.Model): self.create_date = timezone.now() # update_date将自动设置为当前时间,因为auto_now=True super(AbilityReview, self).save(*args, **kwargs) - + class Meta: verbose_name = '评审情况' db_table = 'ability_review' diff --git a/server/apps/information/serializers.py b/server/apps/information/serializers.py index 0dcbf5e..6223ae3 100644 --- a/server/apps/information/serializers.py +++ b/server/apps/information/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers from apps.system.serializers import OrganizationSimpleSerializer -from .models import AbilityReview, QualityCommendation, QualityActivities, Contact, ExternalAuditors +from .models import AbilityReview, QualityCommendation, QualityActivities, Contact, ExternalAuditors, AuditLog, Qualification class AbilityReviewSerializer(serializers.ModelSerializer): @@ -35,4 +35,15 @@ class ExternalAuditorsSerializer(serializers.ModelSerializer): fields = '__all__' +class QualificationSerializer(serializers.ModelSerializer): + class Meta: + model = Qualification + fields = '__all__' + + +class AuditLogSerializer(serializers.ModelSerializer): + class Meta: + model = AuditLog + fields = '__all__' + diff --git a/server/apps/information/urls.py b/server/apps/information/urls.py index e76b32b..5cf107a 100644 --- a/server/apps/information/urls.py +++ b/server/apps/information/urls.py @@ -1,6 +1,6 @@ from django.urls import path, include from rest_framework import routers -from .views import AbilityReviewViewSet, QualityCommendationViewSet, QualityActivitiesViewSet, ContactViewSet, ExternalAuditorsViewSet +from .views import AbilityReviewViewSet, QualityCommendationViewSet, QualityActivitiesViewSet, ContactViewSet, ExternalAuditorsViewSet, QualificationViewSet router = routers.DefaultRouter() router.register('ar', AbilityReviewViewSet, basename='abilityreviews') @@ -8,6 +8,7 @@ router.register('qc', QualityCommendationViewSet, basename='qualitycommendation' router.register('qa', QualityActivitiesViewSet, basename='qualityactivities') router.register('contact', ContactViewSet, basename='contact') router.register('ea', ExternalAuditorsViewSet, basename='externalauditors') +router.register('faq', QualificationViewSet, basename='faq') urlpatterns = [ path('', include(router.urls)) ] \ No newline at end of file diff --git a/server/apps/information/views.py b/server/apps/information/views.py index 14718f9..6293ffd 100644 --- a/server/apps/information/views.py +++ b/server/apps/information/views.py @@ -1,11 +1,6 @@ - -from rest_framework import viewsets, mixins -from rest_framework.viewsets import ViewSet from rest_framework import status - from django.conf import settings from rest_framework.decorators import action -from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet from utils.queryset import get_child_queryset2 from rest_framework.response import Response @@ -33,7 +28,7 @@ class AbilityReviewViewSet(ModelViewSet): serializer.save() return Response(serializer.data, status = status.HTTP_201_CREATED) else: - raise ParseError("公司名称不存在") + raise ParseError("公司名称不存在") # 查询子以及已经本公司的评审情况 @action(detail=False, methods=['get']) @@ -47,6 +42,7 @@ class AbilityReviewViewSet(ModelViewSet): #根据日期过滤数据 @action(detail=False, methods=['post']) + @transaction.atomic def filter_by_date(self, request, *args, **kwargs): father_dept = request.user.dept child_dept = get_child_queryset2(father_dept) @@ -137,6 +133,7 @@ class ImpMixin: return Response({'uploaded': 'File uploaded successfully'}, status=status.HTTP_201_CREATED) + class QualityCommendationViewSet(ModelViewSet): queryset = QualityCommendation.objects.all() serializer_class = QualityCommendationSerializer @@ -153,13 +150,6 @@ class QualityCommendationViewSet(ModelViewSet): else: raise ParseError("获奖单位不存在") - # # 导入表格 - # @action(methods=['post'], detail=False) - # @transaction.atomic - # def imp(self, request, *args, **kwargs): - # return self.gen_imp_view(request, 5, QualityCommendationSerializer, 'qt') - - #构造导入的数据格式 def build_qt_data(self, sheet): data_list = [] for row in sheet.iter_rows(min_row=2, values_only=True): # 假设第一行是表头,从第二行开始读取数据 @@ -186,7 +176,6 @@ class QualityCommendationViewSet(ModelViewSet): data_list.append(serializer_data) return data_list - # 查询子以及已经本公司的质量表彰 @action(detail=False, methods=['get']) def commentdation_info(self, request, *args, **kwargs): @@ -199,6 +188,7 @@ class QualityCommendationViewSet(ModelViewSet): #根据日期过滤数据 @action(detail=False, methods=['post']) + @transaction.atomic def filter_by_date(self, request, *args, **kwargs): father_dept = request.user.dept child_dept = get_child_queryset2(father_dept) @@ -249,6 +239,7 @@ class QualityActivitiesViewSet(ModelViewSet): #根据日期过滤数据 @action(detail=False, methods=['post']) + @transaction.atomic def filter_by_date(self, request, *args, **kwargs): father_dept = request.user.dept child_dept = get_child_queryset2(father_dept) @@ -281,6 +272,7 @@ class ContactViewSet(ModelViewSet): queryset = Contact.objects.all() serializer_class = ContactSerializer + class ExternalAuditorsViewSet(ModelViewSet): queryset = ExternalAuditors.objects.all() serializer_class = ExternalAuditorsSerializer @@ -294,7 +286,7 @@ class ExternalAuditorsViewSet(ModelViewSet): serializer.save() return Response(serializer.data, status = status.HTTP_201_CREATED) else: - raise ParseError("组织单位不存在") + raise ParseError("公司名称不存在") # 查询子以及已经本公司的质量活动 @action(detail=False, methods=['get']) @@ -307,6 +299,7 @@ class ExternalAuditorsViewSet(ModelViewSet): #根据日期过滤数据 @action(detail=False, methods=['post']) + @transaction.atomic def filter_by_date(self, request, *args, **kwargs): father_dept = request.user.dept child_dept = get_child_queryset2(father_dept) @@ -330,4 +323,58 @@ class ExternalAuditorsViewSet(ModelViewSet): new_dict['评审类型'] = role_map[data_list[i]['review_types']] new_data_list.append(new_dict) data = {'count':len(serializer.data), 'results':new_data_list} - return Response(data, status = status.HTTP_200_OK) \ No newline at end of file + return Response(data, status = status.HTTP_200_OK) + + +class QualificationViewSet(ModelViewSet): + queryset = Qualification.objects.all() + serializer_class = QualificationSerializer + + #重写保存方法 + def create(self, request): + if Organization.objects.filter(name=request.data['company_name']).exists(): + department_id = Organization.objects.filter(name=request.data['company_name']).first().id + request.data['department'] = department_id + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(raise_exception=True): + serializer.save() + return Response(serializer.data, status = status.HTTP_201_CREATED) + else: + raise ParseError("公司名称不存在") + + # 重写更新的方法 + def partial_update(self, request, pk=None): + #获取需要更新的实列 + instance = self.get_object() + # 数据比较 + ignore_fields = ['create_by', 'create_date', 'update_date', 'id'] + origin_dict = QualificationSerializer(instance=instance).data + diff = [] + for k, v in request.data.items(): + if k not in ignore_fields: + origin_value = origin_dict.get(k) + if origin_value != v: + diff.append({k:{'old':origin_value, 'new':v}}) + serializers = self.get_serializer(instance, data=request.data, partial=True) + serializers.is_valid(raise_exception=True) + self.perform_update(serializers) + if diff: + AuditLog.objects.create( + action='update', + instance_id=instance.id, + change_time = datetime.now(), + change_user=request.user, + val_new=serializers.data, + difference=diff + ) + return Response(serializers.data, status = status.HTTP_204_NO_CONTENT) + + + # 查询子以及已经本公司的资质情况 + @action(detail=False, methods=['get']) + def activate_info(self, request, *args, **kwargs): + child_dept = get_child_queryset2(request.user.dept) + query = Qualification.objects.filter(department__in=child_dept) + serializer = QualificationSerializer(query, many=True) + data = {'count':len(serializer.data), 'results':serializer.data} + return Response(data, status = status.HTTP_200_OK)