From f04f35b562760afbac0c477357e2a29f77aec3b9 Mon Sep 17 00:00:00 2001 From: lrj <owen.stl@gmail.com> Date: 星期四, 02 十月 2025 13:51:47 +0800 Subject: [PATCH] fix: 修复评审次数重复显示问题 --- web/src/views/review-list.vue | 350 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 343 insertions(+), 7 deletions(-) diff --git a/web/src/views/review-list.vue b/web/src/views/review-list.vue index 1df7c38..c63b301 100644 --- a/web/src/views/review-list.vue +++ b/web/src/views/review-list.vue @@ -60,18 +60,24 @@ v-loading="projectsLoading" empty-text="璇峰厛閫夋嫨姣旇禌" > - <el-table-column prop="playerName" label="椤圭洰鍚嶇О" min-width="150"> + <el-table-column prop="projectName" label="椤圭洰鍚嶇О" min-width="150"> <template #default="scope"> - {{ scope.row.projectName || scope.row.playerName }} + {{ scope.row.projectName || '鏈~鍐欓」鐩悕绉�' }} </template> </el-table-column> <el-table-column prop="playerName" label="鍙傝禌浜哄鍚�" min-width="120" /> <el-table-column prop="phone" label="鑱旂郴鐢佃瘽" min-width="120" /> <el-table-column prop="ratingCount" label="璇勫娆℃暟" width="100" align="center"> <template #default="scope"> - <el-tag :type="scope.row.ratingCount > 0 ? 'success' : 'info'"> + <el-button + text + :type="scope.row.ratingCount > 0 ? 'success' : 'info'" + @click="showRatingList(scope.row)" + :disabled="scope.row.ratingCount === 0" + class="rating-count-btn" + > {{ scope.row.ratingCount }} - </el-tag> + </el-button> </template> </el-table-column> <el-table-column prop="averageScore" label="骞冲潎鍒�" width="100" align="center"> @@ -119,6 +125,107 @@ @current-change="handleCurrentChange" /> </div> + + <!-- 璇勫鍒楄〃寮圭獥 --> + <el-dialog + v-model="ratingListVisible" + title="璇勫鍒楄〃" + width="60%" + :before-close="handleRatingListClose" + > + <div v-if="selectedProject"> + <div class="dialog-header"> + <h4>{{ selectedProject.projectName || selectedProject.playerName }} - 璇勫璇︽儏</h4> + <p class="project-info">鍙傝禌浜猴細{{ selectedProject.playerName }} | 鑱旂郴鐢佃瘽锛歿{ selectedProject.phone }}</p> + </div> + + <el-table + :data="judgeRatings" + v-loading="ratingsLoading" + style="width: 100%" + > + <el-table-column prop="judgeName" label="璇勫濮撳悕" min-width="120" /> + <el-table-column prop="totalScore" label="璇勫垎" width="100" align="center"> + <template #default="scope"> + <span v-if="scope.row.hasRated && scope.row.totalScore" class="score"> + {{ scope.row.totalScore.toFixed(1) }} + </span> + <span v-else class="no-score">鏈瘎鍒�</span> + </template> + </el-table-column> + <el-table-column prop="hasRated" label="鐘舵��" width="100" align="center"> + <template #default="scope"> + <el-tag :type="scope.row.hasRated ? 'success' : 'info'"> + {{ scope.row.hasRated ? '宸茶瘎鍒�' : '鏈瘎鍒�' }} + </el-tag> + </template> + </el-table-column> + <el-table-column label="鎿嶄綔" width="100" align="center"> + <template #default="scope"> + <el-button + text + type="primary" + @click="viewRatingDetail(scope.row)" + :disabled="!scope.row.hasRated" + size="small" + > + 鏌ョ湅璇︽儏 + </el-button> + </template> + </el-table-column> + </el-table> + </div> + + <template #footer> + <div class="dialog-footer"> + <el-button @click="handleRatingListClose">鍏抽棴</el-button> + </div> + </template> + </el-dialog> + + <!-- 璇勫垎璇︽儏寮圭獥 --> + <el-dialog + v-model="ratingDetailVisible" + title="璇勫垎璇︽儏" + width="50%" + :before-close="handleRatingDetailClose" + > + <div v-if="selectedRating"> + <div class="rating-detail-header"> + <h4>璇勫锛歿{ selectedRating.judgeName }}</h4> + <p>鎬诲垎锛�<span class="total-score">{{ selectedRating.totalScore.toFixed(1) }}</span></p> + </div> + + <el-table + :data="ratingItems" + v-loading="ratingDetailLoading" + style="width: 100%" + > + <el-table-column prop="itemName" label="璇勫垎椤圭洰" min-width="150" /> + <el-table-column prop="score" label="寰楀垎" width="100" align="center"> + <template #default="scope"> + <span class="item-score">{{ scope.row.score }}</span> + </template> + </el-table-column> + <el-table-column prop="maxScore" label="婊″垎" width="100" align="center"> + <template #default="scope"> + <span class="max-score">{{ scope.row.maxScore || 100 }}</span> + </template> + </el-table-column> + </el-table> + + <div v-if="selectedRating.remark" class="rating-comment"> + <h5>璇勮锛�</h5> + <p>{{ selectedRating.remark }}</p> + </div> + </div> + + <template #footer> + <div class="dialog-footer"> + <el-button @click="handleRatingDetailClose">鍏抽棴</el-button> + </div> + </template> + </el-dialog> </div> </template> @@ -127,8 +234,10 @@ import { useRouter } from 'vue-router' import { ElMessage } from 'element-plus' import { Search, Trophy, View } from '@element-plus/icons-vue' -import { getActiveActivities, getRatingStats } from '@/api/projectReview' +import { getActiveActivities, getRatingStats, getJudgeRatingDetail } from '@/api/projectReview' import { getProjectReviewApplications } from '@/api/projectReviewNew' +import { userApi } from '@/api/user' +import { getUserInfo } from '@/utils/auth' const router = useRouter() @@ -139,6 +248,16 @@ const searchName = ref('') const activitiesLoading = ref(false) const projectsLoading = ref(false) + +// 璇勫寮圭獥鐩稿叧鏁版嵁 +const ratingListVisible = ref(false) +const ratingDetailVisible = ref(false) +const selectedProject = ref(null) +const selectedRating = ref(null) +const judgeRatings = ref([]) +const ratingItems = ref([]) +const ratingsLoading = ref(false) +const ratingDetailLoading = ref(false) // 鍒嗛〉鏁版嵁 const currentPage = ref(1) @@ -251,8 +370,147 @@ } // 鏌ョ湅璇︽儏 -const viewDetails = (projectId) => { - router.push(`/project-review/${projectId}/detail`) +const viewDetails = async (projectId) => { + // 浼犻�抯tageId鍙傛暟锛宻electedActivity.value灏辨槸褰撳墠閫変腑鐨剆tageId + const stageId = selectedActivity.value + if (!stageId) { + ElMessage.warning('璇峰厛閫夋嫨姣旇禌闃舵') + return + } + + try { + // 鑾峰彇褰撳墠鐢ㄦ埛淇℃伅 + const userInfo = getUserInfo() + if (!userInfo) { + ElMessage.error('鐢ㄦ埛鏈櫥褰曪紝璇烽噸鏂扮櫥褰�') + return + } + + // 妫�鏌ョ敤鎴锋槸鍚︽湁employee韬唤 + const hasEmployeeRole = !!userInfo.employee + + if (hasEmployeeRole) { + // 濡傛灉鐢ㄦ埛鏈塭mployee韬唤锛岀洿鎺ュ厑璁告煡鐪嬶紙涓嶉渶瑕佹潈闄愭鏌ワ級 + console.log('鐢ㄦ埛鍏锋湁鍛樺伐韬唤锛屽厑璁告煡鐪嬫墍鏈夎瘎鍒嗚褰�') + router.push(`/project-review/${projectId}/detail?stageId=${stageId}`) + return + } + + // 濡傛灉鐢ㄦ埛鍙湁judge韬唤锛堟病鏈塭mployee韬唤锛夛紝闇�瑕佹鏌ヨ瘎濮旀潈闄� + const judgeInfo = await userApi.getCurrentJudgeInfo() + + if (!judgeInfo) { + ElMessage.error('鎮ㄦ病鏈夎瘎濮旀潈闄愶紝鏃犳硶杩涜璇勫') + return + } + + // 妫�鏌ヨ瘎濮旀槸鍚︽湁褰撳墠姣旇禌闃舵鐨勬潈闄� + const hasPermission = await userApi.checkJudgeInActivity(stageId, judgeInfo.judgeId) + + if (!hasPermission) { + ElMessage.error('鎮ㄦ病鏈夊綋鍓嶆瘮璧涢樁娈电殑璇勫鏉冮檺锛屾棤娉曡繘鍏ヨ瘎瀹¢〉闈�') + return + } + + // 鏉冮檺妫�鏌ラ�氳繃锛岃烦杞埌璇勫椤甸潰 + router.push(`/project-review/${projectId}/detail?stageId=${stageId}`) + } catch (error) { + console.error('鏉冮檺妫�鏌ュけ璐�:', error) + ElMessage.error('鏉冮檺楠岃瘉澶辫触锛岃閲嶆柊鐧诲綍') + } +} + +// 鏄剧ず璇勫鍒楄〃 +const showRatingList = async (project) => { + if (project.ratingCount === 0) { + ElMessage.warning('璇ラ」鐩殏鏃犺瘎瀹¤褰�') + return + } + + selectedProject.value = project + ratingListVisible.value = true + + // 鍔犺浇璇勫鍒楄〃 + await loadJudgeRatings(project.id) +} + +// 鍔犺浇璇勫璇勫垎鍒楄〃 +const loadJudgeRatings = async (activityPlayerId) => { + ratingsLoading.value = true + try { + const result = await getRatingStats(activityPlayerId) + console.log('getRatingStats 杩斿洖鏁版嵁:', result) + + // 浣跨敤姝g‘鐨勫瓧娈靛悕 + judgeRatings.value = result.ratings || [] + console.log('judgeRatings 璁剧疆涓�:', judgeRatings.value) + } catch (error) { + console.error('鍔犺浇璇勫鍒楄〃澶辫触:', error) + ElMessage.error('鍔犺浇璇勫鍒楄〃澶辫触') + judgeRatings.value = [] + } finally { + ratingsLoading.value = false + } +} + +// 鏌ョ湅璇勫垎璇︽儏 +const viewRatingDetail = async (rating) => { + if (!rating.hasRated) { + ElMessage.warning('璇ヨ瘎濮斿皻鏈瘎鍒�') + return + } + + selectedRating.value = rating + ratingDetailVisible.value = true + + // 鍔犺浇璇勫垎鏄庣粏 + await loadRatingDetail(selectedProject.value.id, rating.judgeId) +} + +// 鍔犺浇璇勫垎鏄庣粏 +const loadRatingDetail = async (activityPlayerId, judgeId) => { + ratingDetailLoading.value = true + try { + console.log('鍔犺浇璇勫垎鏄庣粏锛宎ctivityPlayerId:', activityPlayerId, 'judgeId:', judgeId) + + const result = await getJudgeRatingDetail(activityPlayerId, judgeId) + console.log('璇勫垎鏄庣粏API杩斿洖:', result) + + if (result && result.items) { + ratingItems.value = result.items.map(item => ({ + itemName: item.ratingItemName, + score: item.score, + maxScore: item.maxScore || 100 + })) + + // 鏇存柊閫変腑璇勫垎鐨勫娉ㄤ俊鎭� + if (selectedRating.value) { + selectedRating.value.remark = result.remark + } + } else { + ratingItems.value = [] + } + } catch (error) { + console.error('鍔犺浇璇勫垎鏄庣粏澶辫触:', error) + ElMessage.error('鍔犺浇璇勫垎鏄庣粏澶辫触: ' + (error.message || '鏈煡閿欒')) + ratingItems.value = [] + } finally { + ratingDetailLoading.value = false + } +} + +// 鍏抽棴璇勫鍒楄〃寮圭獥 +const handleRatingListClose = () => { + ratingListVisible.value = false + selectedProject.value = null + judgeRatings.value = [] +} + +// 鍏抽棴璇勫垎璇︽儏寮圭獥 +const handleRatingDetailClose = () => { + ratingDetailVisible.value = false + selectedRating.value = null + ratingItems.value = [] } // 鏍煎紡鍖栨棩鏈� @@ -350,6 +608,84 @@ line-height: 1.5; } +/* 璇勫娆℃暟鎸夐挳鏍峰紡 */ +.rating-count-btn { + font-weight: 500; +} + +/* 寮圭獥鏍峰紡 */ +.dialog-header { + margin-bottom: 20px; + + h4 { + margin: 0 0 8px 0; + color: #303133; + font-size: 16px; + font-weight: 600; + } + + .project-info { + margin: 0; + color: #606266; + font-size: 14px; + } +} + +.rating-detail-header { + margin-bottom: 20px; + + h4 { + margin: 0 0 8px 0; + color: #303133; + font-size: 16px; + font-weight: 600; + } + + .total-score { + color: #409eff; + font-weight: 600; + font-size: 18px; + } +} + +.rating-comment { + margin-top: 20px; + padding: 16px; + background-color: #f5f7fa; + border-radius: 8px; + + h5 { + margin: 0 0 8px 0; + color: #303133; + font-size: 14px; + font-weight: 600; + } + + p { + margin: 0; + color: #606266; + line-height: 1.6; + } +} + +.score { + color: #67c23a; + font-weight: 600; +} + +.no-score { + color: #909399; +} + +.item-score { + color: #409eff; + font-weight: 500; +} + +.max-score { + color: #909399; +} + /* 鎼滅储宸ュ叿鏍� */ .search-toolbar { display: flex; -- Gitblit v1.8.0