/** * 主观题任务服务模块 * 负责任务详情和进度相关的 API 调用 */ import { campApi } from '../../../config/camp_api.js'; /** * 静默获取用户任务进度(避免全局 request 的业务错误弹窗) * @param {String} userId - 用户ID * @param {String} taskId - 任务ID * @returns {Promise} 任务进度 */ export function fetchProgressSilent(userId, taskId) { // 使用 Fiber 后端的接口 return campApi.getProgressDetail(userId, taskId).then(function(res) { // 统一返回格式 if (res && res.success === true) { return res; } else if (res && res.code === 200) { return { success: true, progress: res.data || res.progress }; } return res; }).catch(function(err) { // 静默失败,返回 null console.log('获取进度失败:', err); return null; }); } /** * 从任务 condition 解析是否需要审核(与后端一致:根级 need_review 或 subjective.need_review) * @param {Object} condition - task.condition * @returns {Boolean} */ function parseNeedReview(condition) { if (!condition || typeof condition !== 'object') return false; if (condition.need_review === true) return true; var sub = condition.subjective; if (sub && typeof sub === 'object' && sub.need_review === true) return true; return false; } /** 将后端数字 review_status (0=pending, 1=approved, 2=rejected) 转为前端字符串 */ function normalizeReviewStatus(val) { if (val === undefined || val === null) return 'NOT_STARTED'; if (typeof val === 'number') { if (val === 0) return 'pending'; if (val === 1) return 'approved'; if (val === 2) return 'rejected'; } return String(val); } /** * 获取任务详情 * @param {String} taskId - 任务ID * @returns {Promise} 任务详情 */ export function getTaskDetail(taskId) { return campApi.getTaskDetailById(taskId).then(function(taskDetail){ console.log('taskDetail', taskDetail,taskId); if (taskDetail && taskDetail.success === true && taskDetail.task) { var task = taskDetail.task; // 接口返回的 content 和 condition 可能为 { subjective: { pdf_url, description, need_review, review_status } } var content = task.content || {}; var condition = task.condition || {}; var subContent = content.subjective || content; var subCondition = condition.subjective || condition; return { pdfUrl: subContent.pdf_url || content.pdf_url || '', description: subContent.description || content.description || '', needReview: parseNeedReview(condition), reviewStatus: normalizeReviewStatus(subCondition.review_status !== undefined && subCondition.review_status !== null ? subCondition.review_status : condition.review_status) }; } else if (taskDetail && taskDetail.code === 200 && taskDetail.data) { var data = taskDetail.data; var condition = data.condition || {}; var content = data.content || {}; var subContent = content.subjective || content; return { pdfUrl: data.pdf_url || subContent.pdf_url || content.pdf_url || '', description: subContent.description || content.description || data.description || '', needReview: parseNeedReview(condition) || !!data.need_review, reviewStatus: normalizeReviewStatus((condition.subjective || condition).review_status) }; } return null; }); } /** * 提交答案 * @param {String} userId - 用户ID * @param {String} taskId - 任务ID * @param {Array} answerImages - 答案图片URL数组 * @returns {Promise} 提交结果 */ export function submitAnswer(userId, taskId, answerImages) { const formatDateTimeString = (date) => { var d = date || new Date(); var year = d.getFullYear(); var month = String(d.getMonth() + 1).padStart(2, '0'); var day = String(d.getDate()).padStart(2, '0'); var hours = String(d.getHours()).padStart(2, '0'); var minutes = String(d.getMinutes()).padStart(2, '0'); var seconds = String(d.getSeconds()).padStart(2, '0'); return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds; }; var submitData = { user_id: String(userId), task_id: String(taskId), is_completed: true, completed_at: formatDateTimeString(new Date()), answer_images: answerImages }; return campApi.updateCampProgress(submitData); }