diff --git a/pages/score-detail/score-detail.vue b/pages/score-detail/score-detail.vue index 50da31c..d4aa58c 100644 --- a/pages/score-detail/score-detail.vue +++ b/pages/score-detail/score-detail.vue @@ -31,28 +31,22 @@ - - + {{ currentScore.toFixed(3) }} + 点击编辑 - - - 扣分项: - @@ -82,12 +76,35 @@ v-model="note" maxlength="200" /> - + + + + + + 输入分数 + + + + 分数范围:{{ minScore }} - {{ maxScore }},保留3位小数 + + + + + + + @@ -113,16 +130,16 @@ export default { note: '', minScore: 5.0, maxScore: 10.0, - deductions: [] + deductions: [], + showInputModal: false, + inputScore: '' } }, async onLoad() { - // 获取全局数据 const app = getApp() const globalData = app.globalData || {} - // 加载当前选手信息(从 score-list 页面传递) const currentAthlete = globalData.currentAthlete || {} this.player = { athleteId: currentAthlete.athleteId || '', @@ -132,18 +149,15 @@ export default { number: currentAthlete.number || '' } - // 如果选手已评分,加载其原有评分 if (currentAthlete.scored && currentAthlete.myScore) { this.currentScore = currentAthlete.myScore } - // 加载评委ID和项目ID this.judgeId = globalData.judgeId this.projectId = globalData.currentProjectId || '' this.competitionId = globalData.matchId || globalData.matchCode || '' this.venueId = globalData.currentVenueId || globalData.venueId || '' - // 调试信息 if (config.debug) { console.log('评分详情页加载:', { athlete: this.player, @@ -155,22 +169,17 @@ export default { }) } - // 加载扣分项列表 await this.loadDeductions() }, methods: { async loadDeductions() { try { - // 🔥 关键改动:使用 dataAdapter 获取扣分项列表 - // Mock模式:调用 mock/score.js 的 getDeductions 函数 - // API模式:调用 api/score.js 的 getDeductions 函数(GET /martial/deductionItem/list) const response = await dataAdapter.getData('getDeductions', { projectId: this.projectId }) - // 为每个扣分项添加 checked 状态,并映射字段名 - const records = response.data?.records || [] + const records = response.data && response.data.records ? response.data.records : [] this.deductions = records.map(item => ({ deductionId: item.id, deductionName: item.itemName, @@ -178,7 +187,6 @@ export default { checked: false })) - // 调试信息 if (config.debug) { console.log('扣分项加载成功:', this.deductions) } @@ -201,7 +209,6 @@ export default { delta: 1, fail: (err) => { console.error('返回失败:', err) - // 如果返回失败,尝试跳转到评分列表页 uni.redirectTo({ url: '/pages/score-list/score-list' }) @@ -221,12 +228,44 @@ export default { } }, + showScoreInput() { + this.inputScore = this.currentScore.toFixed(3) + this.showInputModal = true + }, + + hideScoreInput() { + this.showInputModal = false + this.inputScore = '' + }, + + confirmScoreInput() { + const score = parseFloat(this.inputScore) + + if (isNaN(score)) { + uni.showToast({ + title: '请输入有效的数字', + icon: 'none' + }) + return + } + + if (score < this.minScore || score > this.maxScore) { + uni.showToast({ + title: `分数必须在${this.minScore}-${this.maxScore}之间`, + icon: 'none' + }) + return + } + + this.currentScore = parseFloat(score.toFixed(3)) + this.hideScoreInput() + }, + toggleDeduction(index) { this.deductions[index].checked = !this.deductions[index].checked }, async handleSubmit() { - // 验证评分范围 if (this.currentScore < this.minScore || this.currentScore > this.maxScore) { uni.showToast({ title: `评分必须在${this.minScore}-${this.maxScore}分之间`, @@ -235,7 +274,6 @@ export default { return } - // 验证必需字段 if (!this.competitionId) { uni.showToast({ title: '缺少比赛ID,请重新登录', @@ -252,7 +290,6 @@ export default { return } - // 收集选中的扣分项ID const selectedDeductions = this.deductions .filter(item => item.checked) .map(item => item.deductionId) @@ -263,7 +300,6 @@ export default { mask: true }) - // 准备提交数据 const submitData = { athleteId: this.player.athleteId, judgeId: this.judgeId, @@ -275,19 +311,14 @@ export default { note: this.note } - // 调试日志:打印提交数据 if (config.debug) { console.log('准备提交评分数据:', submitData) } - // 🔥 关键改动:使用 dataAdapter 提交评分 - // Mock模式:调用 mock/score.js 的 submitScore 函数 - // API模式:调用 api/score.js 的 submitScore 函数(POST /martial/score/submit) const response = await dataAdapter.getData('submitScore', submitData) uni.hideLoading() - // 调试信息 if (config.debug) { console.log('评分提交成功:', { athleteId: this.player.athleteId, @@ -297,14 +328,12 @@ export default { }) } - // 显示成功提示 uni.showToast({ title: '提交成功', icon: 'success', duration: 1500 }) - // 返回上一页 setTimeout(() => { uni.navigateBack() }, 1500) @@ -485,6 +514,14 @@ export default { display: flex; flex-direction: column; align-items: center; + cursor: pointer; + padding: 20rpx; + border-radius: 16rpx; + transition: background-color 0.2s; +} + +.score-display:active { + background-color: rgba(27, 124, 94, 0.1); } .current-score { @@ -493,6 +530,12 @@ export default { color: #1B7C5E; } +.edit-hint { + font-size: 22rpx; + color: #999999; + margin-top: 8rpx; +} + .judge-tip { padding: 0 30rpx; font-size: 24rpx; @@ -628,4 +671,95 @@ export default { .submit-btn:active { opacity: 0.9; } + +/* 分数输入弹窗 */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} + +.modal-content { + width: 600rpx; + background-color: #FFFFFF; + border-radius: 24rpx; + overflow: hidden; +} + +.modal-header { + padding: 40rpx 30rpx 20rpx; + text-align: center; +} + +.modal-title { + font-size: 34rpx; + font-weight: 600; + color: #333333; +} + +.modal-body { + padding: 20rpx 30rpx 30rpx; +} + +.score-input { + width: 100%; + height: 90rpx; + border: 2rpx solid #E0E0E0; + border-radius: 12rpx; + padding: 0 24rpx; + font-size: 36rpx; + text-align: center; + color: #1B7C5E; + font-weight: 600; +} + +.score-input:focus { + border-color: #1B7C5E; +} + +.input-hint { + display: block; + margin-top: 16rpx; + font-size: 24rpx; + color: #999999; + text-align: center; +} + +.modal-footer { + display: flex; + border-top: 1rpx solid #E0E0E0; +} + +.modal-btn { + flex: 1; + height: 100rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 32rpx; + background: none; + border: none; + border-radius: 0; +} + +.modal-btn.cancel { + color: #666666; + border-right: 1rpx solid #E0E0E0; +} + +.modal-btn.confirm { + color: #1B7C5E; + font-weight: 600; +} + +.modal-btn:active { + background-color: #F5F5F5; +} diff --git a/src/pages/score-detail/score-detail.vue b/src/pages/score-detail/score-detail.vue index a38714b..d4aa58c 100644 --- a/src/pages/score-detail/score-detail.vue +++ b/src/pages/score-detail/score-detail.vue @@ -31,28 +31,22 @@ - - + {{ currentScore.toFixed(3) }} + 点击编辑 - - - 扣分项: - @@ -82,12 +76,35 @@ v-model="note" maxlength="200" /> - + + + + + + 输入分数 + + + + 分数范围:{{ minScore }} - {{ maxScore }},保留3位小数 + + + + + + + @@ -107,50 +124,22 @@ export default { }, judgeId: '', projectId: '', + competitionId: '', + venueId: '', currentScore: 8.000, note: '', minScore: 5.0, maxScore: 10.0, - deductions: [] + deductions: [], + showInputModal: false, + inputScore: '' } }, 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' - }) - }, 1500) - return - } - - // 检查是否有选手信息 - if (!globalData.currentAthlete || !globalData.currentAthlete.athleteId) { - console.warn('没有选手信息,返回列表页') - uni.showToast({ - title: '请选择选手', - icon: 'none', - duration: 1500 - }) - setTimeout(() => { - uni.navigateBack() - }, 1500) - return - } - - // 加载当前选手信息(从 score-list 页面传递) const currentAthlete = globalData.currentAthlete || {} this.player = { athleteId: currentAthlete.athleteId || '', @@ -160,57 +149,44 @@ export default { number: currentAthlete.number || '' } - // 如果选手已评分,加载其原有评分 if (currentAthlete.scored && currentAthlete.myScore) { this.currentScore = currentAthlete.myScore } - // 加载评委ID和项目ID this.judgeId = globalData.judgeId - const projects = globalData.projects || [] - const currentIndex = globalData.currentProjectIndex || 0 - const currentProject = projects[currentIndex] || {} - this.projectId = currentProject.projectId + this.projectId = globalData.currentProjectId || '' + this.competitionId = globalData.matchId || globalData.matchCode || '' + this.venueId = globalData.currentVenueId || globalData.venueId || '' - // 调试信息 if (config.debug) { console.log('评分详情页加载:', { athlete: this.player, judgeId: this.judgeId, projectId: this.projectId, + competitionId: this.competitionId, + venueId: this.venueId, initialScore: this.currentScore }) } - // 加载扣分项列表 await this.loadDeductions() }, methods: { async loadDeductions() { try { - // 🔥 关键改动:使用 dataAdapter 获取扣分项列表 - // Mock模式:调用 mock/score.js 的 getDeductions 函数 - // API模式:调用 api/score.js 的 getDeductions 函数(GET /blade-martial/deductionItem/list) const response = await dataAdapter.getData('getDeductions', { projectId: this.projectId }) - // 获取返回数据(兼容分页和非分页格式) - const responseData = response.data || {} - const records = responseData.records || response.data || [] - - // 为每个扣分项添加 checked 状态,并映射字段名 - // 后端字段: id, itemName - // 前端字段: deductionId, deductionName - this.deductions = (Array.isArray(records) ? records : []).map(item => ({ - deductionId: item.deductionId || item.id, - deductionName: item.deductionName || item.itemName, - deductionPoint: item.deductionPoint || 0, + const records = response.data && response.data.records ? response.data.records : [] + this.deductions = records.map(item => ({ + deductionId: item.id, + deductionName: item.itemName, + deductionScore: parseFloat(item.deductionPoint || 0), checked: false })) - // 调试信息 if (config.debug) { console.log('扣分项加载成功:', this.deductions) } @@ -225,7 +201,19 @@ export default { }, goBack() { - uni.navigateBack() + if (config.debug) { + console.log('返回上一页') + } + + uni.navigateBack({ + delta: 1, + fail: (err) => { + console.error('返回失败:', err) + uni.redirectTo({ + url: '/pages/score-list/score-list' + }) + } + }) }, decreaseScore() { @@ -240,12 +228,44 @@ export default { } }, + showScoreInput() { + this.inputScore = this.currentScore.toFixed(3) + this.showInputModal = true + }, + + hideScoreInput() { + this.showInputModal = false + this.inputScore = '' + }, + + confirmScoreInput() { + const score = parseFloat(this.inputScore) + + if (isNaN(score)) { + uni.showToast({ + title: '请输入有效的数字', + icon: 'none' + }) + return + } + + if (score < this.minScore || score > this.maxScore) { + uni.showToast({ + title: `分数必须在${this.minScore}-${this.maxScore}之间`, + icon: 'none' + }) + return + } + + this.currentScore = parseFloat(score.toFixed(3)) + this.hideScoreInput() + }, + toggleDeduction(index) { this.deductions[index].checked = !this.deductions[index].checked }, async handleSubmit() { - // 验证评分范围 if (this.currentScore < this.minScore || this.currentScore > this.maxScore) { uni.showToast({ title: `评分必须在${this.minScore}-${this.maxScore}分之间`, @@ -254,10 +274,25 @@ export default { return } - // 收集选中的扣分项ID(转为数字类型,后端期望 List) + if (!this.competitionId) { + uni.showToast({ + title: '缺少比赛ID,请重新登录', + icon: 'none' + }) + return + } + + if (!this.projectId) { + uni.showToast({ + title: '缺少项目ID,请返回重新选择', + icon: 'none' + }) + return + } + const selectedDeductions = this.deductions .filter(item => item.checked) - .map(item => String(item.deductionId)) + .map(item => item.deductionId) try { uni.showLoading({ @@ -265,26 +300,25 @@ export default { mask: true }) - // 🔥 关键改动:使用 dataAdapter 提交评分 - // Mock模式:调用 mock/score.js 的 submitScore 函数 - // API模式:调用 api/score.js 的 submitScore 函数(POST /mini/score/submit) - const app = getApp() - const globalData = app.globalData || {} - const response = await dataAdapter.getData('submitScore', { - athleteId: String(this.player.athleteId), - judgeId: String(this.judgeId), + const submitData = { + athleteId: this.player.athleteId, + judgeId: this.judgeId, + projectId: this.projectId, + competitionId: this.competitionId, + venueId: this.venueId, score: this.currentScore, - projectId: String(this.projectId), - competitionId: globalData.matchId ? String(globalData.matchId) : null, - venueId: globalData.venueId ? String(globalData.venueId) : null, - scheduleId: globalData.scheduleId ? String(globalData.scheduleId) : null, deductions: selectedDeductions, - note: this.note || '' - }) + note: this.note + } + + if (config.debug) { + console.log('准备提交评分数据:', submitData) + } + + const response = await dataAdapter.getData('submitScore', submitData) uni.hideLoading() - // 调试信息 if (config.debug) { console.log('评分提交成功:', { athleteId: this.player.athleteId, @@ -294,14 +328,12 @@ export default { }) } - // 显示成功提示 uni.showToast({ title: '提交成功', icon: 'success', duration: 1500 }) - // 返回上一页 setTimeout(() => { uni.navigateBack() }, 1500) @@ -341,12 +373,19 @@ export default { .nav-left { position: absolute; - left: 30rpx; - width: 60rpx; - height: 60rpx; + left: 0; + top: 0; + width: 120rpx; + height: 90rpx; display: flex; align-items: center; justify-content: center; + z-index: 10; + cursor: pointer; +} + +.nav-left:active { + opacity: 0.6; } .back-icon { @@ -475,6 +514,14 @@ export default { display: flex; flex-direction: column; align-items: center; + cursor: pointer; + padding: 20rpx; + border-radius: 16rpx; + transition: background-color 0.2s; +} + +.score-display:active { + background-color: rgba(27, 124, 94, 0.1); } .current-score { @@ -483,6 +530,12 @@ export default { color: #1B7C5E; } +.edit-hint { + font-size: 22rpx; + color: #999999; + margin-top: 8rpx; +} + .judge-tip { padding: 0 30rpx; font-size: 24rpx; @@ -618,4 +671,95 @@ export default { .submit-btn:active { opacity: 0.9; } + +/* 分数输入弹窗 */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} + +.modal-content { + width: 600rpx; + background-color: #FFFFFF; + border-radius: 24rpx; + overflow: hidden; +} + +.modal-header { + padding: 40rpx 30rpx 20rpx; + text-align: center; +} + +.modal-title { + font-size: 34rpx; + font-weight: 600; + color: #333333; +} + +.modal-body { + padding: 20rpx 30rpx 30rpx; +} + +.score-input { + width: 100%; + height: 90rpx; + border: 2rpx solid #E0E0E0; + border-radius: 12rpx; + padding: 0 24rpx; + font-size: 36rpx; + text-align: center; + color: #1B7C5E; + font-weight: 600; +} + +.score-input:focus { + border-color: #1B7C5E; +} + +.input-hint { + display: block; + margin-top: 16rpx; + font-size: 24rpx; + color: #999999; + text-align: center; +} + +.modal-footer { + display: flex; + border-top: 1rpx solid #E0E0E0; +} + +.modal-btn { + flex: 1; + height: 100rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 32rpx; + background: none; + border: none; + border-radius: 0; +} + +.modal-btn.cancel { + color: #666666; + border-right: 1rpx solid #E0E0E0; +} + +.modal-btn.confirm { + color: #1B7C5E; + font-weight: 600; +} + +.modal-btn:active { + background-color: #F5F5F5; +}