Files
competition-website/app/lib/decimal_score.js
qubiaobiao 2ab0991310 fix(admin): 复核页选择题选项渲染修复 + 阅卷导出 Word + 评分两位小数(R28)
针对测试人员反馈的四项:
1) 复核明细「选择题大量空白」:options 为 text 列存 JSON 字符串,原先被原样透传,
   前端 v-for 对字符串逐字符迭代(op.key/op.text 皆 undefined)⇒ 每字符渲染一行。
   新增 parseOptions()(仅 string 才 JSON.parse,失败降级 null)。
2) 选项与答案不随机:仅题目用 RAND() 抽题,normalizeQuestion 无 shuffle,字母无歧义。
3) 评分精度:DECIMAL(6,1) -> DECIMAL(6,2),migration 026 覆盖 17 列(与 025 同范围),
   lib/decimal_score.js 与 11 个 model 注释同步;汇总收敛 round2(×100/100)。
4) 阅卷导出:GET /api/admin/big-answers/:group/export?ids=
   单选考生 -> 直接 .docx;多位/全部 -> 每位考生单独 .docx 打包 .zip。
   路由为 3 段,注册在 :group 通配段之前。

验证:verify_big_question 51 PASS/1 FAIL(唯一 FAIL=测试人员新数据,非本次改动)、
verify_score_leak_all_channels 24/24、verify_question_no_answer_leak 4/3/0/1。
2026-09-28 15:50:46 +08:00

43 lines
1.8 KiB
JavaScript
Raw Permalink 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';
/**
* 分数列类型工厂(2026-09-28:大题人工评分精确到小数点后**两位**)
*
* 用法(在 model 文件内):
* const decimalScore = require('../lib/decimal_score')(app);
* ...
* word_score: decimalScore('word_score', 'Word题/综合大题得分(可含 2 位小数)'),
*
* ⚠️ 三处必须同时成立,小数才不会被截断或变形:
* ① DB 列 = DECIMAL
* → database/migrations/025-scores-decimal-one-place.sql(INT(11) → DECIMAL(6,1))
* → database/migrations/026-scores-decimal-two-places.sql((6,1) → (6,2) ← 现行)
* ② model 声明 = DECIMAL(本文件)
* → 若仍写 INTEGER,Sequelize 读取时会走 INTEGER.parse(parseInt),
* 把 7.5 **静默截成 7**,且不报任何错
* ③ mysql2 驱动配 decimalNumbers=true(config/config.default.js)
* → 否则 DECIMAL 经驱动读出为**字符串**('7.5'),前端 `+` 会变成拼接
*
* getter 再兜底转一次 Number,保证 raw / 非 raw 查询路径都拿到数值类型。
*
* @param {Egg.Application} app Egg 应用实例(用于取 app.Sequelize)
* @returns {(field: string, comment: string, extra?: object) => object}
*/
module.exports = app => {
const { DECIMAL } = app.Sequelize;
return function decimalScore(field, comment, extra = {}) {
return Object.assign({
// 上限 9999.99,足够覆盖总分 / 单题分;两位小数满足阅卷评分精度
// ⚠️ 改这里必须同步 database/migrations/026-scores-decimal-two-places.sql
type: DECIMAL(6, 2),
allowNull: true,
comment,
get() {
const v = this.getDataValue(field);
return (v === null || v === undefined) ? v : Number(v);
},
}, extra);
};
};