From 5e747884dc616b862d6bb526c71f2d5a9a149b15 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 23 Aug 2023 15:36:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E8=AF=81=E4=B9=A6?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=88=9B=E5=BB=BA=E5=9B=BE=E7=89=87=E5=90=8E?= =?UTF-8?q?=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/apps/edu/__init__.py | 0 server/apps/edu/admin.py | 3 + server/apps/edu/apps.py | 6 ++ server/apps/edu/migrations/0001_initial.py | 46 ++++++++++ .../edu/migrations/0002_auto_20230823_1529.py | 28 +++++++ server/apps/edu/migrations/__init__.py | 0 server/apps/edu/models.py | 19 +++++ server/apps/edu/serializers.py | 8 ++ server/apps/edu/services.py | 44 ++++++++++ server/apps/edu/tests.py | 3 + server/apps/edu/urls.py | 11 +++ server/apps/edu/views.py | 83 +++++++++++++++++++ server/server/settings.py | 3 +- server/server/urls.py | 1 + 14 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 server/apps/edu/__init__.py create mode 100644 server/apps/edu/admin.py create mode 100644 server/apps/edu/apps.py create mode 100644 server/apps/edu/migrations/0001_initial.py create mode 100644 server/apps/edu/migrations/0002_auto_20230823_1529.py create mode 100644 server/apps/edu/migrations/__init__.py create mode 100644 server/apps/edu/models.py create mode 100644 server/apps/edu/serializers.py create mode 100644 server/apps/edu/services.py create mode 100644 server/apps/edu/tests.py create mode 100644 server/apps/edu/urls.py create mode 100644 server/apps/edu/views.py diff --git a/server/apps/edu/__init__.py b/server/apps/edu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/apps/edu/admin.py b/server/apps/edu/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/server/apps/edu/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/server/apps/edu/apps.py b/server/apps/edu/apps.py new file mode 100644 index 0000000..eb55b0c --- /dev/null +++ b/server/apps/edu/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EduConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'apps.edu' diff --git a/server/apps/edu/migrations/0001_initial.py b/server/apps/edu/migrations/0001_initial.py new file mode 100644 index 0000000..bda317f --- /dev/null +++ b/server/apps/edu/migrations/0001_initial.py @@ -0,0 +1,46 @@ +# Generated by Django 3.2.12 on 2023-08-23 06:57 + +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), + ] + + operations = [ + migrations.CreateModel( + name='Certificate', + 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='删除标记')), + ('姓名', models.CharField(max_length=20)), + ('性别', models.CharField(default='男', max_length=10)), + ('证书编号', models.CharField(max_length=20)), + ('所属单位', models.CharField(max_length=20)), + ('单位名称', models.CharField(max_length=30)), + ('职务', models.CharField(max_length=20)), + ('手机号', models.CharField(max_length=11)), + ('是否内审员', models.BooleanField(default=False)), + ('是否授权签字人', models.BooleanField(default=False)), + ('是否质量负责人', models.BooleanField(default=False)), + ('是否最高管理者', models.BooleanField(default=False)), + ('是否需要集团证书', models.BooleanField(default=False)), + ('是否需要北京标研培训合格', models.BooleanField(default=False)), + ('证书地址', models.CharField(blank=True, max_length=100, null=True)), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='certificate_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='certificate_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/server/apps/edu/migrations/0002_auto_20230823_1529.py b/server/apps/edu/migrations/0002_auto_20230823_1529.py new file mode 100644 index 0000000..28f4049 --- /dev/null +++ b/server/apps/edu/migrations/0002_auto_20230823_1529.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.12 on 2023-08-23 07:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('edu', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='certificate', + name='性别', + field=models.CharField(blank=True, default='男', max_length=10, null=True), + ), + migrations.AlterField( + model_name='certificate', + name='手机号', + field=models.CharField(blank=True, max_length=11, null=True), + ), + migrations.AlterField( + model_name='certificate', + name='职务', + field=models.CharField(blank=True, max_length=20, null=True), + ), + ] diff --git a/server/apps/edu/migrations/__init__.py b/server/apps/edu/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/apps/edu/models.py b/server/apps/edu/models.py new file mode 100644 index 0000000..d943926 --- /dev/null +++ b/server/apps/edu/models.py @@ -0,0 +1,19 @@ +from django.db import models +from apps.system.models import CommonADModel +# Create your models here. + +class Certificate(CommonADModel): + 姓名 = models.CharField(max_length=20) + 性别 = models.CharField(max_length=10, default='男', null=True, blank=True) + 证书编号 = models.CharField(max_length=20) + 所属单位 = models.CharField(max_length=20) + 单位名称 = models.CharField(max_length=30) + 职务 = models.CharField(max_length=20, null=True, blank=True) + 手机号 = models.CharField(max_length=11, null=True, blank=True) + 是否内审员 = models.BooleanField(default=False) + 是否授权签字人 = models.BooleanField(default=False) + 是否质量负责人 = models.BooleanField(default=False) + 是否最高管理者 = models.BooleanField(default=False) + 是否需要集团证书 = models.BooleanField(default=False) + 是否需要北京标研培训合格 = models.BooleanField(default=False) + 证书地址 = models.CharField(max_length=100, null=True, blank=True) diff --git a/server/apps/edu/serializers.py b/server/apps/edu/serializers.py new file mode 100644 index 0000000..6c3f8ea --- /dev/null +++ b/server/apps/edu/serializers.py @@ -0,0 +1,8 @@ +from rest_framework import serializers +from apps.edu.models import Certificate + +class CertificateSerializer(serializers.ModelSerializer): + class Meta: + model = Certificate + fields = '__all__' + read_only_fields = ['create_time', 'update_time', 'create_by', 'update_by', 'is_deleted'] \ No newline at end of file diff --git a/server/apps/edu/services.py b/server/apps/edu/services.py new file mode 100644 index 0000000..58c8df1 --- /dev/null +++ b/server/apps/edu/services.py @@ -0,0 +1,44 @@ +from PIL import ImageFont, ImageDraw, Image +from django.conf import settings + +def make_img(number, name, title): + # 打开底版图片 + imageFile = settings.BASE_DIR + '/media/cert/template/background.jpg' + img = Image.open(imageFile) + # 选择字体与大小 + font = ImageFont.truetype(settings.BASE_DIR+ "/media/cert/template/weibei.ttf", 155) + font_title = ImageFont.truetype(settings.BASE_DIR + "/media/cert/template/siyuan.otf", 76) + font_number = ImageFont.truetype(settings.BASE_DIR + "/media/cert/template/timesbd.ttf", 58) + # print(font) + # 在图片上添加文字 + # word = """ + # 夜 归 小 朝 + # 梦 鸟 舟 有 静 + # 星 清 载 赤 安 + # 河 风 我 羽 心 + # 一 同 湖 暮 野 + # 壶 桨 旋 落 + # 茶 驻 停 霞 + + # ldc 2020-07-25 + # """ + word_number = number #"CTCZL20230001" + word_name = name #"曹前明" + word_title = title #"内审员、授权签字人、质量负责人、最高管理者" + # width = img.width + # height = img.height + # # 查看图片宽高 + # print(width,height) + position_number = (1772, 645) + position_name = (628, 860) + position_title = (900, 1230) + color_name = (82, 68, 19) + color = (0,0,0) + draw = ImageDraw.Draw(img) + draw.text(position_name, word_name, color_name, font=font) + draw.text(position_title, word_title, color, font=font_title) + draw.text(position_number, word_number, color_name, font=font_number) + # 保存图片 + path = f"/media/cert/{number}.jpg" + img.save(settings.BASE_DIR + path) + return path \ No newline at end of file diff --git a/server/apps/edu/tests.py b/server/apps/edu/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/server/apps/edu/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/server/apps/edu/urls.py b/server/apps/edu/urls.py new file mode 100644 index 0000000..103b7ef --- /dev/null +++ b/server/apps/edu/urls.py @@ -0,0 +1,11 @@ +from django.urls import path, include +from rest_framework import routers +from apps.edu.views import CertificateViewSet + +API_BASE_URL = 'api/edu/' +HTML_BASE_URL = 'edu/' +router = routers.DefaultRouter() +router.register('certificate', CertificateViewSet, basename="certificate") +urlpatterns = [ + path(API_BASE_URL, include(router.urls)) +] \ No newline at end of file diff --git a/server/apps/edu/views.py b/server/apps/edu/views.py new file mode 100644 index 0000000..73bd13c --- /dev/null +++ b/server/apps/edu/views.py @@ -0,0 +1,83 @@ +from django.shortcuts import render +from rest_framework.viewsets import GenericViewSet, ModelViewSet +from apps.system.mixins import CreateUpdateCustomMixin +from apps.edu.serializers import CertificateSerializer +from apps.edu.models import Certificate +from rest_framework.decorators import action +from django.db import transaction +from django.conf import settings +from rest_framework.exceptions import ParseError +from rest_framework.response import Response +from openpyxl import load_workbook +from apps.edu.services import make_img +from rest_framework.serializers import Serializer +from django.db import transaction +# Create your views here. + +class CertificateViewSet(CreateUpdateCustomMixin, ModelViewSet): + perms_map = {'get': '*', 'post': 'certificate', + 'put': 'certificate', 'delete': 'certificate'} + queryset = Certificate.objects.all() + serializer_class = CertificateSerializer + pagination_class = None + search_fields = ['姓名', '证书编号', '所属单位'] + filterset_fields = ['是否内审员','是否授权签字人', '是否质量负责人', '是否最高管理者'] + ordering = ['-create_time'] + + def retrieve(self, request, *args, **kwargs): + regen_img = request.query_params.get('regen_img', False) + instance = self.get_object() + if instance.证书地址 is None or regen_img: + titles = [] + if instance.是否内审员: + titles.append('内审员') + elif instance.是否授权签字人: + titles.append('授权签字人') + elif instance.是否质量负责人: + titles.append('质量负责人') + elif instance.是否最高管理者: + titles.append('最高管理者') + instance.证书地址 = make_img(instance.证书编号, instance.姓名, '、'.join(titles)) + instance.save() + serializer = self.get_serializer(instance) + return Response(serializer.data) + + def make_data(self, data, sheet, i): + data['证书编号'] = sheet['b'+str(i)].value + data['所属单位'] = sheet['c'+str(i)].value + data['单位名称'] = sheet['d'+str(i)].value + data['姓名'] = sheet['e'+str(i)].value + data['性别'] = sheet['f'+str(i)].value + data['职务'] = sheet['g'+str(i)].value + data['手机号'] = sheet['h'+str(i)].value + data['是否内审员'] = True if sheet['i'+str(i)].value else False + data['是否授权签字人'] = True if sheet['j'+str(i)].value else False + data['是否质量负责人'] = True if sheet['k'+str(i)].value else False + data['是否最高管理者'] = True if sheet['l'+str(i)].value else False + data['是否需要集团证书'] = True if sheet['m'+str(i)].value else False + data['是否需要北京标研培训合格'] = True if sheet['n'+str(i)].value else False + return data + + @action(methods=['post'], detail=False, perms_map = {'post':'certificate'}, serializer_class=Serializer) + def imp(self, request, *args, **kwargs): + """导入表格 + + 导入表格 + """ + path = request.data.get('path', '') + full_path = settings.BASE_DIR + path + if not path.endswith('.xlsx'): + raise ParseError('请提供xlsx格式文件') + wb = load_workbook(full_path, data_only=True) + sheet = wb.worksheets[0] + i = 3 + while sheet['b'+str(i)].value: + data = {} + data = self.make_data(data, sheet, i) + obj, created = Certificate.objects.update_or_create(defaults=data, 证书编号=data['证书编号']) + if created: + print(f'已创建证书-{data["姓名"]}-{data["证书编号"]}') + else: + print(f'已更新证书-{data["姓名"]}-{data["证书编号"]}') + i = i + 1 + return Response() \ No newline at end of file diff --git a/server/server/settings.py b/server/server/settings.py index 1934997..f7b3066 100644 --- a/server/server/settings.py +++ b/server/server/settings.py @@ -50,7 +50,8 @@ INSTALLED_APPS = [ 'apps.vod', 'apps.consulting', 'apps.exam', - 'apps.ops' + 'apps.ops', + 'apps.edu' ] diff --git a/server/server/urls.py b/server/server/urls.py index b4b8c41..f5ad6fd 100644 --- a/server/server/urls.py +++ b/server/server/urls.py @@ -62,6 +62,7 @@ urlpatterns = [ path('api/consulting/', include('apps.consulting.urls')), path('', include('apps.ops.urls')), path('', include('apps.exam.urls')), + path('', include('apps.edu.urls')), path('api/docs/', include_docs_urls(title="接口文档",authentication_classes=[], permission_classes=[])), url(r'^api/swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),