From 915d80766dd8e0157e9b9510b3634ed758eb5c5a Mon Sep 17 00:00:00 2001 From: Codex Assistant <codex@example.com> Date: 星期日, 05 十月 2025 14:45:58 +0800 Subject: [PATCH] feat: 新增员工审核入口与审核页面 --- wx/pages/profile/profile.js | 380 ++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 285 insertions(+), 95 deletions(-) diff --git a/wx/pages/profile/profile.js b/wx/pages/profile/profile.js index 7e68688..99de718 100644 --- a/wx/pages/profile/profile.js +++ b/wx/pages/profile/profile.js @@ -16,20 +16,31 @@ awards: 0 }, - // 鎴戠殑鎶ュ悕璁板綍 - registrations: [], - registrationLoading: false, + + + // 鐢ㄦ埛椤圭洰 + userProjects: [], + projectsLoading: false, // 瑙掕壊鐩稿叧 userRoles: [], isJudge: false, isOrganizer: false, + hasPlayer: false, + isEmployee: false, + + // 鍛樺伐瀹℃牳缁熻 + employeeReviewStats: { + pendingCount: 0, + approvedCount: 0, + rejectedCount: 0 + }, // 璇勫鐩稿叧鏁版嵁 judgeStats: { pendingReviews: 0, completedReviews: 0, - totalReviews: 0 + studentUnReviewedCount: 0 }, // 涓诲姙鏂圭浉鍏虫暟鎹� @@ -141,14 +152,14 @@ this.loadUserInfo() this.loadUserStats() - this.loadRecentRegistrations() + this.loadUserProjects() }, onShow() { // 椤甸潰鏄剧ず鏃跺埛鏂版暟鎹� this.loadUserInfo() this.loadUserStats() - this.loadRecentRegistrations() + this.loadUserProjects() // 鍒濆鍖栬嚜瀹氫箟 tabbar if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().init() @@ -161,13 +172,18 @@ // 鍒锋柊鏁版嵁 async refreshData() { + this.setData({ loading: true }) + try { await Promise.all([ this.loadUserInfo(), this.loadUserStats(), - this.loadRecentRegistrations() + this.loadUserProjects() ]) + } catch (error) { + console.error('鍒锋柊鏁版嵁澶辫触:', error) } finally { + this.setData({ loading: false }) wx.stopPullDownRefresh() } }, @@ -190,6 +206,18 @@ grade roles createdAt + employee { + id + name + roleId + description + } + player { + id + name + phone + description + } } } ` @@ -203,6 +231,8 @@ const userRoles = userInfo.roles || [] const isJudge = userRoles.includes('JUDGE') const isOrganizer = userRoles.includes('ORGANIZER') + const hasPlayer = userInfo.player && userInfo.player.id + const isEmployee = !!(userInfo.employee && userInfo.employee.id) // 澶勭悊澶村儚鏂囧瓧 const avatarText = (userInfo.name || '鐢ㄦ埛').substring(0, 1) @@ -212,7 +242,9 @@ avatarText, userRoles, isJudge, - isOrganizer + isOrganizer, + hasPlayer, + isEmployee }) // 鏇存柊鍏ㄥ眬鐢ㄦ埛淇℃伅 @@ -225,6 +257,18 @@ if (isOrganizer) { this.loadOrganizerStats() + } + + if (isEmployee) { + this.loadEmployeeReviewStats() + } else { + this.setData({ + employeeReviewStats: { + pendingCount: 0, + approvedCount: 0, + rejectedCount: 0 + } + }) } } } catch (error) { @@ -265,74 +309,140 @@ }, // 鍔犺浇鏈�杩戞姤鍚嶈褰� - async loadRecentRegistrations() { + // 鍔犺浇鐢ㄦ埛椤圭洰 + async loadUserProjects() { + this.setData({ projectsLoading: true }) + try { - this.setData({ registrationLoading: true }) - const query = ` - query GetRecentRegistrations { - myRegistrations(limit: 5) { + query GetMyProjects { + myProjects { id - activity { - id - title - coverImage { - id - name - path - fullUrl - fullThumbUrl - mediaType - } - startTime - status - } + projectName + activityName status - registrationTime + statusText + createTime + submissionFiles { + id + name + path + fullUrl + fullThumbUrl + fileExt + mediaType + } } } ` const result = await graphqlRequest(query) - if (result && result.myRegistrations) { - // 涓烘瘡涓椿鍔ㄦ坊鍔犳爣棰樻枃瀛� - const registrations = result.myRegistrations.map(registration => ({ - ...registration, - activity: { - ...registration.activity, - titleText: (registration.activity.title || '娲诲姩').substring(0, 2) + if (result && result.myProjects) { + const projects = result.myProjects.map(project => { + // 鑾峰彇椤圭洰鐨勭涓�涓獟浣撴枃浠朵綔涓虹缉鐣ュ浘 + let thumbnailUrl = '' + let iconClass = this.getProjectIcon(project.status) + + if (project.submissionFiles && project.submissionFiles.length > 0) { + const firstFile = project.submissionFiles[0] + + // 鏍规嵁鏂囦欢绫诲瀷璁剧疆缂╃暐鍥惧拰鍥炬爣 + if (firstFile.mediaType === 'IMAGE') { + thumbnailUrl = firstFile.fullThumbUrl || firstFile.fullUrl + iconClass = 'ic-image' + } else if (firstFile.mediaType === 'VIDEO') { + thumbnailUrl = firstFile.fullThumbUrl || firstFile.fullUrl + iconClass = 'ic-video' + } else if (firstFile.fileExt && firstFile.fileExt.toLowerCase() === 'pdf') { + iconClass = 'ic-pdf' + } else if (firstFile.fileExt && ['doc', 'docx'].includes(firstFile.fileExt.toLowerCase())) { + iconClass = 'ic-word' + } else { + iconClass = 'ic-file' + } } - })) - - this.setData({ - registrations + + return { + id: project.id, + projectName: project.projectName, + activityName: project.activityName, + state: project.status, + statusText: project.statusText || this.getProjectStatusText(project.status), + statusType: this.getProjectStatusType(project.status), + icon: iconClass, + thumbnailUrl: thumbnailUrl, + createTime: project.createTime + } }) + + this.setData({ userProjects: projects }) } } catch (error) { - console.error('鍔犺浇鎶ュ悕璁板綍澶辫触:', error) + console.error('鍔犺浇鐢ㄦ埛椤圭洰澶辫触:', error) + // 涓嶆樉绀洪敊璇彁绀猴紝闈欓粯澶辫触 } finally { - this.setData({ registrationLoading: false }) + this.setData({ projectsLoading: false }) } }, + // 鍔犺浇鍛樺伐瀹℃牳缁熻 + async loadEmployeeReviewStats(keyword = null) { + if (!this.data.isEmployee) { + return + } + + try { + const query = ` + query EmployeeReviewStats($keyword: String) { + employeeReviewStats(keyword: $keyword) { + pendingCount + approvedCount + rejectedCount + } + } + ` + + const variables = {} + if (keyword && typeof keyword === 'string' && keyword.trim()) { + variables.keyword = keyword.trim() + } + + const result = await graphqlRequest(query, variables) + + if (result && result.employeeReviewStats) { + this.setData({ + employeeReviewStats: result.employeeReviewStats + }) + } + } catch (error) { + console.error('鍔犺浇鍛樺伐瀹℃牳缁熻澶辫触:', error) + } + }, // 鍔犺浇璇勫缁熻鏁版嵁 async loadJudgeStats() { try { const query = ` - query GetJudgeStats { - judgeStats { - pendingReviews - completedReviews - totalReviews + query GetReviewStatistics { + reviewStatistics { + unReviewedCount + reviewedCount + studentUnReviewedCount } } ` const result = await graphqlRequest(query) - if (result && result.judgeStats) { - const judgeStats = result.judgeStats + if (result && result.reviewStatistics) { + const stats = result.reviewStatistics + + // 杞崲瀛楁鍚嶄互鍖归厤鐜版湁鐨勬暟鎹粨鏋� + const judgeStats = { + pendingReviews: stats.unReviewedCount, + completedReviews: stats.reviewedCount, + studentUnReviewedCount: stats.studentUnReviewedCount + } this.setData({ judgeStats, @@ -376,14 +486,58 @@ }) }, - // 鑿滃崟椤圭偣鍑� - onMenuItemTap(e) { - const { path } = e.currentTarget.dataset - + // 璺宠浆鍒颁釜浜轰俊鎭〉闈� + goToPersonalInfo() { wx.navigateTo({ - url: path + url: '/pages/profile/personal-info' }) }, + + // 璺宠浆鍒伴」鐩鎯呴〉闈� + goToProjectDetail(e) { + const projectId = e.currentTarget.dataset.projectId + + if (!projectId) { + wx.showToast({ + title: '椤圭洰ID鏃犳晥', + icon: 'none' + }) + return + } + + // 濡傛灉鏄ず渚嬫暟鎹紝鏄剧ず鎻愮ず + if (projectId === 'registrations' || projectId === 'achievements') { + wx.showToast({ + title: '杩欐槸绀轰緥椤圭洰锛岃閫夋嫨鐪熷疄椤圭洰', + icon: 'none' + }) + return + } + + wx.navigateTo({ + url: `/pages/project/detail?id=${projectId}` + }) + }, + + // 璺宠浆鍒拌瘎瀹¢〉闈� + goToReviewPage() { + wx.navigateTo({ + url: '/pages/review/index' + }) + }, + + // 璺宠浆鍒板憳宸ュ鏍搁〉闈� + goToEmployeeReviewPage() { + if (!this.data.isEmployee) { + return + } + + wx.navigateTo({ + url: '/pages/profile/employee-review' + }) + }, + + // 鏌ョ湅鎶ュ悕璇︽儏 onRegistrationTap(e) { @@ -448,53 +602,89 @@ return formatDate(dateString, 'MM-DD HH:mm') }, - // 閫�鍑虹櫥褰� - onLogout() { - wx.showModal({ - title: '纭閫�鍑�', - content: '纭畾瑕侀��鍑虹櫥褰曞悧锛�', - success: (res) => { - if (res.confirm) { - this.logout() - } - } - }) + // 鑾峰彇椤圭洰鐘舵�佹枃鏈紙鏀寔鏁板瓧鍜屽瓧绗︿覆鐘舵�侊級 + getProjectStatusText(status) { + // 鏁板瓧鐘舵�佹槧灏勶紙涓巜eb绔繚鎸佷竴鑷达級 + const numericStatusMap = { + 0: '鏈鏍�', + 1: '瀹℃牳閫氳繃', + 2: '瀹℃牳椹冲洖', + 3: '宸茬粨鏉�' + } + + // 瀛楃涓茬姸鎬佹槧灏� + const stringStatusMap = { + 'SUBMITTED': '宸叉彁浜�', + 'UNDER_REVIEW': '璇勫涓�', + 'REVIEWED': '宸茶瘎瀹�', + 'REJECTED': '宸叉嫆缁�', + 'DRAFT': '鑽夌' + } + + // 浼樺厛浣跨敤鏁板瓧鐘舵�佹槧灏� + if (typeof status === 'number' && numericStatusMap[status]) { + return numericStatusMap[status] + } + + return stringStatusMap[status] || '鏈煡鐘舵��' }, - // 鎵ц閫�鍑虹櫥褰� - async logout() { - try { - wx.showLoading({ title: '閫�鍑轰腑...' }) - - // 娓呴櫎鏈湴瀛樺偍 - wx.removeStorageSync('token') - wx.removeStorageSync('userInfo') - - // 娓呴櫎鍏ㄥ眬鏁版嵁 - app.globalData.token = '' - app.globalData.userInfo = null - app.globalData.isLoggedIn = false - - // 璺宠浆鍒扮櫥褰曢〉 - wx.reLaunch({ - url: '/pages/login/login' - }) - - wx.showToast({ - title: '宸查��鍑虹櫥褰�', - icon: 'success' - }) - } catch (error) { - console.error('閫�鍑虹櫥褰曞け璐�:', error) - wx.showToast({ - title: '閫�鍑哄け璐�', - icon: 'error' - }) - } finally { - wx.hideLoading() + // 鑾峰彇椤圭洰鐘舵�佺被鍨嬶紙鐢ㄤ簬鏍峰紡锛� + getProjectStatusType(status) { + // 鏁板瓧鐘舵�佺被鍨嬫槧灏勶紙涓巜eb绔繚鎸佷竴鑷达級 + const numericTypeMap = { + 0: 'warning', // 鏈鏍� + 1: 'success', // 瀹℃牳閫氳繃 + 2: 'danger', // 瀹℃牳椹冲洖 + 3: 'info' // 宸茬粨鏉� } + + // 瀛楃涓茬姸鎬佺被鍨嬫槧灏� + const stringTypeMap = { + 'SUBMITTED': 'primary', + 'UNDER_REVIEW': 'warning', + 'REVIEWED': 'success', + 'REJECTED': 'danger', + 'DRAFT': 'info' + } + + // 浼樺厛浣跨敤鏁板瓧鐘舵�佹槧灏� + if (typeof status === 'number' && numericTypeMap[status]) { + return numericTypeMap[status] + } + + return stringTypeMap[status] || 'info' }, + // 鑾峰彇椤圭洰鍥炬爣 + getProjectIcon(status) { + // 鏁板瓧鐘舵�佸浘鏍囨槧灏� + const numericIconMap = { + 0: '鈴�', // 鏈鏍� + 1: '鉁�', // 瀹℃牳閫氳繃 + 2: '鉂�', // 瀹℃牳椹冲洖 + 3: '馃搵' // 宸茬粨鏉� + } + + // 瀛楃涓茬姸鎬佸浘鏍囨槧灏� + const stringIconMap = { + 'SUBMITTED': '馃搵', + 'UNDER_REVIEW': '鈴�', + 'REVIEWED': '鉁�', + 'REJECTED': '鉂�', + 'DRAFT': '馃摑' + } + + // 浼樺厛浣跨敤鏁板瓧鐘舵�佹槧灏� + if (typeof status === 'number' && numericIconMap[status]) { + return numericIconMap[status] + } + + return stringIconMap[status] || '馃搵' + }, + + + // 鍒嗕韩椤甸潰 onShareAppMessage() { return { -- Gitblit v1.8.0