- 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)
72 lines
2.4 KiB
JavaScript
72 lines
2.4 KiB
JavaScript
'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;
|
||
};
|