feat: 修改考试和 新增证书字段
This commit is contained in:
parent
779855ea62
commit
5638574339
|
|
@ -69,6 +69,8 @@ class CompanyInfo(CommonModel):
|
||||||
edu_points = models.FloatField('教育积分', null=True, blank=True)
|
edu_points = models.FloatField('教育积分', null=True, blank=True)
|
||||||
co_sponsor_points = models.FloatField('协办大赛积分', null=True, blank=True)
|
co_sponsor_points = models.FloatField('协办大赛积分', null=True, blank=True)
|
||||||
sum_points = models.FloatField('总积分', null=True, blank=True)
|
sum_points = models.FloatField('总积分', null=True, blank=True)
|
||||||
|
photo = models.ImageField('公司图片', upload_to='photo', null=True, blank=True)
|
||||||
|
remark = models.TextField('备注', null=True, blank=True, max_length=500)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.company_name
|
return self.company_name
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ from .models import Candidate, Company, Consumer, PaySubject, ConsumerPerm, Cons
|
||||||
from question.models import Question, Questioncat
|
from question.models import Question, Questioncat
|
||||||
from .permission import get_consumerperm_list
|
from .permission import get_consumerperm_list
|
||||||
from rbac.serializers.user_serializer import UserListSerializer
|
from rbac.serializers.user_serializer import UserListSerializer
|
||||||
|
from examtest.services import make_img
|
||||||
|
from server import settings
|
||||||
|
|
||||||
class ConsumerPermSerializer(serializers.ModelSerializer):
|
class ConsumerPermSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -43,7 +44,7 @@ class ConsumerSerializer(serializers.ModelSerializer):
|
||||||
create_admin_name = serializers.StringRelatedField(source='create_admin', read_only=True)
|
create_admin_name = serializers.StringRelatedField(source='create_admin', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Consumer
|
model = Consumer
|
||||||
exclude = ('avatar','collects', 'process')
|
exclude = ('collects', 'process')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def setup_eager_loading(queryset):
|
def setup_eager_loading(queryset):
|
||||||
|
|
@ -83,6 +84,7 @@ class ConsumerDetailSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class CandidateSerializer(serializers.ModelSerializer):
|
class CandidateSerializer(serializers.ModelSerializer):
|
||||||
create_admin_username = serializers.StringRelatedField(source='create_admin', read_only=True)
|
create_admin_username = serializers.StringRelatedField(source='create_admin', read_only=True)
|
||||||
|
cert_template = serializers.StringRelatedField(source='examtest.exam.cert_template', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Candidate
|
model = Candidate
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
@ -96,6 +98,16 @@ class CandidateCreateSerializer(serializers.ModelSerializer):
|
||||||
validated_data['is_manual'] = True
|
validated_data['is_manual'] = True
|
||||||
validated_data['create_admin'] = self.context['request'].user
|
validated_data['create_admin'] = self.context['request'].user
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
validated_data['is_manual'] = True
|
||||||
|
validated_data['create_admin'] = self.context['request'].user
|
||||||
|
issue_date = validated_data.get('issue_date', None)
|
||||||
|
exp_date = validated_data.get('end_date', None)
|
||||||
|
header_photo = settings.BASE_DIR + validated_data.get('photo', None)
|
||||||
|
path = make_img(validated_data["consumer_name"], str(issue_date.year), str(issue_date.month), str(exp_date.year), str(exp_date.month), str(exp_date.day), validated_data["number"], header_photo)
|
||||||
|
validated_data['path'] = path
|
||||||
|
return super().update(instance,validated_data)
|
||||||
|
|
||||||
class MsgSerializer(serializers.ModelSerializer):
|
class MsgSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class Exam(CommonModel):
|
||||||
qdimgs = JSONField('签到图片', default=list)
|
qdimgs = JSONField('签到图片', default=list)
|
||||||
xcimgs = JSONField('现场图片', default=list)
|
xcimgs = JSONField('现场图片', default=list)
|
||||||
only_vip = models.BooleanField('仅允许培训班学员', default=False)
|
only_vip = models.BooleanField('仅允许培训班学员', default=False)
|
||||||
cert_template = models.PositiveSmallIntegerField('证书模板', null=True, blank=True, help_text='1,2')
|
cert_template = models.PositiveSmallIntegerField('证书模板', null=True, blank=True, help_text='1,2,3')
|
||||||
auto_issue = models.BooleanField('是否自动发证', default=False)
|
auto_issue = models.BooleanField('是否自动发证', default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ from django.utils import timezone
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
from rbac.models import UserProfile
|
from rbac.models import UserProfile
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
import settings, datetime
|
||||||
|
from server import settings
|
||||||
|
|
||||||
def issue(obj: ExamTest, create_admin: UserProfile = None):
|
def issue(obj: ExamTest, create_admin: UserProfile = None):
|
||||||
if create_admin is None:
|
if create_admin is None:
|
||||||
create_admin = obj.exam.create_admin
|
create_admin = obj.exam.create_admin
|
||||||
|
|
@ -35,8 +39,124 @@ def issue(obj: ExamTest, create_admin: UserProfile = None):
|
||||||
if cert_template == 2:
|
if cert_template == 2:
|
||||||
count = Candidate.objects.filter(create_admin=create_admin, issue_date__year=now.year, issue_date__month=now.month).count()
|
count = Candidate.objects.filter(create_admin=create_admin, issue_date__year=now.year, issue_date__month=now.month).count()
|
||||||
candidate.number='HNHK'+ str(now.year) + str(now.month).zfill(2) + str(count+1).zfill(4)
|
candidate.number='HNHK'+ str(now.year) + str(now.month).zfill(2) + str(count+1).zfill(4)
|
||||||
|
elif cert_template == 3:
|
||||||
|
cer_path = make_img(candidate.consumer_name, str(candidate.start_date.year), str(candidate.start_date.month), str(candidate.end_date.year), str(candidate.end_date.month), str(candidate.end_date.day), candidate.number, header_path=candidate.photo, mode=True)
|
||||||
|
candidate.path = cer_path
|
||||||
|
candidate.number='HNHK'+ str(now.year) + str(now.month).zfill(2) + str(count+1).zfill(4)
|
||||||
|
elif cert_template == 4:
|
||||||
|
cer_path = make_img(candidate.consumer_name, str(candidate.start_date.year), str(candidate.start_date.month), str(candidate.end_date.year), str(candidate.end_date.month), str(candidate.end_date.day), candidate.number, header_path=candidate.photo, mode=False)
|
||||||
|
candidate.path = cer_path
|
||||||
|
candidate.number='HNHK'+ str(now.year) + str(now.month).zfill(2) + str(count+1).zfill(4)
|
||||||
else:
|
else:
|
||||||
candidate.number='SL'+ str(now.year)[-2:] + str(candidate.pk).zfill(6)
|
candidate.number='SL'+ str(now.year)[-2:] + str(candidate.pk).zfill(6)
|
||||||
|
|
||||||
candidate.create_admin = create_admin
|
candidate.create_admin = create_admin
|
||||||
candidate.save()
|
candidate.save()
|
||||||
return {"id":candidate.pk, "number":candidate.number, "path":None}
|
return {"id":candidate.pk, "number":candidate.number, "path":None}
|
||||||
|
|
||||||
|
|
||||||
|
def make_img(name:str, year:str, month:str, expiry_year:str, expiry_month:str, expiry_day:str, certificate_number:str, header_path=None, mode=None):
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
font_path = settings.BASE_DIR + "/media/cert/template/STKAITI.TTF"
|
||||||
|
if mode:
|
||||||
|
demo_image_path = settings.BASE_DIR + "/media/cert/template/assess.png"
|
||||||
|
# demo_image_path = r"C:\code\cma_search\server\media\test.png"
|
||||||
|
img = Image.open(demo_image_path)
|
||||||
|
if img.mode == 'RGBA':
|
||||||
|
img = img.convert('RGB')
|
||||||
|
# Initialize ImageDraw
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
# Set font paths and sizes
|
||||||
|
# font_path = r"C:/code/cma_search/server/media/font/SIMLI.TTF" # Update this to the correct font path
|
||||||
|
font_name = ImageFont.truetype(font_path, 20) # Font size for the name
|
||||||
|
font_text = ImageFont.truetype(font_path, 20) # Font size for the other text
|
||||||
|
font_number = ImageFont.truetype(font_path, 15) # Font size for the other text
|
||||||
|
|
||||||
|
# uoload header image
|
||||||
|
# header_path = "C:\code\cma_search\server\media\OIP.jpg"
|
||||||
|
if header_path:
|
||||||
|
header_img = Image.open(header_path)
|
||||||
|
# 指定粘贴的位置
|
||||||
|
header_position = (210, 235) # 粘贴图像的左上角位置
|
||||||
|
header_img = header_img.resize((140, 150))
|
||||||
|
img.paste(header_img, header_position)
|
||||||
|
if len(name) <= 3:
|
||||||
|
position_name = (105, 395)
|
||||||
|
else:
|
||||||
|
position_name = (100, 395)
|
||||||
|
position_year = (220, 395)
|
||||||
|
position_month = (280, 395)
|
||||||
|
|
||||||
|
position_exp_day = (310, 490)
|
||||||
|
position_exp_month = (270, 490)
|
||||||
|
position_exp_year = (210, 490)
|
||||||
|
position_cert_number = (180, 530)
|
||||||
|
|
||||||
|
# Define colors
|
||||||
|
color = (0, 0, 0) # Black color
|
||||||
|
|
||||||
|
# Draw the text on the image
|
||||||
|
draw.text(position_name, name, fill=color, font=font_name)
|
||||||
|
draw.text(position_year, year, fill=color, font=font_text)
|
||||||
|
draw.text(position_month, month, fill=color, font=font_text)
|
||||||
|
|
||||||
|
draw.text(position_exp_year, expiry_year, fill=color, font=font_text)
|
||||||
|
draw.text(position_exp_month, expiry_month, fill=color, font=font_text)
|
||||||
|
draw.text(position_exp_day, expiry_day, fill=color, font=font_text)
|
||||||
|
|
||||||
|
draw.text(position_cert_number, certificate_number, fill=color, font=font_number)
|
||||||
|
# Save the edited image
|
||||||
|
output_path = f"/media/cert/template/certificate/{now}.jpg"# Update this to the desired output path
|
||||||
|
img.save(settings.BASE_DIR + output_path, format='JPEG')
|
||||||
|
else:
|
||||||
|
demo_image_path = settings.BASE_DIR + "/media/cert/template/inspect.jpg"
|
||||||
|
# font_path = r"C:/code/cma_search/server/media/font/SIMLI.TTF" # Update this to the correct font path
|
||||||
|
img = Image.open(demo_image_path)
|
||||||
|
if img.mode == 'RGBA':
|
||||||
|
img = img.convert('RGB')
|
||||||
|
# Initialize ImageDraw
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
# Set font paths and sizes
|
||||||
|
font_name = ImageFont.truetype(font_path, 20) # Font size for the name
|
||||||
|
font_text = ImageFont.truetype(font_path, 20) # Font size for the other text
|
||||||
|
font_number = ImageFont.truetype(font_path, 15) # Font size for the other text
|
||||||
|
|
||||||
|
# uoload header image
|
||||||
|
if header_path:
|
||||||
|
header_img = Image.open(header_path)
|
||||||
|
# 指定粘贴的位置
|
||||||
|
header_position = (240, 250) # 粘贴图像的左上角位置
|
||||||
|
header_img = header_img.resize((120, 150))
|
||||||
|
img.paste(header_img, header_position)
|
||||||
|
|
||||||
|
# Define text positions (X, Y) based on your image
|
||||||
|
if len(name) <= 3:
|
||||||
|
position_name = (130, 430)
|
||||||
|
else:
|
||||||
|
position_name = (140, 430)
|
||||||
|
position_year = (245, 430)
|
||||||
|
position_month = (308, 430)
|
||||||
|
|
||||||
|
position_exp_day = (430, 525)
|
||||||
|
position_exp_month = (390, 525)
|
||||||
|
position_exp_year = (330, 525)
|
||||||
|
position_cert_number = (200, 565)
|
||||||
|
|
||||||
|
# Define colors
|
||||||
|
color = (0, 0, 0) # Black color
|
||||||
|
|
||||||
|
# Draw the text on the image
|
||||||
|
draw.text(position_name, name, fill=color, font=font_name)
|
||||||
|
draw.text(position_year, year, fill=color, font=font_text)
|
||||||
|
draw.text(position_month, month, fill=color, font=font_text)
|
||||||
|
|
||||||
|
draw.text(position_exp_year, expiry_year, fill=color, font=font_text)
|
||||||
|
draw.text(position_exp_month, expiry_month, fill=color, font=font_text)
|
||||||
|
draw.text(position_exp_day, expiry_day, fill=color, font=font_text)
|
||||||
|
|
||||||
|
draw.text(position_cert_number, certificate_number, fill=color, font=font_number)
|
||||||
|
# Save the edited image
|
||||||
|
output_path = f"/media/cert/template/certificate/{now}.jpg"# Update this to the desired output path # Update this to the desired output path
|
||||||
|
img.save(settings.BASE_DIR + output_path, format='JPEG')
|
||||||
|
return output_path
|
||||||
Loading…
Reference in New Issue