| | |
| | | // pages/judge/review.js |
| | | const app = getApp() |
| | | const { graphqlRequest, formatDate } = require('../../lib/utils') |
| | | const { graphqlRequest, formatDate: formatDateUtil } = require('../../lib/utils') |
| | | |
| | | Page({ |
| | | data: { |
| | |
| | | |
| | | // 提交作品信息 |
| | | submission: null, |
| | | submissionId: '', |
| | | |
| | | activityPlayerId: '', |
| | | stageId: null, |
| | | submissionId: null, |
| | | |
| | | // 活动信息 |
| | | activity: null, |
| | | |
| | | |
| | | // 评审标准 |
| | | criteria: [], |
| | | |
| | | |
| | | // 评分数据 |
| | | scores: {}, |
| | | |
| | |
| | | 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分 - 优秀' } |
| | | ] |
| | | existingReview: null |
| | | }, |
| | | |
| | | onLoad(options) { |
| | | if (options.id) { |
| | | this.setData({ submissionId: options.id }) |
| | | this.setData({ activityPlayerId: options.id }) |
| | | this.loadSubmissionDetail() |
| | | } |
| | | }, |
| | |
| | | } |
| | | }, |
| | | |
| | | transformMediaFile(file) { |
| | | const url = file.fullUrl || file.url |
| | | const thumbUrl = file.fullThumbUrl || url |
| | | const ext = (file.fileExt || '').toLowerCase() |
| | | let mediaType = 'file' |
| | | |
| | | if (file.mediaType === 1 || ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'].includes(ext)) { |
| | | mediaType = 'image' |
| | | } else if (file.mediaType === 2 || ['mp4', 'mov', 'avi', 'wmv', 'mkv', 'webm', 'flv'].includes(ext)) { |
| | | mediaType = 'video' |
| | | } else if (ext === 'pdf') { |
| | | mediaType = 'pdf' |
| | | } else if (['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'wps', 'txt', 'rtf'].includes(ext)) { |
| | | mediaType = 'word' |
| | | } |
| | | |
| | | return { |
| | | id: file.id, |
| | | name: file.name, |
| | | url, |
| | | thumbUrl, |
| | | mediaType, |
| | | size: file.fileSize || 0 |
| | | } |
| | | }, |
| | | |
| | | // 加载提交作品详情 |
| | | async loadSubmissionDetail() { |
| | | try { |
| | | this.setData({ loading: true }) |
| | | |
| | | const query = ` |
| | | query GetSubmissionDetail($id: ID!) { |
| | | submission(id: $id) { |
| | | query GetActivityPlayerDetail($id: ID!) { |
| | | activityPlayerDetail(id: $id) { |
| | | id |
| | | title |
| | | projectName |
| | | description |
| | | files { |
| | | activityName |
| | | stageId |
| | | state |
| | | playerInfo { |
| | | id |
| | | name |
| | | url |
| | | type |
| | | size |
| | | } |
| | | images |
| | | videos |
| | | submittedAt |
| | | status |
| | | participant { |
| | | id |
| | | name |
| | | school |
| | | major |
| | | avatar |
| | | } |
| | | team { |
| | | id |
| | | name |
| | | members { |
| | | id |
| | | phone |
| | | gender |
| | | birthday |
| | | education |
| | | introduction |
| | | userInfo { |
| | | userId |
| | | name |
| | | role |
| | | phone |
| | | avatarUrl |
| | | } |
| | | } |
| | | activity { |
| | | regionInfo { |
| | | id |
| | | title |
| | | description |
| | | judgeCriteria { |
| | | name |
| | | fullPath |
| | | } |
| | | submissionFiles { |
| | | id |
| | | name |
| | | fullUrl |
| | | fullThumbUrl |
| | | fileExt |
| | | fileSize |
| | | mediaType |
| | | } |
| | | ratingForm { |
| | | schemeId |
| | | schemeName |
| | | totalMaxScore |
| | | items { |
| | | id |
| | | name |
| | | description |
| | | maxScore |
| | | weight |
| | | orderNo |
| | | } |
| | | } |
| | | myReview { |
| | | id |
| | | scores |
| | | comment |
| | | totalScore |
| | | status |
| | | reviewedAt |
| | | } |
| | | } |
| | | } |
| | | ` |
| | | |
| | | const result = await graphqlRequest(query, { id: this.data.submissionId }) |
| | | const result = await graphqlRequest(query, { id: this.data.activityPlayerId }) |
| | | |
| | | if (result && result.submission) { |
| | | const submission = result.submission |
| | | if (result && result.activityPlayerDetail) { |
| | | const detail = result.activityPlayerDetail |
| | | |
| | | // 为每个文件添加下载状态 |
| | | if (submission.files) { |
| | | submission.files = submission.files.map(file => ({ |
| | | ...file, |
| | | isDownloading: this.data.downloadingFiles.indexOf(file.id) > -1 |
| | | })) |
| | | // 构建submission对象以兼容现有的WXML模板 |
| | | const submission = { |
| | | id: detail.id, |
| | | title: detail.projectName, |
| | | description: detail.description, |
| | | submittedAt: detail.submitTime || null, |
| | | team: detail.team || null, |
| | | participant: { |
| | | id: detail.playerInfo?.id, |
| | | name: detail.playerInfo?.name, |
| | | phone: detail.playerInfo?.phone || detail.playerInfo?.userInfo?.phone || '', |
| | | avatar: detail.playerInfo?.userInfo?.avatarUrl || '/images/default-avatar.svg', |
| | | gender: this.getGenderLabel(detail.playerInfo?.gender), |
| | | birthday: this.getBirthdayText(detail.playerInfo?.birthday), |
| | | region: detail.regionInfo?.fullPath || detail.regionInfo?.name || '', |
| | | education: detail.playerInfo?.education || '', |
| | | school: detail.regionInfo ? detail.regionInfo.name : '', |
| | | major: detail.playerInfo?.education || '' |
| | | }, |
| | | status: detail.state === 1 ? 'APPROVED' : detail.state === 2 ? 'REJECTED' : 'PENDING', |
| | | mediaList: (detail.submissionFiles || []).map(file => this.transformMediaFile(file)) |
| | | } |
| | | |
| | | // 初始化评分数据 |
| | | |
| | | const criteria = (detail.ratingForm?.items || []).map(item => { |
| | | const maxScore = item.maxScore || 0 |
| | | return { |
| | | id: item.id, |
| | | name: item.name, |
| | | maxScore, |
| | | description: item.description || '暂无描述', |
| | | step: maxScore > 20 ? 1 : 0.5, |
| | | currentScore: 0 |
| | | } |
| | | }) |
| | | |
| | | 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 |
| | | }) |
| | | } |
| | | |
| | | criteria.forEach(criterion => { |
| | | scores[criterion.id] = 0 |
| | | }) |
| | | |
| | | const maxScore = detail.ratingForm?.totalMaxScore || criteria.reduce((sum, item) => sum + (item.maxScore || 0), 0) |
| | | |
| | | this.setData({ |
| | | submission, |
| | | activity: submission.activity, |
| | | criteria: submission.activity.judgeCriteria || [], |
| | | activity: { |
| | | id: detail.id, |
| | | stageId: detail.stageId, |
| | | ratingSchemeId: detail.ratingForm?.schemeId || null, |
| | | totalMaxScore: maxScore |
| | | }, |
| | | stageId: detail.stageId || null, |
| | | submissionId: detail.id, |
| | | criteria, |
| | | scores, |
| | | maxScore, |
| | | existingReview: submission.myReview, |
| | | reviewStatus: submission.myReview ? submission.myReview.status : 'PENDING', |
| | | comment: submission.myReview ? submission.myReview.comment : '' |
| | | totalScore: 0, |
| | | existingReview: null, |
| | | reviewStatus: 'PENDING', |
| | | comment: '' |
| | | }) |
| | | |
| | | |
| | | this.calculateTotalScore() |
| | | |
| | | // 检查是否已有评分 |
| | | this.checkReviewStatus() |
| | | } |
| | | } catch (error) { |
| | | console.error('加载作品详情失败:', error) |
| | |
| | | async checkReviewStatus() { |
| | | try { |
| | | const query = ` |
| | | query CheckReviewStatus($submissionId: ID!) { |
| | | reviewStatus(submissionId: $submissionId) { |
| | | query GetCurrentJudgeRating($activityPlayerId: ID!) { |
| | | currentJudgeRating(activityPlayerId: $activityPlayerId) { |
| | | id |
| | | totalScore |
| | | remark |
| | | status |
| | | canReview |
| | | deadline |
| | | ratedAt |
| | | items { |
| | | ratingItemId |
| | | ratingItemName |
| | | score |
| | | maxScore |
| | | } |
| | | } |
| | | } |
| | | ` |
| | | |
| | | const result = await graphqlRequest(query, { submissionId: this.data.submissionId }) |
| | | const result = await graphqlRequest(query, { activityPlayerId: this.data.activityPlayerId }) |
| | | |
| | | if (result && result.reviewStatus) { |
| | | const { status, canReview, deadline } = result.reviewStatus |
| | | if (result && result.currentJudgeRating) { |
| | | const rating = result.currentJudgeRating |
| | | |
| | | if (!canReview) { |
| | | wx.showModal({ |
| | | title: '无法评审', |
| | | content: deadline ? `评审已截止(截止时间:${formatDate(deadline)})` : '当前无法进行评审', |
| | | showCancel: false, |
| | | success: () => { |
| | | wx.navigateBack() |
| | | } |
| | | // 如果已有评分,填充数据 |
| | | const scores = {} |
| | | let totalScore = 0 |
| | | |
| | | if (rating.items) { |
| | | rating.items.forEach(item => { |
| | | const numericScore = item.score !== undefined && item.score !== null ? Number(item.score) : 0 |
| | | scores[item.ratingItemId] = numericScore |
| | | totalScore += numericScore |
| | | }) |
| | | } |
| | | |
| | | const updatedCriteria = this.data.criteria.map(criterion => { |
| | | const value = scores[criterion.id] !== undefined ? scores[criterion.id] : 0 |
| | | return { |
| | | ...criterion, |
| | | currentScore: value |
| | | } |
| | | }) |
| | | |
| | | const normalizedTotal = Number(totalScore.toFixed(2)) |
| | | |
| | | this.setData({ |
| | | scores, |
| | | criteria: updatedCriteria, |
| | | totalScore: normalizedTotal, |
| | | comment: rating.remark || rating.comment || '', |
| | | existingReview: { |
| | | ...rating, |
| | | totalScore: rating.totalScore ? Number(rating.totalScore) : normalizedTotal, |
| | | reviewedAt: rating.ratedAt || rating.reviewedAt || rating.updateTime || null |
| | | }, |
| | | reviewStatus: 'COMPLETED' |
| | | }) |
| | | |
| | | console.log('已加载现有评分:', rating) |
| | | } else { |
| | | console.log('当前评委尚未评分') |
| | | } |
| | | |
| | | this.calculateTotalScore() |
| | | } catch (error) { |
| | | console.error('检查评审状态失败:', error) |
| | | } |
| | | }, |
| | | |
| | | normalizeScore(value, criterion) { |
| | | const maxScore = Number(criterion.maxScore || 0) |
| | | const step = Number(criterion.step || (maxScore > 20 ? 1 : 0.5)) |
| | | if (Number.isNaN(value)) { |
| | | value = 0 |
| | | } |
| | | let normalized = Math.round(value / step) * step |
| | | if (normalized < 0) normalized = 0 |
| | | if (normalized > maxScore) normalized = maxScore |
| | | return Number(normalized.toFixed(2)) |
| | | }, |
| | | |
| | | updateCriterionScore(criterionId, index, value) { |
| | | const criterion = this.data.criteria[index] |
| | | if (!criterion) return |
| | | const normalized = this.normalizeScore(value, criterion) |
| | | |
| | | this.setData({ |
| | | [`scores.${criterionId}`]: normalized, |
| | | [`criteria[${index}].currentScore`]: normalized |
| | | }) |
| | | |
| | | this.calculateTotalScore() |
| | | }, |
| | | |
| | | // 评分改变 |
| | | onScoreChange(e) { |
| | | const { criterionId } = e.currentTarget.dataset |
| | | const { value } = e.detail |
| | | |
| | | this.setData({ |
| | | [`scores.${criterionId}`]: parseInt(value) |
| | | }) |
| | | |
| | | this.calculateTotalScore() |
| | | const { criterionId, index } = e.currentTarget.dataset |
| | | const criterion = this.data.criteria[index] |
| | | if (!criterion) return |
| | | |
| | | const inputValue = Number(e.detail.value) |
| | | const newScore = this.normalizeScore(inputValue, criterion) |
| | | this.updateCriterionScore(criterionId, index, newScore) |
| | | }, |
| | | |
| | | increaseScore(e) { |
| | | const { criterionId, index } = e.currentTarget.dataset |
| | | const criterion = this.data.criteria[index] |
| | | if (!criterion) return |
| | | const current = Number(this.data.scores[criterionId] || criterion.currentScore || 0) |
| | | const step = criterion.step || (criterion.maxScore > 20 ? 1 : 0.5) |
| | | this.updateCriterionScore(criterionId, index, current + step) |
| | | }, |
| | | |
| | | decreaseScore(e) { |
| | | const { criterionId, index } = e.currentTarget.dataset |
| | | const criterion = this.data.criteria[index] |
| | | if (!criterion) return |
| | | const current = Number(this.data.scores[criterionId] || criterion.currentScore || 0) |
| | | const step = criterion.step || (criterion.maxScore > 20 ? 1 : 0.5) |
| | | this.updateCriterionScore(criterionId, index, current - step) |
| | | }, |
| | | |
| | | // 计算总分 |
| | |
| | | let totalScore = 0 |
| | | |
| | | criteria.forEach(criterion => { |
| | | const score = scores[criterion.id] || 0 |
| | | totalScore += score * (criterion.weight || 1) |
| | | const score = Number(scores[criterion.id] || 0) |
| | | totalScore += score |
| | | }) |
| | | |
| | | this.setData({ totalScore }) |
| | | this.setData({ totalScore: Number(totalScore.toFixed(2)) }) |
| | | }, |
| | | |
| | | // 评审意见输入 |
| | |
| | | |
| | | // 媒体点击 |
| | | onMediaTap(e) { |
| | | const { url, type } = e.currentTarget.dataset |
| | | |
| | | if (type === 'image') { |
| | | const index = Number(e.currentTarget.dataset.index) |
| | | const mediaList = this.data.submission?.mediaList || [] |
| | | const media = mediaList[index] |
| | | if (!media) return |
| | | |
| | | if (media.mediaType === 'image') { |
| | | const imageUrls = mediaList |
| | | .filter(item => item.mediaType === 'image') |
| | | .map(item => item.url) |
| | | wx.previewImage({ |
| | | current: url, |
| | | urls: this.data.submission.images || [] |
| | | current: media.url, |
| | | urls: imageUrls |
| | | }) |
| | | } else if (type === 'video') { |
| | | this.setData({ |
| | | showMediaPreview: true, |
| | | currentMedia: url, |
| | | mediaType: 'video' |
| | | } else if (media.mediaType === 'video') { |
| | | wx.navigateTo({ |
| | | url: `/pages/video/video?url=${encodeURIComponent(media.url)}&title=${encodeURIComponent(media.name)}` |
| | | }) |
| | | } else { |
| | | this.openDocumentMedia(media) |
| | | } |
| | | }, |
| | | |
| | | // 关闭媒体预览 |
| | | onCloseMediaPreview() { |
| | | this.setData({ |
| | | showMediaPreview: false, |
| | | currentMedia: null |
| | | }) |
| | | }, |
| | | |
| | | // 下载文件 |
| | | async onDownloadFile(e) { |
| | | const { fileId, fileName, fileUrl } = e.currentTarget.dataset |
| | | |
| | | async openDocumentMedia(media) { |
| | | 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 downloadRes = await new Promise((resolve, reject) => { |
| | | wx.downloadFile({ |
| | | url: media.url, |
| | | success: resolve, |
| | | fail: reject |
| | | }) |
| | | }) |
| | | |
| | | 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' |
| | | }) |
| | | } |
| | | |
| | | if (downloadRes.statusCode !== 200) { |
| | | throw new Error('文件下载失败') |
| | | } |
| | | |
| | | await new Promise((resolve, reject) => { |
| | | wx.openDocument({ |
| | | filePath: downloadRes.tempFilePath, |
| | | showMenu: true, |
| | | success: resolve, |
| | | fail: reject |
| | | }) |
| | | }) |
| | | } catch (error) { |
| | | console.error('下载文件失败:', error) |
| | | console.error('打开文件失败:', error) |
| | | wx.showToast({ |
| | | title: '下载失败', |
| | | 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 |
| | | const commentText = (comment || '').trim() |
| | | |
| | | // 检查是否所有标准都已评分 |
| | | for (let criterion of criteria) { |
| | |
| | | } |
| | | |
| | | // 检查评审意见 |
| | | if (!comment.trim()) { |
| | | if (!commentText) { |
| | | wx.showToast({ |
| | | title: '请填写评审意见', |
| | | icon: 'error' |
| | |
| | | return false |
| | | } |
| | | |
| | | if (comment.trim().length < 10) { |
| | | if (commentText.length < 10) { |
| | | wx.showToast({ |
| | | title: '评审意见至少10个字符', |
| | | icon: 'error' |
| | |
| | | } |
| | | |
| | | 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() |
| | | } |
| | | }, |
| | | |
| | | // 提交评审 |
| | |
| | | this.setData({ submitting: true }) |
| | | wx.showLoading({ title: '提交中...' }) |
| | | |
| | | const { submissionId, scores, comment, totalScore } = this.data |
| | | const { activityPlayerId, scores, comment, criteria, stageId } = this.data |
| | | const commentText = (comment || '').trim() |
| | | |
| | | if (!stageId) { |
| | | wx.showToast({ |
| | | title: '缺少阶段信息,无法提交', |
| | | icon: 'none' |
| | | }) |
| | | this.setData({ submitting: false }) |
| | | wx.hideLoading() |
| | | return |
| | | } |
| | | |
| | | // 构建评分项数组 |
| | | const ratings = criteria.map(criterion => ({ |
| | | itemId: criterion.id, |
| | | score: Number(scores[criterion.id] || 0) |
| | | })) |
| | | |
| | | const mutation = ` |
| | | mutation SubmitReview($input: ReviewSubmitInput!) { |
| | | submitReview(input: $input) { |
| | | success |
| | | review { |
| | | id |
| | | status |
| | | reviewedAt |
| | | } |
| | | } |
| | | mutation SaveActivityPlayerRating($input: ActivityPlayerRatingInput!) { |
| | | saveActivityPlayerRating(input: $input) |
| | | } |
| | | ` |
| | | |
| | | const input = { |
| | | submissionId, |
| | | scores, |
| | | comment: comment.trim(), |
| | | totalScore |
| | | activityPlayerId, |
| | | stageId, |
| | | ratings, |
| | | comment: commentText |
| | | } |
| | | |
| | | const result = await graphqlRequest(mutation, { input }) |
| | | |
| | | if (result && result.submitReview.success) { |
| | | if (result && result.saveActivityPlayerRating) { |
| | | wx.showToast({ |
| | | title: '评审提交成功', |
| | | title: '评分提交成功', |
| | | icon: 'success' |
| | | }) |
| | | |
| | | // 更新状态 |
| | | this.setData({ |
| | | reviewStatus: 'COMPLETED', |
| | | existingReview: result.submitReview.review |
| | | reviewStatus: 'COMPLETED' |
| | | }) |
| | | |
| | | // 重新加载评分状态 |
| | | await this.checkReviewStatus() |
| | | |
| | | // 延迟返回上一页 |
| | | setTimeout(() => { |
| | |
| | | }, 1500) |
| | | } |
| | | } catch (error) { |
| | | console.error('提交评审失败:', error) |
| | | console.error('提交评分失败:', error) |
| | | wx.showToast({ |
| | | title: '提交失败', |
| | | icon: 'error' |
| | |
| | | // 查看其他评审 |
| | | onViewOtherReviews() { |
| | | wx.navigateTo({ |
| | | url: `/pages/judge/reviews?submissionId=${this.data.submissionId}` |
| | | url: `/pages/judge/reviews?activityPlayerId=${this.data.activityPlayerId}` |
| | | }) |
| | | }, |
| | | |
| | | // 联系参赛者 |
| | | 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 |
| | | } |
| | | } |
| | | const phone = submission?.participant?.phone |
| | | if (phone) { |
| | | wx.makePhoneCall({ |
| | | phoneNumber: phone |
| | | }) |
| | | } else { |
| | | wx.showToast({ |
| | | title: '暂无联系方式', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | }, |
| | | |
| | | // 获取评分等级文本 |
| | | getScoreLabel(score) { |
| | | const option = this.data.scoreOptions.find(opt => opt.value === score) |
| | | return option ? option.label : `${score}分` |
| | | }, |
| | | |
| | | // 获取文件大小文本 |
| | |
| | | } |
| | | }, |
| | | |
| | | // 统一处理性别显示文本 |
| | | getGenderLabel(gender) { |
| | | if (gender === null || gender === undefined || gender === '') { |
| | | return '未填写' |
| | | } |
| | | |
| | | const normalized = String(gender).trim().toLowerCase() |
| | | |
| | | if (normalized === '') { |
| | | return '未填写' |
| | | } |
| | | |
| | | if (normalized === 'male' || normalized === 'm') { |
| | | return '男' |
| | | } |
| | | if (normalized === 'female' || normalized === 'f') { |
| | | return '女' |
| | | } |
| | | |
| | | if (/^-?\d+$/.test(normalized)) { |
| | | const numeric = Number(normalized) |
| | | if (numeric === 1) return '男' |
| | | if (numeric === 0) return '女' |
| | | if (numeric === 2) return '女' |
| | | } |
| | | |
| | | return gender === undefined || gender === null ? '未填写' : String(gender) |
| | | }, |
| | | |
| | | // 统一处理出生日期显示文本 |
| | | getBirthdayText(dateString) { |
| | | if (!dateString) { |
| | | return '未填写' |
| | | } |
| | | const formatted = formatDateUtil(dateString, 'YYYY-MM-DD') |
| | | return formatted || '未填写' |
| | | }, |
| | | |
| | | // 格式化日期 |
| | | formatDate(dateString) { |
| | | return formatDate(dateString, 'YYYY-MM-DD HH:mm') |
| | | return formatDateUtil(dateString, 'YYYY-MM-DD HH:mm') |
| | | }, |
| | | |
| | | // 分享页面 |
| | |
| | | path: '/pages/index/index' |
| | | } |
| | | } |
| | | }) |
| | | }) |