// pages/judge/review.js
|
const app = getApp()
|
const { graphqlRequest, formatDate } = require('../../lib/utils')
|
|
Page({
|
data: {
|
loading: false,
|
submitting: false,
|
|
// 提交作品信息
|
submission: null,
|
submissionId: '',
|
|
// 活动信息
|
activity: null,
|
|
// 评审标准
|
criteria: [],
|
|
// 评分数据
|
scores: {},
|
|
// 评审意见
|
comment: '',
|
|
// 总分
|
totalScore: 0,
|
maxScore: 0,
|
|
// 评审状态
|
reviewStatus: 'PENDING', // PENDING, COMPLETED
|
|
// 已有评审记录
|
existingReview: null,
|
|
// 媒体预览
|
showMediaPreview: false,
|
currentMedia: null,
|
mediaType: 'image',
|
|
// 文件下载
|
downloadingFiles: [],
|
|
// 评分等级
|
scoreOptions: [
|
{ value: 1, label: '1分 - 很差' },
|
{ value: 2, label: '2分 - 较差' },
|
{ value: 3, label: '3分 - 一般' },
|
{ value: 4, label: '4分 - 良好' },
|
{ value: 5, label: '5分 - 优秀' }
|
]
|
},
|
|
onLoad(options) {
|
if (options.id) {
|
this.setData({ submissionId: options.id })
|
this.loadSubmissionDetail()
|
}
|
},
|
|
onShow() {
|
// 页面显示时检查评审状态
|
if (this.data.submissionId) {
|
this.checkReviewStatus()
|
}
|
},
|
|
// 加载提交作品详情
|
async loadSubmissionDetail() {
|
try {
|
this.setData({ loading: true })
|
|
const query = `
|
query GetSubmissionDetail($id: ID!) {
|
submission(id: $id) {
|
id
|
title
|
description
|
files {
|
id
|
name
|
url
|
type
|
size
|
}
|
images
|
videos
|
submittedAt
|
status
|
participant {
|
id
|
name
|
school
|
major
|
avatar
|
}
|
team {
|
id
|
name
|
members {
|
id
|
name
|
role
|
}
|
}
|
activity {
|
id
|
title
|
description
|
judgeCriteria {
|
id
|
name
|
description
|
maxScore
|
weight
|
}
|
}
|
myReview {
|
id
|
scores
|
comment
|
totalScore
|
status
|
reviewedAt
|
}
|
}
|
}
|
`
|
|
const result = await graphqlRequest(query, { id: this.data.submissionId })
|
|
if (result && result.submission) {
|
const submission = result.submission
|
|
// 为每个文件添加下载状态
|
if (submission.files) {
|
submission.files = submission.files.map(file => ({
|
...file,
|
isDownloading: this.data.downloadingFiles.indexOf(file.id) > -1
|
}))
|
}
|
|
// 初始化评分数据
|
const scores = {}
|
let maxScore = 0
|
|
if (submission.activity.judgeCriteria) {
|
submission.activity.judgeCriteria.forEach(criterion => {
|
scores[criterion.id] = submission.myReview ?
|
submission.myReview.scores[criterion.id] || 0 : 0
|
maxScore += criterion.maxScore
|
})
|
}
|
|
this.setData({
|
submission,
|
activity: submission.activity,
|
criteria: submission.activity.judgeCriteria || [],
|
scores,
|
maxScore,
|
existingReview: submission.myReview,
|
reviewStatus: submission.myReview ? submission.myReview.status : 'PENDING',
|
comment: submission.myReview ? submission.myReview.comment : ''
|
})
|
|
this.calculateTotalScore()
|
}
|
} catch (error) {
|
console.error('加载作品详情失败:', error)
|
wx.showToast({
|
title: '加载失败',
|
icon: 'error'
|
})
|
} finally {
|
this.setData({ loading: false })
|
}
|
},
|
|
// 检查评审状态
|
async checkReviewStatus() {
|
try {
|
const query = `
|
query CheckReviewStatus($submissionId: ID!) {
|
reviewStatus(submissionId: $submissionId) {
|
status
|
canReview
|
deadline
|
}
|
}
|
`
|
|
const result = await graphqlRequest(query, { submissionId: this.data.submissionId })
|
|
if (result && result.reviewStatus) {
|
const { status, canReview, deadline } = result.reviewStatus
|
|
if (!canReview) {
|
wx.showModal({
|
title: '无法评审',
|
content: deadline ? `评审已截止(截止时间:${formatDate(deadline)})` : '当前无法进行评审',
|
showCancel: false,
|
success: () => {
|
wx.navigateBack()
|
}
|
})
|
}
|
}
|
} catch (error) {
|
console.error('检查评审状态失败:', error)
|
}
|
},
|
|
// 评分改变
|
onScoreChange(e) {
|
const { criterionId } = e.currentTarget.dataset
|
const { value } = e.detail
|
|
this.setData({
|
[`scores.${criterionId}`]: parseInt(value)
|
})
|
|
this.calculateTotalScore()
|
},
|
|
// 计算总分
|
calculateTotalScore() {
|
const { scores, criteria } = this.data
|
let totalScore = 0
|
|
criteria.forEach(criterion => {
|
const score = scores[criterion.id] || 0
|
totalScore += score * (criterion.weight || 1)
|
})
|
|
this.setData({ totalScore })
|
},
|
|
// 评审意见输入
|
onCommentInput(e) {
|
this.setData({
|
comment: e.detail.value
|
})
|
},
|
|
// 媒体点击
|
onMediaTap(e) {
|
const { url, type } = e.currentTarget.dataset
|
|
if (type === 'image') {
|
wx.previewImage({
|
current: url,
|
urls: this.data.submission.images || []
|
})
|
} else if (type === 'video') {
|
this.setData({
|
showMediaPreview: true,
|
currentMedia: url,
|
mediaType: 'video'
|
})
|
}
|
},
|
|
// 关闭媒体预览
|
onCloseMediaPreview() {
|
this.setData({
|
showMediaPreview: false,
|
currentMedia: null
|
})
|
},
|
|
// 下载文件
|
async onDownloadFile(e) {
|
const { fileId, fileName, fileUrl } = e.currentTarget.dataset
|
|
try {
|
// 添加到下载中列表
|
const downloadingFiles = [...this.data.downloadingFiles, fileId]
|
|
// 同时更新文件的isDownloading字段
|
const submission = { ...this.data.submission }
|
if (submission.files) {
|
submission.files = submission.files.map(file => ({
|
...file,
|
isDownloading: file.id === fileId ? true : file.isDownloading
|
}))
|
}
|
|
this.setData({
|
downloadingFiles,
|
submission
|
})
|
|
wx.showLoading({ title: '下载中...' })
|
|
const result = await wx.downloadFile({
|
url: fileUrl,
|
success: (res) => {
|
if (res.statusCode === 200) {
|
// 保存到相册或文件
|
wx.saveFile({
|
tempFilePath: res.tempFilePath,
|
success: () => {
|
wx.showToast({
|
title: '下载成功',
|
icon: 'success'
|
})
|
},
|
fail: () => {
|
wx.showToast({
|
title: '保存失败',
|
icon: 'error'
|
})
|
}
|
})
|
}
|
},
|
fail: () => {
|
wx.showToast({
|
title: '下载失败',
|
icon: 'error'
|
})
|
}
|
})
|
} catch (error) {
|
console.error('下载文件失败:', error)
|
wx.showToast({
|
title: '下载失败',
|
icon: 'error'
|
})
|
} finally {
|
// 从下载中列表移除
|
const downloadingFiles = this.data.downloadingFiles.filter(id => id !== fileId)
|
|
// 同时更新文件的isDownloading字段
|
const submission = { ...this.data.submission }
|
if (submission.files) {
|
submission.files = submission.files.map(file => ({
|
...file,
|
isDownloading: file.id === fileId ? false : file.isDownloading
|
}))
|
}
|
|
this.setData({
|
downloadingFiles,
|
submission
|
})
|
wx.hideLoading()
|
}
|
},
|
|
// 验证评审数据
|
validateReview() {
|
const { scores, criteria, comment } = this.data
|
|
// 检查是否所有标准都已评分
|
for (let criterion of criteria) {
|
if (!scores[criterion.id] || scores[criterion.id] === 0) {
|
wx.showToast({
|
title: `请为"${criterion.name}"评分`,
|
icon: 'error'
|
})
|
return false
|
}
|
}
|
|
// 检查评审意见
|
if (!comment.trim()) {
|
wx.showToast({
|
title: '请填写评审意见',
|
icon: 'error'
|
})
|
return false
|
}
|
|
if (comment.trim().length < 10) {
|
wx.showToast({
|
title: '评审意见至少10个字符',
|
icon: 'error'
|
})
|
return false
|
}
|
|
return true
|
},
|
|
// 保存草稿
|
async onSaveDraft() {
|
try {
|
wx.showLoading({ title: '保存中...' })
|
|
const { submissionId, scores, comment, totalScore } = this.data
|
|
const mutation = `
|
mutation SaveReviewDraft($input: ReviewDraftInput!) {
|
saveReviewDraft(input: $input) {
|
success
|
review {
|
id
|
status
|
}
|
}
|
}
|
`
|
|
const input = {
|
submissionId,
|
scores,
|
comment: comment.trim(),
|
totalScore
|
}
|
|
const result = await graphqlRequest(mutation, { input })
|
|
if (result && result.saveReviewDraft.success) {
|
wx.showToast({
|
title: '草稿已保存',
|
icon: 'success'
|
})
|
}
|
} catch (error) {
|
console.error('保存草稿失败:', error)
|
wx.showToast({
|
title: '保存失败',
|
icon: 'error'
|
})
|
} finally {
|
wx.hideLoading()
|
}
|
},
|
|
// 提交评审
|
async onSubmitReview() {
|
if (!this.validateReview()) {
|
return
|
}
|
|
wx.showModal({
|
title: '确认提交',
|
content: '评审提交后将无法修改,确定要提交吗?',
|
success: async (res) => {
|
if (res.confirm) {
|
await this.submitReview()
|
}
|
}
|
})
|
},
|
|
// 执行提交评审
|
async submitReview() {
|
try {
|
this.setData({ submitting: true })
|
wx.showLoading({ title: '提交中...' })
|
|
const { submissionId, scores, comment, totalScore } = this.data
|
|
const mutation = `
|
mutation SubmitReview($input: ReviewSubmitInput!) {
|
submitReview(input: $input) {
|
success
|
review {
|
id
|
status
|
reviewedAt
|
}
|
}
|
}
|
`
|
|
const input = {
|
submissionId,
|
scores,
|
comment: comment.trim(),
|
totalScore
|
}
|
|
const result = await graphqlRequest(mutation, { input })
|
|
if (result && result.submitReview.success) {
|
wx.showToast({
|
title: '评审提交成功',
|
icon: 'success'
|
})
|
|
// 更新状态
|
this.setData({
|
reviewStatus: 'COMPLETED',
|
existingReview: result.submitReview.review
|
})
|
|
// 延迟返回上一页
|
setTimeout(() => {
|
wx.navigateBack()
|
}, 1500)
|
}
|
} catch (error) {
|
console.error('提交评审失败:', error)
|
wx.showToast({
|
title: '提交失败',
|
icon: 'error'
|
})
|
} finally {
|
this.setData({ submitting: false })
|
wx.hideLoading()
|
}
|
},
|
|
// 查看其他评审
|
onViewOtherReviews() {
|
wx.navigateTo({
|
url: `/pages/judge/reviews?submissionId=${this.data.submissionId}`
|
})
|
},
|
|
// 联系参赛者
|
onContactParticipant() {
|
const { submission } = this.data
|
|
if (submission.participant) {
|
wx.showActionSheet({
|
itemList: ['发送消息', '查看详情'],
|
success: (res) => {
|
switch (res.tapIndex) {
|
case 0:
|
// 发送消息功能
|
wx.navigateTo({
|
url: `/pages/chat/chat?userId=${submission.participant.id}`
|
})
|
break
|
case 1:
|
// 查看用户详情
|
wx.navigateTo({
|
url: `/pages/user/profile?userId=${submission.participant.id}`
|
})
|
break
|
}
|
}
|
})
|
}
|
},
|
|
// 获取评分等级文本
|
getScoreLabel(score) {
|
const option = this.data.scoreOptions.find(opt => opt.value === score)
|
return option ? option.label : `${score}分`
|
},
|
|
// 获取文件大小文本
|
getFileSizeText(size) {
|
if (size < 1024) {
|
return `${size}B`
|
} else if (size < 1024 * 1024) {
|
return `${(size / 1024).toFixed(1)}KB`
|
} else {
|
return `${(size / (1024 * 1024)).toFixed(1)}MB`
|
}
|
},
|
|
// 格式化日期
|
formatDate(dateString) {
|
return formatDate(dateString, 'YYYY-MM-DD HH:mm')
|
},
|
|
// 分享页面
|
onShareAppMessage() {
|
return {
|
title: '蓉易创 - 评审作品',
|
path: '/pages/index/index'
|
}
|
}
|
})
|