feat: 「个人+团体」项目真正落地——通道级不计入单位 + 队内平均排名

口径(用户确认):
- 个人分按个人成绩排名给,**不计入单位总分**(下沉到通道级开关,不再动全局系数)
- 团体成绩 = 每队成员成绩的**平均值** → 排名(并列顺延)→ 团体模板给分 → 计入单位总分
- 平均值口径是**小项级单选项**:默认「只算有效成绩」;「全部报名人员计入」= 分母为报名条数、
  没成绩按 0 加入分子;在**成绩录入页**就地切换并立即保存

服务端:
- 迁移 0017:score_ledger 加 count_to_team(重建,无子表);event_score_channels 加 count_to_team;
  events 加 avg_mode(默认 valid)
- 规则包 Channel 加 countToTeam(缺省 true);channelTemplates 支持 individual_team →
  默认 athlete(result, 不计入单位) + team(aggregate 队内平均)
- 计分引擎:SumByTeam 跳过 count_to_team=0 的流水;实现 basis=aggregate 的队内平均团体排名
  (valid 分母=有有效成绩人数;all 分母=报名人数;某队 0 有效成绩不参与)

前端:
- 计分通道页:每行通道「计入单位总分」勾选 + basis 下拉「按队内平均」
- 成绩录入页:仅有队内平均通道的小项显示「平均值口径」单选(默认只算有效成绩),改动即存
- 录入页「实时积分预览」按新口径对齐(原先按主体求和且双通道重复计入,与发布后不一致)
- 大屏/管理端团体成绩只显示数值,不出现「平均」字样

自检:服务端 12 包全绿;前端 vue-tsc + build、node --test 134/134;console 16 文件通过。
This commit is contained in:
AskaEth committed 2026-09-10 12:02:00 +08:00
1 parent 592e47aef7
commit 6bd7bd1627
47 files changed
+1770 -153

No files matched your search

+5 -1
View File
@@ -266,6 +266,8 @@
4. 删除大项 / 小项会二次确认。
> 「个人+团体」用于团体与个人赛事合并的项目:会同时按个人通道与团体通道记分,具体通道见 10.4「计分通道」。
> 个人通道的分**只记在个人榜**,不计入单位总分;单位总分只算团体通道——把本单位成员在该组别的成绩取平均后排名再给分。
> 平均值分母(「平均值口径」)在录入页选择:选「只算有效成绩」时,一个人都没成绩的单位不参与团体排名、不得分;选「全部报名人员都计入」时,没成绩的人按 0 计入,分母是该单位在该组别的报名人数。
### 10.3 组别
@@ -281,7 +283,9 @@
1. 先选中一个小项;
2. 点「新增通道」逐条配置,同一「名次范围 + 名次来源」只能有一个通道;
3. 点「保存全部」整体替换该小项的通道配置;
4. 标记为「不计分」的小项,通道可以保存但不参与积分计算。
4. 标记为「不计分」的小项,通道可以保存但不参与积分计算;
5. 「名次来源」选「按队内平均」时,把同一个单位(或个人)在该组别的成绩**取平均**后排名,并列按积分模板的并列口径处理(默认顺延);平均值分母取录入页选的「平均值口径」;
6. 每条通道有一个「计入单位总分」开关,默认打开。关掉后该通道的分只记在个人头上,不进单位总分——「个人+团体」项目的个人通道就靠它做到只记个人。
### 10.5 积分模板