feat: 小项类型加「个人+团体」+ 报名导入拆团体/个人两部分
小项类型: - 迁移 0016 给 events.event_type 的 CHECK 增加 individual_team。SQLite 改不了 CHECK, 而 events 被多张子表引用(含 ON DELETE CASCADE/SET NULL),事务内 DROP 重建会级联删数据, 故用 writable_schema 就地改写建表语句文本(只追加一个枚举值,'match' 在建表语句里仅出现一次, 无副作用),零数据搬动 - domain 加 EventTypeIndividualTeam;管理端下拉加「个人+团体」并提示会同时走两条通道; guards/rules 的 eventType 白名单同步(否则会被降级成 individual) - 注意:该类型目前只解决「能被选出来」,双计的算分语义(个人分不计入单位、团体按队内平均排名) 尚未实现,等口径确认后再动数据模型 报名导入: - 卡片拆成「个人报名 / 团体报名」两个 tab,小项+组别提到 tab 之上共享 - 团体报名 = 从已配置单位清单里多选(默认全不勾,正好表达「部分单位不参加」), 可逐单位为登记队员(0 人即纯单位报名),一次提交为多个单位各建一条报名 - 已报名单位仍可覆盖名单,但会提示「提交将清空原名单」,且「全选」只勾启用中且未报名的单位 自检:服务端 12 包全绿;前端 vue-tsc + build、node --test 117/117;console 16 文件通过。
This commit is contained in:
1 parent
b5f40642ff
commit
592e47aef7
19 files changed
+1318
-117
No files matched your search
@@ -88,6 +88,47 @@ func TestEventWritesWriteChangeLog(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 小项类型新增「个人+团体」:REST 写接口要能存下来并原样返回,不被当成未知类型。
|
||||
func TestEventAcceptsIndividualTeamType(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
ids := env.seed(t)
|
||||
env.createUser("recorder", "recorder-pass", "recorder")
|
||||
client, _ := env.client()
|
||||
env.login(client, "recorder", "recorder-pass")
|
||||
|
||||
status, env2 := env.do(client, http.MethodPost, "/api/events", map[string]any{
|
||||
"sportId": ids.sport, "code": "TEAM_PULLUP", "name": "团体引体向上",
|
||||
"eventType": "individual_team", "resultType": "count", "compare": "desc", "scored": true,
|
||||
}, true)
|
||||
if status != http.StatusOK || !env2.OK {
|
||||
t.Fatalf("建「个人+团体」项目应 200,得到 %d %+v", status, env2.Error)
|
||||
}
|
||||
created := decodeData[map[string]any](t, env2)
|
||||
if created["eventType"] != "individual_team" {
|
||||
t.Fatalf("建回的 eventType = %v,期望 individual_team", created["eventType"])
|
||||
}
|
||||
eventID := int64(created["id"].(float64))
|
||||
|
||||
status, env2 = env.do(client, http.MethodGet, fmt.Sprintf("/api/events/%d", eventID), nil, true)
|
||||
if status != http.StatusOK || !env2.OK {
|
||||
t.Fatalf("读项目应 200,得到 %d %+v", status, env2.Error)
|
||||
}
|
||||
if got := decodeData[map[string]any](t, env2); got["eventType"] != "individual_team" {
|
||||
t.Fatalf("读回的 eventType = %v,期望 individual_team", got["eventType"])
|
||||
}
|
||||
|
||||
status, env2 = env.do(client, http.MethodPut, fmt.Sprintf("/api/events/%d", eventID), map[string]any{
|
||||
"sportId": ids.sport, "code": "TEAM_PULLUP", "name": "团体引体向上",
|
||||
"eventType": "team", "resultType": "count", "compare": "desc", "scored": true,
|
||||
}, true)
|
||||
if status != http.StatusOK || !env2.OK {
|
||||
t.Fatalf("改回团体应 200,得到 %d %+v", status, env2.Error)
|
||||
}
|
||||
if got := decodeData[map[string]any](t, env2); got["eventType"] != "team" {
|
||||
t.Fatalf("改回的 eventType = %v,期望 team", got["eventType"])
|
||||
}
|
||||
}
|
||||
|
||||
// 证件号是人员的唯一标识:可读写、重复 409、空值不互斥(部分唯一索引)。
|
||||
func TestAthleteIDCardUnique(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
|
||||
Reference in new issue
Block a user