import * as taskService from './modules/task-service.js'; import * as imageHandler from './modules/image-handler.js'; import { campApi } from '../../config/camp_api.js'; // 兼容:formatDateTime 可能不存在,提供安全封装 function safeFormatDateTime(v) { try { if (typeof formatDateTime === 'function') return formatDateTime(v); } catch (_) { } return v || ''; } // 格式化日期为 YYYY-MM-DD HH:mm:ss 格式 function 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; } import { formatDateTime } from '../../utils/util'; var app = getApp(); Page({ data: { pdfUrl: '', description: '', fileName: '主观题试卷.pdf', loading: true, needReview: false, reviewStatus: 'NOT_STARTED', reviewTime: '', reviewComment: '', reviewImages: [], submittedImages: [], hasSubmitted: false, allowResubmit: false, tempImages: [], taskId: null, showPdfActionSheet: false, statusText: '', // 状态文本:任务已完成、需要审核、等待审核、审核通过、已驳回 statusClass: '' // 状态样式类名 }, onLoad: function (options) { var that = this; // 从 URL 参数中获取数据 var campId = options.campId || ''; var courseId = options.courseId || ''; var taskId = options.taskId || ''; var taskTitle = options.taskTitle ? decodeURIComponent(options.taskTitle) : '主观题'; if (!taskId) { wx.showToast({ title: '任务ID不存在', icon: 'none' }); return; } wx.setNavigationBarTitle({ title: taskTitle }); that.setData({ campId: String(campId), courseId: String(courseId), taskId: String(taskId) }); that.getTaskDetail(); }, getTaskDetail: function () { var that = this; var taskId = this.data.taskId; taskService.getTaskDetail(taskId).then(function (taskData) { console.log('taskData', taskData,taskId); if (taskData) { var needReview = taskData.needReview || false; // 初始状态:还没有进度信息,根据 needReview 计算状态文本 var statusInfo = that.computeStatusText(needReview, 'NOT_STARTED', false); that.setData({ pdfUrl: taskData.pdfUrl, description: taskData.description || '', needReview: needReview, reviewStatus: taskData.reviewStatus, loading: false, statusText: statusInfo.text, statusClass: statusInfo.class }); } }).finally(function () { var userId = wx.getStorageSync('wxuserid'); if (userId && taskId) { taskService.fetchProgressSilent(userId, taskId) .then(function (progressRes) { var progress = null; if (progressRes && progressRes.success === true && progressRes.progress) { progress = progressRes.progress; } else if (progressRes && progressRes.code === 200 && progressRes.data) { progress = progressRes.data; } if (progress) { var hasImgs = Array.isArray(progress.answer_images) && progress.answer_images.length > 0; var done = hasImgs || progress.is_completed === true || progress.is_completed === 1; if (done) { that.setData({ hasSubmitted: true }); } that.handleTaskDetail(progress); } else { // 没有进度信息,根据 needReview 计算状态文本 var needReview = that.data.needReview; var statusInfo = that.computeStatusText(needReview, 'NOT_STARTED', false); that.setData({ hasSubmitted: false, submittedImages: [], reviewImages: [], reviewStatus: 'NOT_STARTED', reviewTime: '', statusText: statusInfo.text, statusClass: statusInfo.class }); } }) .catch(function () { // 获取进度失败,根据 needReview 计算状态文本 var needReview = that.data.needReview; var statusInfo = that.computeStatusText(needReview, 'NOT_STARTED', false); that.setData({ hasSubmitted: false, submittedImages: [], reviewImages: [], reviewStatus: 'NOT_STARTED', reviewTime: '', statusText: statusInfo.text, statusClass: statusInfo.class }); }); } }); }, /** * 计算状态文本和样式类 * @param {Boolean} needReview - 是否需要审核 * @param {String} reviewStatus - 审核状态 * @param {Boolean} hasProgress - 是否有进度信息 * @returns {Object} {text: String, class: String} */ computeStatusText: function (needReview, reviewStatus, hasProgress) { var statusText = ''; var statusClass = ''; if (!needReview) { // 不需要审核 if (hasProgress) { statusText = '任务已完成'; statusClass = 'no-audit'; } else { statusText = '不需要审核'; statusClass = 'no-audit'; } } else { // 需要审核 if (!hasProgress) { // 没有进度信息 statusText = '需要审核'; statusClass = 'need-audit'; } else { // 有进度信息,根据审核状态判断 var normalizedStatus = String(reviewStatus || '').toLowerCase(); if (normalizedStatus === 'approved' || normalizedStatus === 'review_status_approved') { statusText = '审核通过'; statusClass = 'approved'; } else if (normalizedStatus === 'rejected' || normalizedStatus === 'review_status_rejected') { statusText = '已驳回'; statusClass = 'need-audit'; } else if (normalizedStatus === 'pending' || normalizedStatus === 'review_status_pending') { statusText = '等待审核'; statusClass = 'need-audit'; } else { statusText = '需要审核'; statusClass = 'need-audit'; } } } return { text: statusText, class: statusClass }; }, handleTaskDetail: function (data) { var that = this; try { // 解析已提交的图片(优先使用 answer_images 数组) var submittedImages = []; if (Array.isArray(data.answer_images)) { submittedImages = data.answer_images; } else if (typeof data.images === 'string') { try { submittedImages = JSON.parse(data.images) || []; } catch (_) { submittedImages = []; } } // 解析批复图片:可能是数组、JSON 字符串或空对象 var reviewImages = []; if (Array.isArray(data.review_images)) { reviewImages = data.review_images; } else if (typeof data.review_images === 'string') { try { reviewImages = JSON.parse(data.review_images) || []; } catch (_) { reviewImages = []; } } // 格式化时间(安全封装) var reviewTime = safeFormatDateTime(data.review_time) // 更新 needReview(如果后端返回了该字段,优先使用后端返回的值) var currentNeedReview = that.data.needReview; if (data.need_review !== undefined) { currentNeedReview = !!data.need_review; } var hasProgress = true; // 有进度数据 var reviewStatus = data.review_status || 'NOT_STARTED'; // 计算状态文本 var statusInfo = that.computeStatusText(currentNeedReview, reviewStatus, hasProgress); var updateData = { submittedImages: submittedImages, hasSubmitted: (submittedImages.length > 0) || (data.is_completed === true || data.is_completed === 1), reviewStatus: reviewStatus, reviewTime: reviewTime, reviewComment: data.review_comment || '', reviewImages: reviewImages, tempImages: [], statusText: statusInfo.text, statusClass: statusInfo.class }; // 如果后端返回了 need_review 字段,使用后端返回的值(更准确) if (data.need_review !== undefined) { updateData.needReview = !!data.need_review; } this.setData(updateData); console.log("reviewStatus", this.data.reviewStatus); console.log("needReview", this.data.needReview); console.log("statusText", this.data.statusText); } catch (error) { console.error('处理数据失败:', error); } }, chooseImage: function () { var that = this; var currentCount = this.data.tempImages.length; imageHandler.chooseImage(6, currentCount).then(function (newImages) { var tempImages = that.data.tempImages.concat(newImages); that.setData({ tempImages: tempImages }); }).catch(function (err) { console.error('选择图片失败:', err); }); }, deleteImage: function (e) { var index = e.currentTarget.dataset.index; var tempImages = this.data.tempImages.slice(); tempImages.splice(index, 1); this.setData({ tempImages: tempImages }); }, previewImage: function (e) { var url = e.currentTarget.dataset.url; var images = this.data.tempImages.length > 0 ? this.data.tempImages : this.data.submittedImages; imageHandler.previewImage(url, images); }, previewFeedbackImage: function (e) { var current = e.currentTarget.dataset.url; wx.previewImage({ current: current, urls: this.data.feedbackImages }); }, uploadImage: function (tempFilePath) { return imageHandler.uploadImage(tempFilePath, this.data.taskId, 'subjective'); }, submitAnswer: function () { var that = this; if (this.data.tempImages.length === 0) { wx.showToast({ title: '请上传答案图片', icon: 'none' }); return; } wx.showLoading({ title: '提交中...', mask: true }); var uploadedUrls = []; var uploadPromises = this.data.tempImages.map(function (tempPath) { return that.uploadImage(tempPath).then(function (imageUrl) { uploadedUrls.push(imageUrl); }); }); Promise.all(uploadPromises) .then(function () { var userId = String(wx.getStorageSync('wxuserid') || ''); var taskIdStr = String(that.data.taskId); return taskService.submitAnswer(userId, taskIdStr, uploadedUrls); }) .then(function (result) { if ((result && result.code === 200) || (result && result.success === true)) { wx.showToast({ title: '提交成功', icon: 'success' }); // 如果不需要审核,直接标记为完成(审核通过) // 需要审核:设置为 pending(等待审核) // 不需要审核:设置为 approved(审核通过,任务完成) // 注意:后端返回的格式是小写(pending, approved, rejected) var newReviewStatus = that.data.needReview ? 'pending' : 'approved'; // 计算状态文本(提交后有进度信息) var statusInfo = that.computeStatusText(that.data.needReview, newReviewStatus, true); that.setData({ hasSubmitted: true, submittedImages: uploadedUrls, tempImages: [], reviewStatus: newReviewStatus, statusText: statusInfo.text, statusClass: statusInfo.class }); // 如果不需要审核,重新获取进度信息以确保状态同步 // 后端应该已经将任务标记为完成,重新获取以确认 if (!that.data.needReview) { var userId = wx.getStorageSync('wxuserid'); if (userId && that.data.taskId) { // 延迟一小段时间,确保后端已更新 setTimeout(function () { taskService.fetchProgressSilent(userId, that.data.taskId) .then(function (progressRes) { var progress = null; if (progressRes && progressRes.success === true && progressRes.progress) { progress = progressRes.progress; } else if (progressRes && progressRes.code === 200 && progressRes.data) { progress = progressRes.data; } if (progress) { // 更新状态,确保与后端同步 that.handleTaskDetail(progress); // 如果后端返回的状态是已完成且不需要审核,确保 reviewStatus 为 approved if ((progress.is_completed === true || progress.is_completed === 1) && !that.data.needReview) { that.setData({ reviewStatus: 'approved' }); } } }) .catch(function (err) { console.log('获取进度信息失败:', err); }); }, 500); } } } else { throw new Error((result && (result.message || result.msg)) || '提交失败'); } }) .catch(function (error) { console.error('提交失败:', error); wx.showToast({ title: error.message || '提交失败,请重试', icon: 'none' }); }) .finally(function () { wx.hideLoading(); }); }, handlePdfTap: function () { if (!this.data.pdfUrl) { wx.showToast({ title: 'PDF文件不存在', icon: 'none' }); return; } wx.showActionSheet({ itemList: ['预览文件', '直接下载', '分享文件'], success: (res) => { var that = this; if (res.tapIndex === 0) { // 预览文件 wx.downloadFile({ url: that.data.pdfUrl, success: function (res) { if (res.statusCode === 200) { wx.openDocument({ filePath: res.tempFilePath, success: function () { console.log('打开文档成功'); }, fail: function (error) { console.error('打开文档失败:', error); wx.showToast({ title: '打开文档失败', icon: 'none' }); } }); } }, fail: function (error) { console.error('下载文件失败:', error); wx.showToast({ title: '下载文件失败', icon: 'none' }); } }); } else if (res.tapIndex === 1) { // 直接下载 wx.downloadFile({ url: that.data.pdfUrl, success: function (res) { if (res.statusCode === 200) { var fs = wx.getFileSystemManager(); fs.saveFile({ tempFilePath: res.tempFilePath, success: function () { wx.showToast({ title: '已保存到本地', icon: 'success' }); }, fail: function (err) { console.error('保存失败:', err); wx.showToast({ title: '保存失败', icon: 'none' }); } }); } }, fail: function (error) { console.error('下载文件失败:', error); wx.showToast({ title: '下载文件失败', icon: 'none' }); } }); } else if (res.tapIndex === 2) { // 分享文件 wx.downloadFile({ url: that.data.pdfUrl, success: function (res) { if (res.statusCode === 200) { wx.shareFileMessage({ fileName: that.data.fileName, filePath: res.tempFilePath, success: () => { console.log('分享文件成功'); }, fail: (error) => { console.error('分享文件失败:', error); wx.showToast({ title: '分享文件失败', icon: 'none' }); } }); } }, fail: (error) => { console.error('下载文件失败:', error); wx.showToast({ title: '下载文件失败', icon: 'none' }); } }); } } }); }, handleResubmit() { console.log('handleResubmit') this.setData({ tempImages: [], allowResubmit: true, hasSubmitted: false, submittedImages: [] }); }, previewReviewImage: function (e) { const { url } = e.currentTarget.dataset; const reviewImages = this.data.reviewImages; if (!reviewImages || reviewImages.length === 0) { console.error('找不到老师批复的图片'); return; } wx.previewImage({ urls: reviewImages, current: url, success: () => { console.log('预览成功'); }, fail: (err) => { console.error('预览失败:', err); } }); }, onShareAppMessage: function () { const fileName = this.data.fileName || '主观题试卷.pdf'; return { title: fileName, path: `/pages/camp_task_subjective_question/index?campId=${this.data.campId}&courseId=${this.data.courseId}&taskId=${this.data.taskId}`, imageUrl: this.data.pdfUrl } }, onShareTimeline: function () { const fileName = this.data.fileName || '主观题试卷.pdf'; return { title: fileName, query: `campId=${this.data.campId}&courseId=${this.data.courseId}&taskId=${this.data.taskId}`, imageUrl: this.data.pdfUrl } } });