feat: 双端题库统一与 PDP/DISC 结果文案、测评 API 与企测上下文

1、修复了测评/结果页与个人中心展示不一致问题;废弃独立 questions.js,统一使用 questionBank;结果格式与详情解析相关问题。

2、新增了 PdpDiscResultText(PDP+DISC 双类型摘要文案)、抖音 questionBank 与 enterpriseContext;扩展 api/Test 与路由、管理端 Order 与 ExtractsTestResults。

3、优化了 resultFormat 与 questionBank 组织方式、UserDetailDialog;移除不再使用的 mbti_test_results 恢复 SQL/脚本。

Made-with: Cursor
This commit is contained in:
Ghost
2026-03-31 15:26:21 +08:00
parent 3fdf9b6ed2
commit e672ad4ede
48 changed files with 1455 additions and 627 deletions

View File

@@ -1,8 +1,8 @@
/**
* 从服务端拉取启用题库,失败或为空时回落本地 questions.js顺序由 shuffleQuestions 随机
* 从服务端拉取启用题库/api/test/questions无本地题目保底
* enterpriseId未传时与 test/submit 一致,见 enterpriseContext.getEnterpriseIdForApiPayload()
*/
const { requestPromise } = require('./request')
const { shuffleQuestions } = require('./questions')
function getAppSafe() {
try {
@@ -12,7 +12,45 @@ function getAppSafe() {
}
}
/** 与 runtime 一致:>0 时在乱序后截取前 N 题 */
/**
* Fisher-Yates打乱题目顺序并随机每题选项顺序深拷贝
* @param {Array} questions
* @returns {Array}
*/
function shuffleQuestions(questions) {
const arr = (questions || []).map(q => ({
...q,
options: (q.options || []).slice().sort(() => Math.random() - 0.5)
}))
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
;[arr[i], arr[j]] = [arr[j], arr[i]]
}
return arr
}
/**
* @param {{ enterpriseId?: number|null }} opts
* @returns {number|null}
*/
function resolveEnterpriseIdForQuestionBank(opts) {
const o = opts || {}
if (Object.prototype.hasOwnProperty.call(o, 'enterpriseId')) {
const v = o.enterpriseId
if (v == null || v === '') {
return null
}
const n = Number(v)
return Number.isFinite(n) && n > 0 ? n : null
}
try {
const { getEnterpriseIdForApiPayload } = require('./enterpriseContext')
return getEnterpriseIdForApiPayload()
} catch (e) {
return null
}
}
function getTestQuestionDrawCount() {
const app = getAppSafe()
const n = app && app.globalData && app.globalData.testQuestionDrawCount
@@ -60,23 +98,21 @@ function fetchQuestionBank(type, enterpriseId) {
/**
* @param {'mbti'|'disc'|'pdp'} type
* @param {Array} localQuestions
* @param {{ enterpriseId?: number|null }} opts
* @returns {Promise<Array>}
* @returns {Promise<Array>} 乱序后的题目;接口无题或失败则 reject
*/
function loadQuestionsWithFallback(type, localQuestions, opts = {}) {
const { enterpriseId } = opts
return fetchQuestionBank(type, enterpriseId)
.then((list) => {
if (!list.length) {
return applyDrawCountAfterShuffle(shuffleQuestions(localQuestions))
}
return shuffleQuestions(list)
})
.catch(() => applyDrawCountAfterShuffle(shuffleQuestions(localQuestions)))
function loadQuestions(type, opts = {}) {
const enterpriseId = resolveEnterpriseIdForQuestionBank(opts)
return fetchQuestionBank(type, enterpriseId).then((list) => {
if (!list.length) {
throw new Error('暂无启用题目')
}
return applyDrawCountAfterShuffle(shuffleQuestions(list))
})
}
module.exports = {
fetchQuestionBank,
loadQuestionsWithFallback
loadQuestions,
shuffleQuestions
}