2026-09-23 18:29:50 +08:00
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-09-28 15:50:46 +08:00
|
|
|
|
* 分数列类型工厂(2026-09-28:大题人工评分精确到小数点后**两位**)
|
2026-09-23 18:29:50 +08:00
|
|
|
|
*
|
|
|
|
|
|
* 用法(在 model 文件内):
|
|
|
|
|
|
* const decimalScore = require('../lib/decimal_score')(app);
|
|
|
|
|
|
* ...
|
2026-09-28 15:50:46 +08:00
|
|
|
|
* word_score: decimalScore('word_score', 'Word题/综合大题得分(可含 2 位小数)'),
|
2026-09-23 18:29:50 +08:00
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 三处必须同时成立,小数才不会被截断或变形:
|
|
|
|
|
|
* ① DB 列 = DECIMAL
|
2026-09-28 15:50:46 +08:00
|
|
|
|
* → 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) ← 现行)
|
2026-09-23 18:29:50 +08:00
|
|
|
|
* ② 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({
|
2026-09-28 15:50:46 +08:00
|
|
|
|
// 上限 9999.99,足够覆盖总分 / 单题分;两位小数满足阅卷评分精度
|
|
|
|
|
|
// ⚠️ 改这里必须同步 database/migrations/026-scores-decimal-two-places.sql
|
|
|
|
|
|
type: DECIMAL(6, 2),
|
2026-09-23 18:29:50 +08:00
|
|
|
|
allowNull: true,
|
|
|
|
|
|
comment,
|
|
|
|
|
|
get() {
|
|
|
|
|
|
const v = this.getDataValue(field);
|
|
|
|
|
|
return (v === null || v === undefined) ? v : Number(v);
|
|
|
|
|
|
},
|
|
|
|
|
|
}, extra);
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|