@@ -65,6 +70,23 @@
+
+
+
+ 点击上传
+
+
+
+
+
取消
@@ -126,7 +148,6 @@
:model="childCompy"
label-width="120px"
label-position="right"
- :rules="rule1"
>
{
+ updateCompany(this.companydata.id, this.companydata).then(() => {
this.getList()
+ // 清空上传图片
this.dialogVisible = false
this.$message.success('成功')
})
diff --git a/test_server/cms/migrations/0019_auto_20250304_1552.py b/test_server/cms/migrations/0019_auto_20250304_1552.py
new file mode 100644
index 0000000..b2e9e20
--- /dev/null
+++ b/test_server/cms/migrations/0019_auto_20250304_1552.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.12 on 2025-03-04 07:52
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('cms', '0018_auto_20240918_1109'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='companyinfo',
+ name='photo',
+ field=models.CharField(blank=True, max_length=100, null=True, verbose_name='公司图片'),
+ ),
+ migrations.AddField(
+ model_name='companyinfo',
+ name='remark',
+ field=models.TextField(blank=True, max_length=500, null=True, verbose_name='备注'),
+ ),
+ ]
diff --git a/test_server/cms/models.py b/test_server/cms/models.py
index 6391436..867cc69 100644
--- a/test_server/cms/models.py
+++ b/test_server/cms/models.py
@@ -69,6 +69,8 @@ class CompanyInfo(CommonModel):
edu_points = models.FloatField('教育积分', null=True, blank=True)
co_sponsor_points = models.FloatField('协办大赛积分', null=True, blank=True)
sum_points = models.FloatField('总积分', null=True, blank=True)
+ photo = models.CharField('公司图片', null=True, blank=True, max_length=100)
+ remark = models.TextField('备注', null=True, blank=True, max_length=500)
def __str__(self):
return self.company_name
diff --git a/test_server/cms/serializers.py b/test_server/cms/serializers.py
index b59a8b2..1680800 100644
--- a/test_server/cms/serializers.py
+++ b/test_server/cms/serializers.py
@@ -88,24 +88,3 @@ class ChildrenCompanySerializer(serializers.ModelSerializer):
parent_company.sum_points = parent_company.edu_points + parent_company.co_sponsor_points
parent_company.save()
return instance
-
-
-# # # 定义信号处理器
-# from django.db.models.signals import pre_save
-# from django.dispatch import receiver
-# from .models import ChildrenCompany, CompanyInfo
-
-
-# @receiver(pre_save, sender=ChildrenCompany)
-# def update_parent_sum_points(sender, instance, **kwargs):
-# parent_company = instance.parent_company
-# child_companies = ChildrenCompany.objects.filter(parent_company=parent_company)
-# # 计算子公司的积分
-# child_edu_sum = sum(c.child_edu_points or 0 for c in child_companies)
-# child_co_sponsor_sum = sum(c.child_co_sponsor_points or 0 for c in child_companies)
-
-# # 更新父公司的总积分
-# parent_company.edu_points = child_edu_sum
-# parent_company.co_sponsor_points = child_co_sponsor_sum
-# parent_company.sum_points = child_edu_sum + child_co_sponsor_sum
-# parent_company.save()
\ No newline at end of file
diff --git a/test_server/cms/views.py b/test_server/cms/views.py
index 6f215bb..bad82e6 100644
--- a/test_server/cms/views.py
+++ b/test_server/cms/views.py
@@ -78,6 +78,7 @@ class ChildrenCompanyViewSet(ModelViewSet):
ordering_fields = ['update_time']
ordering = ['-update_time']
+
class MaterialViewSet(ModelViewSet):
"""
资料:增删改查
diff --git a/test_server/crm/migrations/0048_auto_20250304_1410.py b/test_server/crm/migrations/0048_auto_20250304_1410.py
new file mode 100644
index 0000000..b6eafd6
--- /dev/null
+++ b/test_server/crm/migrations/0048_auto_20250304_1410.py
@@ -0,0 +1,22 @@
+# Generated by Django 3.2.12 on 2025-03-04 06:10
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('crm', '0047_auto_20240919_1605'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='candidate',
+ options={'ordering': ['opllevel'], 'verbose_name': '证书', 'verbose_name_plural': '证书'},
+ ),
+ migrations.AlterField(
+ model_name='candidate',
+ name='opllevel',
+ field=models.IntegerField(blank=True, choices=[(0, '高级工'), (1, '中级工'), (2, '初级工'), (3, '高级技师'), (4, '技师')], null=True),
+ ),
+ ]
diff --git a/test_server/crm/models.py b/test_server/crm/models.py
index 643245b..8f6e3b0 100644
--- a/test_server/crm/models.py
+++ b/test_server/crm/models.py
@@ -107,6 +107,13 @@ class SendCode(CommonModel):
code = models.CharField(max_length=6, verbose_name= '验证码')
class Candidate(CommonModel):
+ OP_LEVEL_CHOICES = [
+ (0, '高级工'),
+ (1, '中级工'),
+ (2, '初级工'),
+ (3, '高级技师'),
+ (4, '技师'),
+ ]
consumer = models.ForeignKey(Consumer, on_delete=models.SET_NULL, related_name='candidate_consumer', null=True, blank=True)
workscope = models.ForeignKey(WorkScope, on_delete=models.SET_NULL, related_name='candidate_workscope', null=True, blank=True)
examtest = models.OneToOneField(to='examtest.examtest', verbose_name='关联考试', null=True, blank=True, on_delete=models.SET_NULL)
@@ -130,11 +137,12 @@ class Candidate(CommonModel):
train_end_date = models.DateField('培训结束日期', null=True)
create_admin = models.ForeignKey(UserProfile, verbose_name="创建管理员", null=True, blank=True, on_delete=models.SET_NULL)
gender = models.CharField('性别', max_length=10, null=True, blank=True)
- opllevel = models.CharField('职业等级',max_length=60, null=True, blank=True)
+ opllevel = models.IntegerField(choices=OP_LEVEL_CHOICES, null=True, blank=True, default=0)
class Meta:
verbose_name = '证书'
verbose_name_plural = verbose_name
+ ordering = ['opllevel']
def __str__(self):
return self.consumer.username
diff --git a/test_server/crm/serializers.py b/test_server/crm/serializers.py
index 7e83bd5..5ad426c 100644
--- a/test_server/crm/serializers.py
+++ b/test_server/crm/serializers.py
@@ -4,7 +4,8 @@ from .models import Candidate, Company, Consumer, PaySubject, ConsumerPerm, Cons
from question.models import Question, Questioncat
from .permission import get_consumerperm_list
from rbac.serializers.user_serializer import UserListSerializer
-
+from examtest.services import make_img
+from server import settings
class ConsumerPermSerializer(serializers.ModelSerializer):
class Meta:
@@ -43,7 +44,7 @@ class ConsumerSerializer(serializers.ModelSerializer):
create_admin_name = serializers.StringRelatedField(source='create_admin', read_only=True)
class Meta:
model = Consumer
- exclude = ('avatar','collects', 'process')
+ exclude = ('collects', 'process')
@staticmethod
def setup_eager_loading(queryset):
@@ -83,6 +84,7 @@ class ConsumerDetailSerializer(serializers.ModelSerializer):
class CandidateSerializer(serializers.ModelSerializer):
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:
model = Candidate
fields = '__all__'
@@ -96,6 +98,16 @@ class CandidateCreateSerializer(serializers.ModelSerializer):
validated_data['is_manual'] = True
validated_data['create_admin'] = self.context['request'].user
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 Meta:
diff --git a/test_server/crm/views.py b/test_server/crm/views.py
index 51c3b8d..b6b60d9 100644
--- a/test_server/crm/views.py
+++ b/test_server/crm/views.py
@@ -743,8 +743,7 @@ class CandidateViewSet(RetrieveModelMixin, ListModelMixin, CreateModelMixin, Upd
filter_backends = [DjangoFilterBackend,SearchFilter, OrderingFilter]
filterset_fields = ['consumer', 'create_admin']
search_fields = ('number', 'consumer_name', 'workscope_name', 'company_name', 'create_admin__username', 'ID_number')
- ordering_fields = ('-id', 'update_time')
- ordering = ['-update_time']
+ ordering_fields = ('-id', 'update_time', 'opllevel')
def get_serializer_class(self):
if self.action in ['create', 'update']:
diff --git a/test_server/examtest/models.py b/test_server/examtest/models.py
index 958bb38..31a6a15 100644
--- a/test_server/examtest/models.py
+++ b/test_server/examtest/models.py
@@ -27,7 +27,7 @@ class Exam(CommonModel):
qdimgs = JSONField('签到图片', default=list)
xcimgs = JSONField('现场图片', default=list)
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)
def __str__(self):
diff --git a/test_server/examtest/services.py b/test_server/examtest/services.py
index 3080dde..bb0b99a 100644
--- a/test_server/examtest/services.py
+++ b/test_server/examtest/services.py
@@ -4,6 +4,10 @@ from django.utils import timezone
from datetime import timedelta
from rest_framework.exceptions import ParseError
from rbac.models import UserProfile
+from PIL import Image, ImageDraw, ImageFont
+import datetime
+from server import settings
+
def issue(obj: ExamTest, create_admin: UserProfile = None):
if create_admin is None:
create_admin = obj.exam.create_admin
@@ -35,8 +39,124 @@ def issue(obj: ExamTest, create_admin: UserProfile = None):
if cert_template == 2:
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)
+ 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:
candidate.number='SL'+ str(now.year)[-2:] + str(candidate.pk).zfill(6)
+
candidate.create_admin = create_admin
candidate.save()
- return {"id":candidate.pk, "number":candidate.number, "path":None}
\ No newline at end of file
+ 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
\ No newline at end of file