feat: 新版证书发放初步完成

This commit is contained in:
caoqianming 2023-12-26 17:49:52 +08:00
parent a4c5058a26
commit 301130d4bf
7 changed files with 172 additions and 21 deletions

View File

@ -1,3 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Course
# Register your models here. # Register your models here.
admin.site.register(Course)

View File

@ -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'),
),
]

View File

@ -1,13 +1,18 @@
from django.db import models from django.db import models
from apps.system.models import CommonADModel from apps.system.models import CommonADModel, CommonAModel
# Create your models here. # Create your models here.
class Course(CommonAModel):
name = models.CharField('课程名', max_length=20)
class Certificate(CommonADModel): class Certificate(CommonADModel):
证书方案 = models.CharField(max_length=20, default='202309')
字体方案 = models.PositiveSmallIntegerField(default=1)
姓名 = models.CharField(max_length=20) 姓名 = models.CharField(max_length=20)
性别 = models.CharField(max_length=10, default='', null=True, blank=True) 性别 = models.CharField(max_length=10, default='', null=True, blank=True)
证书编号 = models.CharField(max_length=20) 证书编号 = models.CharField(max_length=20)
所属单位 = models.CharField(max_length=20) 所属单位 = models.CharField(max_length=20, null=True, blank=True)
单位名称 = models.CharField(max_length=30) 单位名称 = models.CharField(max_length=30, null=True, blank=True)
职务 = models.CharField(max_length=20, null=True, blank=True) 职务 = models.CharField(max_length=20, null=True, blank=True)
手机号 = models.CharField(max_length=11, null=True, blank=True) 手机号 = models.CharField(max_length=11, null=True, blank=True)
是否内审员 = models.BooleanField(default=False) 是否内审员 = models.BooleanField(default=False)
@ -16,5 +21,7 @@ class Certificate(CommonADModel):
是否最高管理者 = 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.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.CharField(max_length=100, null=True, blank=True)
字体方案 = models.PositiveSmallIntegerField(default=1)

View File

@ -1,5 +1,5 @@
from rest_framework import serializers 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 from apps.edu.services import make_img_x
class CertificateSerializer(serializers.ModelSerializer): class CertificateSerializer(serializers.ModelSerializer):
@ -11,4 +11,11 @@ class CertificateSerializer(serializers.ModelSerializer):
def save(self, **kwargs): def save(self, **kwargs):
instance = super().save(**kwargs) instance = super().save(**kwargs)
make_img_x(instance) make_img_x(instance)
return instance 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']

View File

@ -1,6 +1,7 @@
from PIL import ImageFont, ImageDraw, Image from PIL import ImageFont, ImageDraw, Image
from django.conf import settings from django.conf import settings
from apps.edu.models import Certificate from apps.edu.models import Certificate
from datetime import date
font_dict = { font_dict = {
'font_1': "/media/cert/template/weibei.ttf", 'font_1': "/media/cert/template/weibei.ttf",
'font_2': "/media/cert/template/SIMLI.TTF" 'font_2': "/media/cert/template/SIMLI.TTF"
@ -8,17 +9,78 @@ font_dict = {
def make_img_x(instance: Certificate): def make_img_x(instance: Certificate):
titles = [] if instance.证书方案 == '202309':
if instance.是否内审员: titles = []
titles.append('内审员') if instance.是否内审员:
if instance.是否授权签字人: titles.append('内审员')
titles.append('授权签字人') if instance.是否授权签字人:
if instance.是否质量负责人: titles.append('授权签字人')
titles.append('质量负责人') if instance.是否质量负责人:
if instance.是否最高管理者: titles.append('质量负责人')
titles.append('最高管理者') if instance.是否最高管理者:
instance.证书地址 = make_img(instance.证书编号, instance.姓名, ''.join(titles), font_dict[f'font_{instance.字体方案}']) titles.append('最高管理者')
instance.save() 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): def make_img(number, name, title, font_name_path):
# 打开底版图片 # 打开底版图片

View File

@ -1,7 +1,7 @@
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from apps.system.mixins import CreateUpdateCustomMixin from apps.system.mixins import CreateUpdateCustomMixin
from apps.edu.serializers import CertificateSerializer from apps.edu.serializers import CertificateSerializer, CourseSerializer
from apps.edu.models import Certificate from apps.edu.models import Certificate, Course
from rest_framework.decorators import action from rest_framework.decorators import action
from django.conf import settings from django.conf import settings
from rest_framework.exceptions import ParseError from rest_framework.exceptions import ParseError
@ -11,6 +11,14 @@ from rest_framework.serializers import Serializer
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny
from apps.edu.services import make_img_x from apps.edu.services import make_img_x
# Create your views here. # 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): class CertificateViewSet(CreateUpdateCustomMixin, ModelViewSet):
perms_map = {'get': '*', 'post': 'certificate', perms_map = {'get': '*', 'post': 'certificate',
@ -18,8 +26,8 @@ class CertificateViewSet(CreateUpdateCustomMixin, ModelViewSet):
queryset = Certificate.objects.all() queryset = Certificate.objects.all()
serializer_class = CertificateSerializer serializer_class = CertificateSerializer
search_fields = ['姓名', '证书编号', '所属单位'] search_fields = ['姓名', '证书编号', '所属单位']
filterset_fields = ['是否内审员','是否授权签字人', '是否质量负责人', '是否最高管理者', '姓名', '证书编号', '所属单位', '单位名称'] filterset_fields = ['是否内审员','是否授权签字人', '是否质量负责人', '是否最高管理者', '姓名', '证书编号', '所属单位', '单位名称', '课程列表']
ordering = ['-create_time'] ordering = ['-create_time', '证书编号']
def get_authenticators(self): def get_authenticators(self):
if self.request.method == 'GET': if self.request.method == 'GET':

3
server/ruff.toml Normal file
View File

@ -0,0 +1,3 @@
line-length = 200
fix = true