This commit is contained in:
@@ -54,7 +54,7 @@ class CompetitionAdmin(ModelAdmin):
|
|||||||
'fields': ('start_time', 'end_time', 'status', 'project_visibility', 'allow_contestant_grading', 'is_active')
|
'fields': ('start_time', 'end_time', 'status', 'project_visibility', 'allow_contestant_grading', 'is_active')
|
||||||
}),
|
}),
|
||||||
('评分配置', {
|
('评分配置', {
|
||||||
'fields': ('score_calculation_type', 'custom_score_formula', 'active_formula'),
|
'fields': ('score_calculation_type', 'active_formula'),
|
||||||
'description': '配置得分计算方式:默认加权平均或使用评分公式'
|
'description': '配置得分计算方式:默认加权平均或使用评分公式'
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -183,7 +183,7 @@ class ScoreFormulaAdmin(ModelAdmin):
|
|||||||
}),
|
}),
|
||||||
('公式配置', {
|
('公式配置', {
|
||||||
'fields': ('formula',),
|
'fields': ('formula',),
|
||||||
'description': '使用维度名称作为变量,例如: 创新性 * 0.3 + 实用性 * 0.5 + 演示效果 * 0.2'
|
'description': '使用 dimension_X 作为变量(X为维度ID),例如: (dimension_1 + dimension_2) / 2'
|
||||||
}),
|
}),
|
||||||
('公式设置', {
|
('公式设置', {
|
||||||
'fields': ('is_active', 'is_default')
|
'fields': ('is_active', 'is_default')
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-03-20 06:19
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('competition', '0009_competition_active_formula_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='competition',
|
||||||
|
name='custom_score_formula',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -44,7 +44,6 @@ class Competition(models.Model):
|
|||||||
|
|
||||||
score_calculation_type = models.CharField(max_length=20, choices=SCORE_CALCULATION_CHOICES, default='default', verbose_name="得分计算方式")
|
score_calculation_type = models.CharField(max_length=20, choices=SCORE_CALCULATION_CHOICES, default='default', verbose_name="得分计算方式")
|
||||||
active_formula = models.ForeignKey('ScoreFormula', on_delete=models.SET_NULL, null=True, blank=True, related_name='active_competitions', verbose_name="启用的评分公式")
|
active_formula = models.ForeignKey('ScoreFormula', on_delete=models.SET_NULL, null=True, blank=True, related_name='active_competitions', verbose_name="启用的评分公式")
|
||||||
custom_score_formula = models.CharField(max_length=1000, blank=True, verbose_name="自定义得分算式", help_text="如使用自定义算式,将使用此公式计算最终得分。变量格式: dimension_维度ID,如 dimension_1, dimension_2")
|
|
||||||
|
|
||||||
is_active = models.BooleanField(default=True, verbose_name="是否启用")
|
is_active = models.BooleanField(default=True, verbose_name="是否启用")
|
||||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
||||||
@@ -178,14 +177,13 @@ class Project(models.Model):
|
|||||||
def calculate_score(self):
|
def calculate_score(self):
|
||||||
"""
|
"""
|
||||||
计算项目得分
|
计算项目得分
|
||||||
支持三种模式:
|
支持两种模式:
|
||||||
1. 默认加权平均:每个评委的得分 = sum(维度分数 × 维度权重),然后所有评委取平均
|
1. 默认加权平均:每个评委的得分 = sum(维度分数 × 维度权重),然后所有评委取平均
|
||||||
2. 使用评分公式:使用比赛关联的评分公式计算最终得分
|
2. 使用评分公式:使用比赛关联的评分公式计算最终得分
|
||||||
3. 自定义算式(比赛级别):使用比赛级别的 custom_score_formula 计算最终得分
|
|
||||||
|
|
||||||
自定义算式变量格式:
|
评分公式变量格式:
|
||||||
- dimension_X: 第X个维度的平均分(所有评委对该维度的平均分)
|
- dimension_X: 第X个维度的平均分(所有评委对该维度的平均分)
|
||||||
- 也可以使用维度名称作为变量
|
- 例如: (dimension_1 + dimension_2) / 2
|
||||||
"""
|
"""
|
||||||
scores = self.scores.all()
|
scores = self.scores.all()
|
||||||
if not scores.exists():
|
if not scores.exists():
|
||||||
@@ -198,9 +196,6 @@ class Project(models.Model):
|
|||||||
if competition.score_calculation_type == 'formula' and competition.active_formula:
|
if competition.score_calculation_type == 'formula' and competition.active_formula:
|
||||||
return self._calculate_formula_score(scores, competition.active_formula)
|
return self._calculate_formula_score(scores, competition.active_formula)
|
||||||
|
|
||||||
if competition.score_calculation_type == 'custom' and competition.custom_score_formula:
|
|
||||||
return self._calculate_custom_score(scores, competition.custom_score_formula)
|
|
||||||
|
|
||||||
return self._calculate_default_score(scores)
|
return self._calculate_default_score(scores)
|
||||||
|
|
||||||
def _calculate_default_score(self, scores):
|
def _calculate_default_score(self, scores):
|
||||||
@@ -230,10 +225,11 @@ class Project(models.Model):
|
|||||||
self.save()
|
self.save()
|
||||||
return avg_score
|
return avg_score
|
||||||
|
|
||||||
def _calculate_custom_score(self, scores, formula):
|
def _calculate_formula_score(self, scores, formula_obj):
|
||||||
"""
|
"""
|
||||||
自定义算式模式(比赛级别)
|
公式配置模式(使用 ScoreFormula 模型)
|
||||||
使用比赛配置的自定义算式计算得分
|
使用公式配置中的公式计算得分
|
||||||
|
变量格式: dimension_X (X为维度ID)
|
||||||
"""
|
"""
|
||||||
dimension_scores = {}
|
dimension_scores = {}
|
||||||
|
|
||||||
@@ -243,36 +239,6 @@ class Project(models.Model):
|
|||||||
if dim_scores.exists():
|
if dim_scores.exists():
|
||||||
avg = sum(float(s.score) for s in dim_scores) / dim_scores.count()
|
avg = sum(float(s.score) for s in dim_scores) / dim_scores.count()
|
||||||
dimension_scores[f'dimension_{dimension.id}'] = avg
|
dimension_scores[f'dimension_{dimension.id}'] = avg
|
||||||
dimension_scores[dimension.name] = avg
|
|
||||||
|
|
||||||
if not dimension_scores:
|
|
||||||
self.final_score = 0
|
|
||||||
self.save()
|
|
||||||
return 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = eval(formula, {"__builtins__": {}}, dimension_scores)
|
|
||||||
final_score = float(result)
|
|
||||||
self.final_score = round(final_score, 2)
|
|
||||||
self.save()
|
|
||||||
return self.final_score
|
|
||||||
except Exception as e:
|
|
||||||
print(f"算式计算错误: {e}, formula: {formula}, values: {dimension_scores}")
|
|
||||||
return self._calculate_default_score(scores)
|
|
||||||
|
|
||||||
def _calculate_formula_score(self, scores, formula_obj):
|
|
||||||
"""
|
|
||||||
公式配置模式(使用 ScoreFormula 模型)
|
|
||||||
使用公式配置中的公式计算得分
|
|
||||||
"""
|
|
||||||
dimension_scores = {}
|
|
||||||
|
|
||||||
dimensions = self.competition.score_dimensions.all()
|
|
||||||
for dimension in dimensions:
|
|
||||||
dim_scores = scores.filter(dimension=dimension)
|
|
||||||
if dim_scores.exists():
|
|
||||||
avg = sum(float(s.score) for s in dim_scores) / dim_scores.count()
|
|
||||||
dimension_scores[dimension.name] = avg
|
|
||||||
|
|
||||||
if not dimension_scores:
|
if not dimension_scores:
|
||||||
self.final_score = 0
|
self.final_score = 0
|
||||||
|
|||||||
Reference in New Issue
Block a user