From 301130d4bf92dd9226fe02e9f08d802810afe75a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 26 Dec 2023 17:49:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E7=89=88=E8=AF=81=E4=B9=A6?= =?UTF-8?q?=E5=8F=91=E6=94=BE=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/apps/edu/admin.py | 2 + .../edu/migrations/0004_auto_20231226_1517.py | 62 ++++++++++++++ server/apps/edu/models.py | 15 +++- server/apps/edu/serializers.py | 11 ++- server/apps/edu/services.py | 84 ++++++++++++++++--- server/apps/edu/views.py | 16 +++- server/ruff.toml | 3 + 7 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 server/apps/edu/migrations/0004_auto_20231226_1517.py create mode 100644 server/ruff.toml diff --git a/server/apps/edu/admin.py b/server/apps/edu/admin.py index 8c38f3f..c2383e6 100644 --- a/server/apps/edu/admin.py +++ b/server/apps/edu/admin.py @@ -1,3 +1,5 @@ from django.contrib import admin +from .models import Course # Register your models here. +admin.site.register(Course) \ No newline at end of file diff --git a/server/apps/edu/migrations/0004_auto_20231226_1517.py b/server/apps/edu/migrations/0004_auto_20231226_1517.py new file mode 100644 index 0000000..c2d6c4c --- /dev/null +++ b/server/apps/edu/migrations/0004_auto_20231226_1517.py @@ -0,0 +1,62 @@ +# Generated by Django 3.2.12 on 2023-12-26 07:17 + +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), + ('edu', '0003_certificate_字体方案'), + ] + + operations = [ + migrations.AddField( + model_name='certificate', + name='发证日期', + field=models.DateField(blank=True, null=True), + ), + migrations.AddField( + model_name='certificate', + name='培训日期', + field=models.DateField(blank=True, null=True), + ), + migrations.AddField( + model_name='certificate', + name='证书方案', + field=models.CharField(default='202309', max_length=20), + ), + migrations.AlterField( + model_name='certificate', + name='单位名称', + field=models.CharField(blank=True, max_length=30, null=True), + ), + migrations.AlterField( + model_name='certificate', + name='所属单位', + field=models.CharField(blank=True, max_length=20, null=True), + ), + migrations.CreateModel( + name='Course', + 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='删除标记')), + ('name', models.CharField(max_length=20, verbose_name='课程名')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='course_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='course_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='certificate', + name='课程列表', + field=models.ManyToManyField(blank=True, to='edu.Course'), + ), + ] diff --git a/server/apps/edu/models.py b/server/apps/edu/models.py index e8a21d0..875b12e 100644 --- a/server/apps/edu/models.py +++ b/server/apps/edu/models.py @@ -1,13 +1,18 @@ from django.db import models -from apps.system.models import CommonADModel +from apps.system.models import CommonADModel, CommonAModel # Create your models here. +class Course(CommonAModel): + name = models.CharField('课程名', max_length=20) + class Certificate(CommonADModel): + 证书方案 = models.CharField(max_length=20, default='202309') + 字体方案 = models.PositiveSmallIntegerField(default=1) 姓名 = 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=30, null=True, blank=True) 职务 = models.CharField(max_length=20, null=True, blank=True) 手机号 = models.CharField(max_length=11, null=True, blank=True) 是否内审员 = models.BooleanField(default=False) @@ -16,5 +21,7 @@ class Certificate(CommonADModel): 是否最高管理者 = models.BooleanField(default=False) 是否需要集团证书 = models.BooleanField(default=False) 是否需要北京标研培训合格 = models.BooleanField(default=False) + 课程列表 = models.ManyToManyField(Course, blank=True) + 培训日期 = models.DateField(null=True, blank=True) + 发证日期 = models.DateField(null=True, blank=True) 证书地址 = models.CharField(max_length=100, null=True, blank=True) - 字体方案 = models.PositiveSmallIntegerField(default=1) diff --git a/server/apps/edu/serializers.py b/server/apps/edu/serializers.py index 70a2a36..971c3aa 100644 --- a/server/apps/edu/serializers.py +++ b/server/apps/edu/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from apps.edu.models import Certificate +from apps.edu.models import Certificate, Course from apps.edu.services import make_img_x class CertificateSerializer(serializers.ModelSerializer): @@ -11,4 +11,11 @@ class CertificateSerializer(serializers.ModelSerializer): def save(self, **kwargs): instance = super().save(**kwargs) make_img_x(instance) - return instance \ No newline at end of file + return instance + + +class CourseSerializer(serializers.ModelSerializer): + class Meta: + model = Course + 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 index 6c1da14..6338d1c 100644 --- a/server/apps/edu/services.py +++ b/server/apps/edu/services.py @@ -1,6 +1,7 @@ from PIL import ImageFont, ImageDraw, Image from django.conf import settings from apps.edu.models import Certificate +from datetime import date font_dict = { 'font_1': "/media/cert/template/weibei.ttf", 'font_2': "/media/cert/template/SIMLI.TTF" @@ -8,17 +9,78 @@ font_dict = { def make_img_x(instance: Certificate): - titles = [] - if instance.是否内审员: - titles.append('内审员') - if instance.是否授权签字人: - titles.append('授权签字人') - if instance.是否质量负责人: - titles.append('质量负责人') - if instance.是否最高管理者: - titles.append('最高管理者') - instance.证书地址 = make_img(instance.证书编号, instance.姓名, '、'.join(titles), font_dict[f'font_{instance.字体方案}']) - instance.save() + if instance.证书方案 == '202309': + titles = [] + if instance.是否内审员: + titles.append('内审员') + if instance.是否授权签字人: + titles.append('授权签字人') + if instance.是否质量负责人: + titles.append('质量负责人') + if instance.是否最高管理者: + titles.append('最高管理者') + instance.证书地址 = make_img(instance.证书编号, instance.姓名, '、'.join(titles), font_dict[f'font_{instance.字体方案}']) + instance.save() + elif instance.证书方案 == '202312': + courses_list = [i.name for i in instance.课程列表.all()] + courses = ';'.join(courses_list) + '。' + instance.证书地址 = make_img_2(instance.证书编号, instance.姓名, instance.培训日期, instance.发证日期, courses, font_dict[f'font_{instance.字体方案}']) + instance.save() + +def text_wrap(draw, text, font, max_width): + lines = [] + + # 将文本分割成单词 + words = list(text) + # 尝试将单词拼成一行,使其宽度不要超过最大宽度 + while words: + line = '' + # 当加上一个新单词不会让行宽超出最大宽度时就加上它 + while words and draw.textlength(line + words[0], font=font) <= max_width: + line += words.pop(0) + lines.append(line.strip()) # 移除多余的空格 + return lines + +def make_img_2(number, name, att_date: date, issue_date: date, courses, font_name_path): + # 打开底版图片 + imageFile = settings.BASE_DIR + '/media/cert/template/background2.jpg' + img = Image.open(imageFile) + # 选择字体与大小 + font = ImageFont.truetype(settings.BASE_DIR+ font_name_path, 155) + font_courses = ImageFont.truetype(settings.BASE_DIR + "/media/cert/template/simkai.ttf", 100) + font_number = ImageFont.truetype(settings.BASE_DIR + "/media/cert/template/timesbd.ttf", 58) + font_day = ImageFont.truetype(settings.BASE_DIR + "/media/cert/template/Dengl.ttf", 68) + position_number = (1730, 606) + position_name = (720, 840) + position_courses = (490, 1070) + position_a_y = (1530, 900) + position_a_m = (1870, 900) + position_a_d = (2170, 900) + position_i_y = (2010, 1910) + position_i_m = (2254, 1910) + position_i_d = (2446, 1910) + color_name = (82, 68, 19) + color = (0,0,0) + draw = ImageDraw.Draw(img) + draw.text(position_name, name, color_name, font=font) + + max_width = 2800 # 根据实际证书的内容区域来设置最大宽度 + wrapped_courses = text_wrap(draw, courses, font_courses, max_width) + y_offset = 0 + for line in wrapped_courses: + draw.text((position_courses[0], position_courses[1] + y_offset), line, (0,0,0), font=font_courses) + y_offset = y_offset + 180 + draw.text(position_number, number, color_name, font=font_number) + draw.text(position_a_y, str(att_date.year), color, font=font_day) + draw.text(position_a_m, str(att_date.month), color, font=font_day) + draw.text(position_a_d, str(att_date.day), color, font=font_day) + draw.text(position_i_y, str(issue_date.year), color, font=font_day) + draw.text(position_i_m, str(issue_date.month), color, font=font_day) + draw.text(position_i_d, str(issue_date.day), color, font=font_day) + # 保存图片 + path = f"/media/cert/{number}.jpg" + img.save(settings.BASE_DIR + path) + return path def make_img(number, name, title, font_name_path): # 打开底版图片 diff --git a/server/apps/edu/views.py b/server/apps/edu/views.py index b6c4654..d7bd095 100644 --- a/server/apps/edu/views.py +++ b/server/apps/edu/views.py @@ -1,7 +1,7 @@ from rest_framework.viewsets import ModelViewSet from apps.system.mixins import CreateUpdateCustomMixin -from apps.edu.serializers import CertificateSerializer -from apps.edu.models import Certificate +from apps.edu.serializers import CertificateSerializer, CourseSerializer +from apps.edu.models import Certificate, Course from rest_framework.decorators import action from django.conf import settings from rest_framework.exceptions import ParseError @@ -11,6 +11,14 @@ from rest_framework.serializers import Serializer from rest_framework.permissions import AllowAny from apps.edu.services import make_img_x # Create your views here. +class CourseViewSet(CreateUpdateCustomMixin, ModelViewSet): + perms_map = {'get': '*', 'post': 'course', + 'put': 'course', 'delete': 'course'} + queryset = Course.objects.all() + serializer_class = CourseSerializer + search_fields = ['name'] + ordering = ['create_time'] + class CertificateViewSet(CreateUpdateCustomMixin, ModelViewSet): perms_map = {'get': '*', 'post': 'certificate', @@ -18,8 +26,8 @@ class CertificateViewSet(CreateUpdateCustomMixin, ModelViewSet): queryset = Certificate.objects.all() serializer_class = CertificateSerializer search_fields = ['姓名', '证书编号', '所属单位'] - filterset_fields = ['是否内审员','是否授权签字人', '是否质量负责人', '是否最高管理者', '姓名', '证书编号', '所属单位', '单位名称'] - ordering = ['-create_time'] + filterset_fields = ['是否内审员','是否授权签字人', '是否质量负责人', '是否最高管理者', '姓名', '证书编号', '所属单位', '单位名称', '课程列表'] + ordering = ['-create_time', '证书编号'] def get_authenticators(self): if self.request.method == 'GET': diff --git a/server/ruff.toml b/server/ruff.toml new file mode 100644 index 0000000..c514775 --- /dev/null +++ b/server/ruff.toml @@ -0,0 +1,3 @@ + +line-length = 200 +fix = true \ No newline at end of file