From 53c865a07640f763484f870e348b0a32837b05dd Mon Sep 17 00:00:00 2001 From: DevOps Date: Tue, 23 Dec 2025 17:26:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=AF=84?= =?UTF-8?q?=E5=88=86=E5=88=97=E8=A1=A8=E9=A1=B5=E9=9D=A2UI=E5=92=8C?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构场地和项目选择区域布局 - 优化选手卡片样式 - 添加日期时间格式化方法 - 改进分数显示格式 - 统一样式命名规范 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../score-list-multi/score-list-multi.vue | 622 +++++++++--------- src/pages/score-list/score-list.vue | 42 +- 2 files changed, 341 insertions(+), 323 deletions(-) diff --git a/src/pages/score-list-multi/score-list-multi.vue b/src/pages/score-list-multi/score-list-multi.vue index 66ea4e2..152a579 100644 --- a/src/pages/score-list-multi/score-list-multi.vue +++ b/src/pages/score-list-multi/score-list-multi.vue @@ -4,57 +4,45 @@ 评分系统 - ··· - + ··· + {{ matchInfo.name }} - 比赛时间:{{ matchInfo.time }} + 比赛时间:{{ formatDateTime(matchInfo.time) }} - - - - - - - {{ venue.venueName }} - - - - - - - + + + + + {{ venueInfo.name }} + 刷新 - - - + + + {{ project.projectName }} - + - 已评分: - {{ scoredCount }}/{{ totalCount }} + 已评分: + {{ scoredCount }}/{{ totalCount }} @@ -65,25 +53,42 @@ v-for="player in players" :key="player.athleteId" > - + {{ player.name }} - 总分:{{ player.totalScore }} - - - + + 总分: + {{ formatScore(player.totalScore) }} + - - 身份证:{{ player.idCard }} - 队伍:{{ player.team }} - 编号:{{ player.number }} + + + 身份证:{{ player.idCard }} + + + 队伍:{{ player.team }} + + + 编号:{{ player.number }} + + + + + 加载中... + — 没有更多了 — + + + + + 暂无选手数据 + @@ -96,38 +101,47 @@ export default { data() { return { matchInfo: { - id: '', name: '', time: '' }, - competitionId: '', - currentVenue: '', - currentProject: '', - venues: [], + venueInfo: { + id: '', + name: '' + }, + projectInfo: { + id: '', + name: '' + }, + judgeId: '', projects: [], + currentProjectIndex: 0, players: [], scoredCount: 0, - totalCount: 0 + totalCount: 0, + pagination: { + current: 1, + size: 10, + total: 0 + }, + isLoading: false, + hasMore: true, + isFirstLoad: true } }, async onLoad() { - // 获取全局数据 const app = getApp() const globalData = app.globalData || {} // 检查登录状态 if (!globalData.judgeId || !globalData.token) { - console.warn('用户未登录,跳转到登录页') uni.showToast({ title: '请先登录', icon: 'none', duration: 1500 }) setTimeout(() => { - uni.reLaunch({ - url: '/pages/login/login' - }) + uni.reLaunch({ url: '/pages/login/login' }) }, 1500) return } @@ -143,171 +157,197 @@ export default { // 加载比赛信息 this.matchInfo = { - id: globalData.matchId, name: globalData.matchName || '比赛名称', - time: globalData.matchTime || '比赛时间' + time: globalData.matchTime || '' } - // 注意:裁判长没有固定场地和项目,需要查看所有 - this.competitionId = globalData.matchId + // 从 globalData 获取场地信息(与普通裁判相同) + this.venueInfo = { + id: globalData.venueId, + name: globalData.venueName || '场地' + } + + // 从 globalData 获取项目列表 + this.projects = globalData.projects || [] + this.currentProjectIndex = globalData.currentProjectIndex || 0 + this.updateCurrentProject() + this.judgeId = globalData.judgeId // 调试信息 if (config.debug) { console.log('裁判长列表页加载:', { userRole: globalData.userRole, - competitionId: this.competitionId + judgeId: this.judgeId, + venueId: this.venueInfo.id, + projectId: this.projectInfo.id }) } - // 加载场地和项目列表 - await this.loadVenuesAndProjects() + await this.loadPlayers(true) + this.isFirstLoad = false + }, + + async onShow() { + // 从修改评分页返回时刷新数据 + if (!this.isFirstLoad) { + if (config.debug) { + console.log('页面显示,刷新数据') + } + await this.loadPlayers(true) + } + }, + + async onPullDownRefresh() { + await this.loadPlayers(true) + uni.stopPullDownRefresh() + }, + + async onReachBottom() { + if (this.hasMore && !this.isLoading) { + await this.loadMore() + } }, methods: { - async loadVenuesAndProjects() { + formatDateTime(dateTimeStr) { + if (!dateTimeStr) return '' try { - uni.showLoading({ - title: '加载中...', - mask: true - }) - - // 🔥 关键改动:使用 dataAdapter 获取场地列表 - // Mock模式:调用 mock/athlete.js 的 getVenues 函数 - // API模式:调用 api/athlete.js 的 getVenues 函数(GET /martial/venue/list) - const venuesRes = await dataAdapter.getData('getVenues', { - competitionId: this.competitionId - }) - - // 🔥 关键改动:使用 dataAdapter 获取项目列表 - // Mock模式:调用 mock/athlete.js 的 getProjects 函数 - // API模式:调用 api/athlete.js 的 getProjects 函数(GET /martial/project/list) - const projectsRes = await dataAdapter.getData('getProjects', { - competitionId: this.competitionId - }) - - this.venues = venuesRes.data || [] - this.projects = projectsRes.data || [] - - // 默认选中第一个场地和项目 - if (this.venues.length > 0) { - this.currentVenue = this.venues[0].venueId - } - if (this.projects.length > 0) { - this.currentProject = this.projects[0].projectId - } - - uni.hideLoading() - - // 调试信息 - if (config.debug) { - console.log('场地和项目加载成功:', { - venues: this.venues.length, - projects: this.projects.length, - currentVenue: this.currentVenue, - currentProject: this.currentProject - }) - } - - // 加载选手列表 - if (this.currentVenue && this.currentProject) { - await this.loadPlayers() - } - + const date = new Date(dateTimeStr) + if (isNaN(date.getTime())) return dateTimeStr + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + const hours = date.getHours() + const minutes = date.getMinutes() + const paddedMinutes = minutes < 10 ? '0' + minutes : minutes + return year + '年' + month + '月' + day + '日 ' + hours + ':' + paddedMinutes } catch (error) { - uni.hideLoading() - console.error('加载场地和项目失败:', error) - uni.showToast({ - title: error.message || '加载失败', - icon: 'none' - }) + return dateTimeStr } }, - async loadPlayers() { - try { - uni.showLoading({ - title: '加载中...', - mask: true - }) + formatScore(score) { + // 处理 null、undefined、-1 等无效值 + if (score === null || score === undefined || score === -1 || score === '-1') { + return '--' + } + // 如果是字符串类型的数字,直接返回 + if (typeof score === 'string' && !isNaN(parseFloat(score))) { + return score + } + // 如果是数字类型,保留3位小数 + if (typeof score === 'number') { + return score.toFixed(3) + } + return score + }, - // 🔥 关键改动:使用 dataAdapter 获取选手列表(裁判长视图) - // Mock模式:调用 mock/athlete.js 的 getAthletesForAdmin 函数 - // API模式:调用 api/athlete.js 的 getAthletesForAdmin 函数(GET /mini/score/athletes) + async handleRefresh() { + if (this.isLoading) return + uni.showToast({ title: '刷新中...', icon: 'loading', duration: 1000 }) + await this.loadPlayers(true) + uni.showToast({ title: '刷新成功', icon: 'success', duration: 1000 }) + }, + + async loadPlayers(refresh = false) { + if (this.isLoading) return + try { + this.isLoading = true + if (refresh) { + this.pagination.current = 1 + this.hasMore = true + } + if (refresh && this.isFirstLoad) { + uni.showLoading({ title: '加载中...', mask: true }) + } const app = getApp() const globalData = app.globalData || {} - const response = await dataAdapter.getData('getAthletesForAdmin', { - judgeId: globalData.judgeId, - competitionId: this.competitionId, - venueId: this.currentVenue, - projectId: this.currentProject + const params = { + matchCode: globalData.matchCode, + judgeId: this.judgeId, + venueId: this.venueInfo.id, + projectId: this.projectInfo.id, + current: this.pagination.current, + size: this.pagination.size + } + Object.keys(params).forEach(key => { + if (params[key] === undefined || params[key] === null || params[key] === '') { + delete params[key] + } }) - uni.hideLoading() - - // 保存选手列表 - this.players = response.data || [] - - // 计算评分统计(裁判长视图:统计有总分的选手) - this.totalCount = this.players.length - this.scoredCount = this.players.filter(p => p.totalScore).length - - // 调试信息 if (config.debug) { - console.log('选手列表加载成功:', { - venueId: this.currentVenue, - projectId: this.currentProject, - total: this.totalCount, + console.log('请求选手列表参数:', params) + } + + // 裁判长使用 getAthletesForAdmin 接口 + const response = await dataAdapter.getData('getAthletesForAdmin', params) + + if (config.debug) { + console.log('选手列表响应:', response) + } + + if (refresh && this.isFirstLoad) { + uni.hideLoading() + } + const responseData = response.data || {} + const records = responseData.records || response.data || [] + const total = responseData.total || records.length + this.pagination.total = total + this.totalCount = total + if (refresh) { + this.players = records + } else { + this.players = [...this.players, ...records] + } + // 裁判长视图:统计有总分的选手 + this.scoredCount = this.players.filter(p => p.totalScore).length + this.hasMore = this.players.length < total + + if (config.debug) { + console.log('选手列表处理结果:', { + total: total, + loaded: this.players.length, scored: this.scoredCount, players: this.players }) } - } catch (error) { uni.hideLoading() console.error('加载选手列表失败:', error) - uni.showToast({ - title: error.message || '加载失败', - icon: 'none' - }) + uni.showToast({ title: error.message || '加载失败', icon: 'none' }) + } finally { + this.isLoading = false } }, - async switchVenue(venueId) { - if (this.currentVenue === venueId) return - - this.currentVenue = venueId - - // 调试信息 - if (config.debug) { - console.log('切换场地:', venueId) - } - - // 重新加载选手列表 - await this.loadPlayers() - }, - - async switchProject(projectId) { - if (this.currentProject === projectId) return - - this.currentProject = projectId - - // 调试信息 - if (config.debug) { - console.log('切换项目:', projectId) - } - - // 重新加载选手列表 - await this.loadPlayers() + async loadMore() { + if (!this.hasMore || this.isLoading) return + this.pagination.current++ + await this.loadPlayers(false) }, goToModify(player) { - // 保存当前选手信息到全局数据 const app = getApp() app.globalData.currentAthlete = player + uni.navigateTo({ url: '/pages/modify-score/modify-score' }) + }, - uni.navigateTo({ - url: '/pages/modify-score/modify-score' - }) + updateCurrentProject() { + const currentProject = this.projects[this.currentProjectIndex] || {} + this.projectInfo = { + id: currentProject.projectId, + name: currentProject.projectName || '项目' + } + }, + + async switchProject(index) { + if (index === this.currentProjectIndex) return + this.currentProjectIndex = index + const app = getApp() + app.globalData.currentProjectIndex = index + this.updateCurrentProject() + await this.loadPlayers(true) } } } @@ -320,7 +360,7 @@ export default { padding-bottom: 40rpx; } -/* 导航栏 */ +/* ==================== 导航栏 ==================== */ .nav-bar { height: 90rpx; background: linear-gradient(135deg, #1B7C5E 0%, #2A9D7E 100%); @@ -335,7 +375,6 @@ export default { font-size: 36rpx; font-weight: 600; color: #FFFFFF; - letter-spacing: 2rpx; } .nav-right { @@ -343,24 +382,15 @@ export default { right: 30rpx; display: flex; align-items: center; - gap: 30rpx; + gap: 20rpx; } -.icon-menu, -.icon-close { - width: 60rpx; - height: 60rpx; - background-color: rgba(255, 255, 255, 0.25); - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; +.nav-dots, .nav-circle { font-size: 32rpx; color: #FFFFFF; - font-weight: bold; } -/* 比赛信息 */ +/* ==================== 比赛信息 ==================== */ .match-info { padding: 30rpx; background-color: #F5F5F5; @@ -369,132 +399,94 @@ export default { .match-title { font-size: 32rpx; font-weight: 600; - color: #333333; - line-height: 1.6; - margin-bottom: 10rpx; -} - -.tip-text { - font-size: 24rpx; - color: #FF4D6A; - margin-bottom: 10rpx; + color: #1B7C5E; + line-height: 1.5; + margin-bottom: 8rpx; } .match-time { font-size: 28rpx; - color: #666666; + color: #333333; } -/* 场地和项目区域 */ -.venue-section { +/* ==================== 场地卡片 ==================== */ +.venue-card { + margin: 0 30rpx 20rpx; background-color: #FFFFFF; - margin: 20rpx 30rpx; border-radius: 16rpx; padding: 30rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06); } -/* 场地滚动容器 */ -.venue-scroll { - width: 100%; - white-space: nowrap; - margin-bottom: 20rpx; +.venue-header { + display: flex; + align-items: center; + justify-content: space-between; + padding-bottom: 24rpx; + border-bottom: 4rpx solid #1B7C5E; + margin-bottom: 24rpx; } -.venue-tabs { - display: inline-flex; - gap: 30rpx; - padding-bottom: 20rpx; - border-bottom: 4rpx solid #E0E0E0; - position: relative; -} - -.venue-tab { +.venue-name { font-size: 32rpx; - font-weight: 500; - color: #666666; - padding: 0 20rpx; - position: relative; - white-space: nowrap; - flex-shrink: 0; -} - -.venue-tab.active { font-weight: 600; color: #333333; } -.venue-tab.active::after { - content: ''; - position: absolute; - bottom: -24rpx; - left: 0; - right: 0; - height: 4rpx; - background-color: #1B7C5E; +.refresh-link { + font-size: 26rpx; + color: #4A90D9; } -.venue-tip { - font-size: 24rpx; - line-height: 1.6; - margin-bottom: 20rpx; +.project-row { + display: flex; + flex-direction: column; } -.tip-bold { - color: #FF4D6A; - font-weight: 500; +.project-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 16rpx; } -.tip-normal { - color: #FF4D6A; -} - -/* 项目滚动容器 */ -.project-scroll { - width: 100%; - white-space: nowrap; -} - -.project-list { - display: inline-flex; - gap: 20rpx; -} - -.project-btn { - padding: 20rpx 30rpx; - background-color: #FFFFFF; - border: 2rpx solid #CCCCCC; +.project-chip { + padding: 20rpx 12rpx; + border: 2rpx solid #1B7C5E; border-radius: 8rpx; font-size: 26rpx; - color: #666666; + color: #1B7C5E; + background-color: #FFFFFF; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; white-space: nowrap; - flex-shrink: 0; } -.project-btn.active { +.project-chip.active { background-color: #1B7C5E; color: #FFFFFF; - border-color: #1B7C5E; - font-weight: 500; } -/* 评分统计 */ +/* ==================== 评分统计 ==================== */ .score-stats { padding: 20rpx 30rpx; + display: flex; + align-items: center; +} + +.stats-label { font-size: 28rpx; color: #333333; } -.stats-text { - color: #666666; -} - -.stats-number { +.stats-value { + font-size: 32rpx; color: #1B7C5E; font-weight: 600; + margin-left: 8rpx; } -/* 选手列表 */ +/* ==================== 选手卡片 ==================== */ .player-list { padding: 0 30rpx; } @@ -502,12 +494,12 @@ export default { .player-card { background-color: #FFFFFF; border-radius: 16rpx; - padding: 30rpx; + padding: 24rpx; margin-bottom: 20rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08); + box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06); } -.player-header { +.card-header { display: flex; align-items: flex-start; justify-content: space-between; @@ -520,32 +512,31 @@ export default { color: #333333; } +/* ==================== 操作区域 ==================== */ .action-area { display: flex; - flex-direction: column; - align-items: flex-end; - gap: 10rpx; + align-items: center; + gap: 16rpx; } -.total-score { - font-size: 26rpx; - color: #333333; - font-weight: 600; -} - -.chief-actions { +.score-tag { display: flex; - flex-direction: column; - align-items: flex-end; - gap: 10rpx; + align-items: center; + padding: 12rpx 20rpx; + background-color: #F5F5F5; + border-radius: 8rpx; + border: 2rpx solid #E5E5E5; } -.chief-hint { - font-size: 22rpx; - color: #FF4D6A; - text-align: right; - line-height: 1.5; - max-width: 400rpx; +.tag-label { + font-size: 24rpx; + color: #666666; +} + +.tag-value { + font-size: 28rpx; + color: #333333; + font-weight: 500; } .modify-btn { @@ -555,21 +546,50 @@ export default { font-size: 28rpx; color: #FFFFFF; font-weight: 500; + border: none; + line-height: 1.4; } -.modify-btn:active { - opacity: 0.9; -} - -.player-info { +/* ==================== 选手详情 ==================== */ +.player-details { display: flex; flex-direction: column; - gap: 12rpx; + gap: 8rpx; } -.info-item { +.detail-row { + line-height: 1.6; +} + +.detail-text { font-size: 26rpx; color: #666666; - line-height: 1.5; +} + +/* ==================== 加载状态 ==================== */ +.loading-status { + padding: 30rpx 0; + text-align: center; +} + +.loading-text { + font-size: 26rpx; + color: #1B7C5E; +} + +.no-more-text { + font-size: 26rpx; + color: #999999; +} + +/* ==================== 空状态 ==================== */ +.empty-state { + padding: 100rpx 0; + text-align: center; +} + +.empty-text { + font-size: 28rpx; + color: #999999; } diff --git a/src/pages/score-list/score-list.vue b/src/pages/score-list/score-list.vue index 40d4506..d26e887 100644 --- a/src/pages/score-list/score-list.vue +++ b/src/pages/score-list/score-list.vue @@ -25,19 +25,17 @@ - - - - {{ project.projectName }} - + + + {{ project.projectName }} - + @@ -443,23 +441,23 @@ export default { flex-direction: column; } -.project-scroll { - white-space: nowrap; -} - -.project-chips { - display: inline-flex; - gap: 20rpx; +.project-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 16rpx; } .project-chip { - display: inline-block; - padding: 16rpx 32rpx; + padding: 20rpx 12rpx; border: 2rpx solid #1B7C5E; border-radius: 8rpx; - font-size: 28rpx; + font-size: 26rpx; color: #1B7C5E; background-color: #FFFFFF; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .project-chip.active {