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:
1 parent
592e47aef7
commit
6bd7bd1627
47 files changed
+1770
-153
No files matched your search
@@ -247,7 +247,7 @@ func loadLedger(db *sql.DB) ([]domain.LedgerEntry, error) {
|
||||
rows, err := db.Query(`
|
||||
SELECT id, team_id, COALESCE(athlete_id, 0), COALESCE(event_id, 0),
|
||||
COALESCE(entry_id, 0), COALESCE(result_id, 0),
|
||||
source_type, source_id, points, voided, COALESCE(void_reason, '')
|
||||
source_type, source_id, points, voided, COALESCE(void_reason, ''), count_to_team
|
||||
FROM score_ledger ORDER BY id`)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("export: 读取积分流水: %w", err)
|
||||
@@ -256,13 +256,17 @@ func loadLedger(db *sql.DB) ([]domain.LedgerEntry, error) {
|
||||
|
||||
var out []domain.LedgerEntry
|
||||
for rows.Next() {
|
||||
var e domain.LedgerEntry
|
||||
var voided int
|
||||
var (
|
||||
e domain.LedgerEntry
|
||||
voided int
|
||||
countToTeam int
|
||||
)
|
||||
if err := rows.Scan(&e.ID, &e.TeamID, &e.AthleteID, &e.EventID, &e.EntryID, &e.ResultID,
|
||||
&e.SourceType, &e.SourceID, &e.Points, &voided, &e.VoidReason); err != nil {
|
||||
&e.SourceType, &e.SourceID, &e.Points, &voided, &e.VoidReason, &countToTeam); err != nil {
|
||||
return nil, fmt.Errorf("export: 扫描积分流水: %w", err)
|
||||
}
|
||||
e.Voided = voided != 0
|
||||
e.CountToTeam = countToTeam != 0
|
||||
out = append(out, e)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
@@ -548,7 +552,7 @@ func loadTeamDetailRows(db *sql.DB, teamID int64) ([]TeamDetailRow, error) {
|
||||
LEFT JOIN event_categories c ON c.id = en.category_id
|
||||
LEFT JOIN results r ON r.id = l.result_id
|
||||
LEFT JOIN athletes a ON a.id = l.athlete_id
|
||||
WHERE l.team_id = ? AND l.voided = 0
|
||||
WHERE l.team_id = ? AND l.voided = 0 AND l.count_to_team = 1
|
||||
ORDER BY s.sort_order, e.sort_order, e.id, c.sort_order, COALESCE(r.rank, 999999), l.id`, teamID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("export: 读取单位 %d 积分明细: %w", teamID, err)
|
||||
|
||||
Reference in new issue
Block a user