Files
competition-website/app/model/aggregation.js
qubiaobiao c101b15e2e feat(admin): 新增小组激活状态清单接口 /api/admin/teams
- router:GET /api/admin/teams(adminAuth;固定路径段,与既有路由无通配冲突)

- controller:teams() 整体透传 group/activated/includeTest(防前端筛选静默失效)

- service:getTeams(),键 = 组别+队伍号;成员并集 aggregation.team_uid ∪ contestants.team_id;学校取 aggregation.organization_cn;激活 = 全组成员均已激活;附 summary 与 schoolConflict

- model/aggregation:补声明运行库既有列 organization_cn / group(此前模型漏声明 ⇒ 查询被当未知列)

线上验证:R86 已部署上线,公网 /api/admin/teams 返回 401(鉴权在位)
2026-10-09 09:33:05 +08:00

155 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/**
* 聚合报名模型 - Aggregation
*
* 存储参赛报名聚合信息,关联竞赛、团队和账号。
* 表名:aggregation
*/
module.exports = app => {
const { STRING, INTEGER, BOOLEAN, ENUM, DATE } = app.Sequelize;
const Aggregation = app.model.define('aggregation', {
// 主键,自增
aggregation_uid: {
type: INTEGER,
primaryKey: true,
autoIncrement: true,
comment: '聚合唯一标识',
},
// 外键:竞赛 ID
competition_uid: {
type: INTEGER,
allowNull: false,
comment: '关联竞赛 ID',
},
// 外键:团队 ID(允许为空:单人参赛/未分组的选手仍可建立聚合报名,
// 以便 benke/jiaoshi 作品上传等依赖 aggregation 的流程正常工作)
team_uid: {
type: INTEGER,
allowNull: true,
comment: '关联团队 ID',
},
// 外键:账号 ID
account_uid: {
type: INTEGER,
allowNull: false,
comment: '关联账号 ID',
},
// 身份:队长/队员/指导教师
identity: {
type: STRING(20),
allowNull: false,
comment: '身份',
},
// 是否为报名负责人
is_registrant: {
type: BOOLEAN,
allowNull: false,
defaultValue: false,
comment: '是否为报名负责人',
},
// 报名表文件路径
registration_form: {
type: STRING(500),
allowNull: true,
defaultValue: null,
comment: '报名表文件路径',
},
// 盖章报名表文件路径
stamped_form: {
type: STRING(500),
allowNull: true,
defaultValue: null,
comment: '盖章报名表文件路径',
},
// 审核状态:pending/approved/rejected
audit_status: {
type: STRING(20),
allowNull: false,
defaultValue: 'pending',
comment: '审核状态',
},
// 驳回原因
reject_reason: {
type: STRING(500),
allowNull: true,
defaultValue: null,
comment: '驳回原因',
},
// 所属单位 / 学校名称(报名表原始来源,R84 续六新增声明)
// ⚠️ 该列在运行库中**一直存在**(`SHOW COLUMNS FROM aggregation` 可见),
// 只是模型漏声明 ⇒ 任何 `attributes: ['organization_cn']` 查询都会
// 被 Sequelize 当作未知列。此处补齐仅为让模型与运行库一致,
// 声明为 allowNull:true,不改变既有写入路径的语义。
organization_cn: {
type: STRING(200),
allowNull: true,
defaultValue: null,
comment: '所属单位/学校名称',
},
// 参赛组别(zhongzhi/gaozhi/benke/jiaoshi)—— 同为运行库既有列,模型漏声明。
// ⚠️ `group` 是 MySQL 保留字,Sequelize 会自动加反引号;手写 SQL 时须自行反引号。
group: {
type: STRING(20),
allowNull: true,
defaultValue: null,
comment: '参赛组别',
},
// 记录创建时间
created_at: {
type: DATE,
allowNull: false,
defaultValue: app.Sequelize.literal('CURRENT_TIMESTAMP'),
comment: '创建时间',
},
// 记录更新时间
updated_at: {
type: DATE,
allowNull: false,
defaultValue: app.Sequelize.literal('CURRENT_TIMESTAMP'),
comment: '更新时间',
},
}, {
tableName: 'aggregation',
timestamps: false,
underscored: true,
indexes: [
{
fields: ['competition_uid'],
},
{
fields: ['team_uid'],
},
{
fields: ['account_uid'],
},
{
fields: ['audit_status'],
},
],
});
// 关联定义
Aggregation.associate = function() {
app.model.Aggregation.belongsTo(app.model.CompetitionInfo, {
foreignKey: 'competition_uid',
targetKey: 'competition_uid',
as: 'competition',
});
app.model.Aggregation.belongsTo(app.model.Team, {
foreignKey: 'team_uid',
targetKey: 'team_uid',
as: 'team',
});
app.model.Aggregation.belongsTo(app.model.Account, {
foreignKey: 'account_uid',
targetKey: 'uid',
as: 'account',
});
};
return Aggregation;
};