Files
competition-website/app/model/competitionInfo.js
qubiaobiao 459f1adf6d feat(admin): R176-R180 公示表与新闻撤回 + 管理端多管理员权限(C 层)+ 交卷冻结
- R176 成绩公示表引擎(lib/publicitySheet.js + lib/assets/publicity-template.xlsx 官方模板基底)
  与指导教师回填(lib/teacherBackfill.js);赛项名称/编号改为配置项
- R177 新闻「发布 ↔ 撤回」互斥:撤回只置 is_draft=1,不删除数据
- R178 C 层 RBAC:lib/adminPermissions.js(13 权限点 / 70 条路由规则,唯一 SoT)
  + middleware/auth.js 三段判定(默认拒绝 · is_super 单点 · token_version)
  + controller/service/adminUser.js + lib/auditLog.js + model/adminAuditLog.js
- R178 B1 交卷冻结:service.exam.assertNotSubmitted(bizCode 4006 单一判据源)
- R178 B④ 提交口径拆分:formalSubmitted / submitted / answeredCount 三字段
- R178 成绩总览补小组编号:resolveTeamLabels(与选手管理同源,含兜底与三态)
- R181 生产迁移配套:admins +7 列、admin_audit_logs(scripts/migrate_r178_admin_rbac.py)
2026-10-20 11:06:29 +08:00

72 lines
2.4 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';
/**
* 竞赛信息模型 - CompetitionInfo
*
* 表名:competition_info
*
* 🔴 2026-10-19(R176)修正:原模型声明的是三列结构
* (`competition_uid` / `competition_name` / `competition_code`),
* 但**运行库实际是 key-value 结构**:
* `id` / `info_key` / `info_value` / `created_at` / `updated_at`(实测 SHOW CREATE TABLE)
* 模型与表不一致的后果:
* ① `findOne()` 默认按模型声明选列 ⇒ `Unknown column 'competition_uid'` 直接 500;
* ② `create()` 会带上 `competition_name`(allowNull:false)⇒ 必然失败。
* 旧代码之所以没暴露,是因为唯一的使用点(导入时取 competition_uid)
* 包在 try/catch 里,失败后静默回落到默认值 1 —— 而 `info_key='competition_uid'`
* 的值恰好也是 1,所以"看起来一直是对的"。
*
* ⚠️ 因此本表**不能按列访问**,必须走 `info_key` 取值。
* 公示表要用的两个键是 `competition_item_name` / `competition_item_code`。
*/
module.exports = app => {
const { STRING, INTEGER, TEXT, DATE } = app.Sequelize;
const CompetitionInfo = app.model.define('competition_info', {
// 主键,自增(运行库真实主键是 id,不是 competition_uid)
id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true,
comment: '自增主键',
},
// 配置键名(如 competition_name / competition_code / competition_item_name)
// ⚠️ 运行库**没有**给 info_key 建唯一索引 ⇒ 写侧必须"先查再写",不能依赖 upsert
info_key: {
type: STRING(50),
allowNull: false,
comment: '配置键',
},
// 配置值(统一按字符串存,数字也以文本形式落库)
info_value: {
type: TEXT,
allowNull: true,
comment: '配置值',
},
created_at: {
type: DATE,
allowNull: true,
comment: '创建时间',
},
updated_at: {
type: DATE,
allowNull: true,
comment: '更新时间',
},
}, {
tableName: 'competition_info',
timestamps: false,
underscored: true,
// 索引仅作 Sequelize 元数据声明(sync 时用);⛔ 本项目的表由 SQL 手工维护,
// 不要指望这里加 unique 会同步到运行库
indexes: [
{
fields: ['info_key'],
},
],
});
return CompetitionInfo;
};