'use strict'; /** * 高职组答题记录模型 - GaozhiSubmission * * 存储高职组参赛选手的答题记录,包括答题数据、判分和Word文件上传。 * 表名:gaozhi_submissions */ module.exports = app => { const { STRING, INTEGER, TEXT, BOOLEAN, DATE } = app.Sequelize; // 分数列统一走共享工厂(DECIMAL(6,1) + Number 兜底,见 app/lib/decimal_score.js) const decimalScore = require('../lib/decimal_score')(app); const GaozhiSubmission = app.model.define('gaozhi_submission', { // 主键 ID,自增 id: { type: INTEGER, primaryKey: true, autoIncrement: true, comment: '提交记录唯一标识', }, // 外键:关联聚合报名 ID aggregation_uid: { type: INTEGER, allowNull: false, comment: '关联聚合报名 ID', }, // 外键:关联题目 ID question_uid: { type: INTEGER, allowNull: false, comment: '关联题目 ID', }, // 题型(choice / judge):与 question_uid 联合唯一标识一道题。 // 选择题与判断题的 id 在不同表中可能数值重叠(如 choice#5 与 judge#5), // 仅凭 question_uid 无法区分,必须结合 question_type 存储,否则会折叠丢失答案(见 B11)。 question_type: { type: STRING(16), allowNull: false, defaultValue: '', comment: '题型:choice/judge,与 question_uid 联合区分题目', }, // 答题数据(选手提交的答案) answer_data: { type: TEXT, allowNull: true, defaultValue: null, comment: '答题数据', }, // 是否判为正确 is_correct: { type: BOOLEAN, allowNull: true, defaultValue: null, comment: '是否判为正确', }, // 得分 score: decimalScore('score', '得分(可含 1 位小数)', { defaultValue: null }), // Word 文件存储路径 word_file_path: { type: STRING(500), allowNull: true, defaultValue: null, comment: 'Word 文件存储路径', }, // Word 文件原始名称 word_file_name: { type: STRING(200), allowNull: true, defaultValue: null, comment: 'Word 文件原始名称', }, // Word 文件 MD5 word_file_md5: { type: STRING(32), allowNull: true, defaultValue: null, comment: 'Word 文件 MD5', }, // 记录创建时间 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: 'gaozhi_submissions', timestamps: false, underscored: true, indexes: [ { fields: ['aggregation_uid'], }, { fields: ['question_uid'], }, { // 唯一约束:同一选手同一题(题型+题号)只保留一行,杜绝并发作答重复落库(B12)。 unique: true, name: 'uk_gaozhi_submission', fields: ['aggregation_uid', 'question_uid', 'question_type'], }, ], }); // 关联定义 GaozhiSubmission.associate = function() { app.model.GaozhiSubmission.belongsTo(app.model.Aggregation, { foreignKey: 'aggregation_uid', targetKey: 'aggregation_uid', as: 'aggregation', }); app.model.GaozhiSubmission.belongsTo(app.model.GaozhiQuestion, { foreignKey: 'question_uid', targetKey: 'question_uid', as: 'gaozhiQuestion', }); }; return GaozhiSubmission; };