128 lines
4.4 KiB
JavaScript
128 lines
4.4 KiB
JavaScript
|
|
'use strict';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 024 - 综合大题作答表 big_question_answers
|
|||
|
|
*
|
|||
|
|
* 背景(2026-09-21 需求变更)
|
|||
|
|
* 中职组 / 高职组取消 Word 上传题,改为随机抽取一道大题、在页面内直接作答三小问。
|
|||
|
|
*
|
|||
|
|
* 设计要点
|
|||
|
|
* 1. **一考生一行**:UNIQUE(aggregation_uid) —— 满足「一个考生一行数据保存」的目标,
|
|||
|
|
* 且与题量配置解耦(客观题题量由 competition_times.choice_count/judge_count 配置,
|
|||
|
|
* 属逐题表 zhongzhi/gaozhi_submissions,与本表互不干扰)。
|
|||
|
|
* 2. **题干快照 question_snapshot**:抽题那一刻把题干(标题/描述/三小问/分值)序列化落库,
|
|||
|
|
* 题目后续被管理员修改也不影响存证 → 防考生纠纷。
|
|||
|
|
* 3. **不存储每题一列**:客观题 50+20=70 题且题量可配,逐题建列会导致配置每变更一次
|
|||
|
|
* 就要 ALTER TABLE(反扩展性);大题固定 3 小问,故 answer_1/2/3 列式存储是安全的。
|
|||
|
|
*
|
|||
|
|
* 隔离原则
|
|||
|
|
* 新增隔离表,zhongzhi_submissions / gaozhi_submissions 零改动、零迁移。
|
|||
|
|
*
|
|||
|
|
* 环境说明
|
|||
|
|
* MariaDB 5.5.68:无 JSON 列类型(快照用 MEDIUMTEXT 存 JSON 文本);
|
|||
|
|
* DATETIME 不支持 DEFAULT CURRENT_TIMESTAMP,时间戳交给应用层写入。
|
|||
|
|
*/
|
|||
|
|
module.exports = {
|
|||
|
|
up: async (queryInterface, Sequelize) => {
|
|||
|
|
await queryInterface.createTable('big_question_answers', {
|
|||
|
|
id: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
primaryKey: true,
|
|||
|
|
autoIncrement: true,
|
|||
|
|
allowNull: false,
|
|||
|
|
comment: '主键ID',
|
|||
|
|
},
|
|||
|
|
aggregation_uid: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
allowNull: false,
|
|||
|
|
comment: '聚合报名ID(中职/高职组 == contestants.id),唯一 → 一考生一行',
|
|||
|
|
},
|
|||
|
|
contestant_id: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '选手ID(冗余,便于管理端查证与排障)',
|
|||
|
|
},
|
|||
|
|
group: {
|
|||
|
|
type: Sequelize.STRING(20),
|
|||
|
|
allowNull: false,
|
|||
|
|
comment: '组别:zhongzhi/gaozhi',
|
|||
|
|
},
|
|||
|
|
big_question_id: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '抽中的大题ID',
|
|||
|
|
},
|
|||
|
|
big_question_uid: {
|
|||
|
|
type: Sequelize.STRING(64),
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '抽中的大题稳定标识',
|
|||
|
|
},
|
|||
|
|
question_snapshot: {
|
|||
|
|
type: Sequelize.TEXT('medium'),
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '抽题时刻的题干快照 JSON(防纠纷存证)',
|
|||
|
|
},
|
|||
|
|
answer_1: {
|
|||
|
|
type: Sequelize.TEXT,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '第1小问作答(上限 2000 字,后端同步校验)',
|
|||
|
|
},
|
|||
|
|
answer_2: {
|
|||
|
|
type: Sequelize.TEXT,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '第2小问作答(上限 2000 字)',
|
|||
|
|
},
|
|||
|
|
answer_3: {
|
|||
|
|
type: Sequelize.TEXT,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '第3小问作答(上限 2000 字)',
|
|||
|
|
},
|
|||
|
|
score_1: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '第1小问得分(0-10,人工阅卷)',
|
|||
|
|
},
|
|||
|
|
score_2: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '第2小问得分(0-10,人工阅卷)',
|
|||
|
|
},
|
|||
|
|
score_3: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '第3小问得分(0-10,人工阅卷)',
|
|||
|
|
},
|
|||
|
|
total_score: {
|
|||
|
|
type: Sequelize.INTEGER,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '三小问得分合计(阅卷后回写 contestants.word_score 取数依据)',
|
|||
|
|
},
|
|||
|
|
submit_time: {
|
|||
|
|
type: Sequelize.DATE,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '随整卷正式提交写入(占位/未提交为 NULL)',
|
|||
|
|
},
|
|||
|
|
created_at: {
|
|||
|
|
type: Sequelize.DATE,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '创建时间',
|
|||
|
|
},
|
|||
|
|
updated_at: {
|
|||
|
|
type: Sequelize.DATE,
|
|||
|
|
allowNull: true,
|
|||
|
|
comment: '更新时间',
|
|||
|
|
},
|
|||
|
|
}).then(() => {
|
|||
|
|
return Promise.all([
|
|||
|
|
queryInterface.addIndex('big_question_answers', ['aggregation_uid'], { name: 'uk_big_answer_agg', unique: true }),
|
|||
|
|
queryInterface.addIndex('big_question_answers', ['group'], { name: 'idx_big_answer_group' }),
|
|||
|
|
queryInterface.addIndex('big_question_answers', ['big_question_uid'], { name: 'idx_big_answer_q' }),
|
|||
|
|
]);
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
down: async (queryInterface) => {
|
|||
|
|
await queryInterface.dropTable('big_question_answers');
|
|||
|
|
},
|
|||
|
|
};
|