766 lines
15 KiB
Vue
766 lines
15 KiB
Vue
<template>
|
||
<view class="container">
|
||
<!-- 自定义导航栏 -->
|
||
<view class="nav-bar">
|
||
<view class="nav-left" @click="goBack">
|
||
<text class="back-icon">‹</text>
|
||
</view>
|
||
<view class="nav-title">评分详情</view>
|
||
<view class="nav-right">
|
||
<view class="icon-menu">···</view>
|
||
<view class="icon-close">⊗</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 选手信息 -->
|
||
<view class="player-info-section">
|
||
<view class="player-name">{{ player.name }}</view>
|
||
<view class="player-details">
|
||
<view class="detail-item">身份证:{{ player.idCard }}</view>
|
||
<view class="detail-item">队伍:{{ player.team }}</view>
|
||
<view class="detail-item">编号:{{ player.number }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 评分提示 -->
|
||
<view class="score-tip">
|
||
点击分数填写或拖动滑块打分(5-10分)
|
||
</view>
|
||
|
||
<!-- 分数调整 -->
|
||
<view class="score-control">
|
||
<view class="control-btn decrease" @click="decreaseScore">
|
||
<text class="btn-symbol">-</text>
|
||
</view>
|
||
|
||
<view class="score-display" @click="showScoreInput">
|
||
<text class="current-score">{{ currentScore.toFixed(3) }}</text>
|
||
<text class="edit-hint">点击编辑</text>
|
||
</view>
|
||
|
||
<view class="control-btn increase" @click="increaseScore">
|
||
<text class="btn-symbol">+</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 扣分项 -->
|
||
<view class="deduction-section">
|
||
<view class="deduction-header">
|
||
<text class="deduction-label">扣分项:</text>
|
||
</view>
|
||
|
||
<view class="deduction-list">
|
||
<view
|
||
v-for="(item, index) in deductions"
|
||
:key="item.deductionId"
|
||
class="deduction-item"
|
||
@click="toggleDeduction(index)"
|
||
>
|
||
<view :class="['checkbox', item.checked ? 'checked' : '']">
|
||
<text v-if="item.checked" class="check-icon">✓</text>
|
||
</view>
|
||
<text class="deduction-text">{{ item.deductionName }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 备注 -->
|
||
<view class="note-section">
|
||
<view class="note-label">
|
||
<text>备注:</text>
|
||
</view>
|
||
<view class="note-input-wrapper">
|
||
<textarea
|
||
class="note-input"
|
||
placeholder="请输入修改备注"
|
||
v-model="note"
|
||
maxlength="200"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 提交按钮 -->
|
||
<button class="submit-btn" @click="handleSubmit">提交</button>
|
||
|
||
<!-- 分数输入弹窗 -->
|
||
<view v-if="showInputModal" class="modal-overlay" @click="hideScoreInput">
|
||
<view class="modal-content" @click.stop>
|
||
<view class="modal-header">
|
||
<text class="modal-title">输入分数</text>
|
||
</view>
|
||
<view class="modal-body">
|
||
<input
|
||
type="digit"
|
||
class="score-input"
|
||
v-model="inputScore"
|
||
placeholder="请输入5-10之间的分数"
|
||
:focus="showInputModal"
|
||
@confirm="confirmScoreInput"
|
||
/>
|
||
<text class="input-hint">分数范围:{{ minScore }} - {{ maxScore }},保留3位小数</text>
|
||
</view>
|
||
<view class="modal-footer">
|
||
<button class="modal-btn cancel" @click="hideScoreInput">取消</button>
|
||
<button class="modal-btn confirm" @click="confirmScoreInput">确定</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import dataAdapter from '@/utils/dataAdapter.js'
|
||
import config from '@/config/env.config.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
player: {
|
||
athleteId: '',
|
||
name: '',
|
||
idCard: '',
|
||
team: '',
|
||
number: ''
|
||
},
|
||
judgeId: '',
|
||
projectId: '',
|
||
competitionId: '',
|
||
venueId: '',
|
||
currentScore: 8.000,
|
||
note: '',
|
||
minScore: 5.0,
|
||
maxScore: 10.0,
|
||
deductions: [],
|
||
showInputModal: false,
|
||
inputScore: ''
|
||
}
|
||
},
|
||
|
||
async onLoad() {
|
||
const app = getApp()
|
||
const globalData = app.globalData || {}
|
||
|
||
const currentAthlete = globalData.currentAthlete || {}
|
||
this.player = {
|
||
athleteId: currentAthlete.athleteId || '',
|
||
name: currentAthlete.name || '选手姓名',
|
||
idCard: currentAthlete.idCard || '',
|
||
team: currentAthlete.team || '',
|
||
number: currentAthlete.number || ''
|
||
}
|
||
|
||
if (currentAthlete.scored && currentAthlete.myScore) {
|
||
this.currentScore = currentAthlete.myScore
|
||
}
|
||
|
||
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,
|
||
judgeId: this.judgeId,
|
||
projectId: this.projectId,
|
||
competitionId: this.competitionId,
|
||
venueId: this.venueId,
|
||
initialScore: this.currentScore
|
||
})
|
||
}
|
||
|
||
await this.loadDeductions()
|
||
},
|
||
|
||
methods: {
|
||
async loadDeductions() {
|
||
try {
|
||
const response = await dataAdapter.getData('getDeductions', {
|
||
projectId: this.projectId
|
||
})
|
||
|
||
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)
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('加载扣分项失败:', error)
|
||
uni.showToast({
|
||
title: '加载扣分项失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
goBack() {
|
||
if (config.debug) {
|
||
console.log('返回上一页')
|
||
}
|
||
|
||
uni.navigateBack({
|
||
delta: 1,
|
||
fail: (err) => {
|
||
console.error('返回失败:', err)
|
||
uni.redirectTo({
|
||
url: '/pages/score-list/score-list'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
|
||
decreaseScore() {
|
||
if (this.currentScore > this.minScore) {
|
||
this.currentScore = parseFloat((this.currentScore - 0.001).toFixed(3))
|
||
}
|
||
},
|
||
|
||
increaseScore() {
|
||
if (this.currentScore < this.maxScore) {
|
||
this.currentScore = parseFloat((this.currentScore + 0.001).toFixed(3))
|
||
}
|
||
},
|
||
|
||
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}分之间`,
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
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 => item.deductionId)
|
||
|
||
try {
|
||
uni.showLoading({
|
||
title: '提交中...',
|
||
mask: true
|
||
})
|
||
|
||
const submitData = {
|
||
athleteId: this.player.athleteId,
|
||
judgeId: this.judgeId,
|
||
projectId: this.projectId,
|
||
competitionId: this.competitionId,
|
||
venueId: this.venueId,
|
||
score: this.currentScore,
|
||
deductions: selectedDeductions,
|
||
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,
|
||
score: this.currentScore,
|
||
deductions: selectedDeductions,
|
||
response: response
|
||
})
|
||
}
|
||
|
||
uni.showToast({
|
||
title: '提交成功',
|
||
icon: 'success',
|
||
duration: 1500
|
||
})
|
||
|
||
setTimeout(() => {
|
||
uni.navigateBack()
|
||
}, 1500)
|
||
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
console.error('提交评分失败:', error)
|
||
|
||
uni.showToast({
|
||
title: error.message || '提交失败,请重试',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.container {
|
||
min-height: 100vh;
|
||
background-color: #F5F5F5;
|
||
padding-bottom: 40rpx;
|
||
}
|
||
|
||
/* 导航栏 */
|
||
.nav-bar {
|
||
height: 90rpx;
|
||
background: linear-gradient(135deg, #1B7C5E 0%, #2A9D7E 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
padding: 0 30rpx;
|
||
}
|
||
|
||
.nav-left {
|
||
position: absolute;
|
||
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 {
|
||
font-size: 60rpx;
|
||
color: #FFFFFF;
|
||
font-weight: 300;
|
||
line-height: 1;
|
||
}
|
||
|
||
.nav-title {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: #FFFFFF;
|
||
letter-spacing: 2rpx;
|
||
}
|
||
|
||
.nav-right {
|
||
position: absolute;
|
||
right: 30rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 30rpx;
|
||
}
|
||
|
||
.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;
|
||
font-size: 32rpx;
|
||
color: #FFFFFF;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 选手信息 */
|
||
.player-info-section {
|
||
margin: 30rpx;
|
||
}
|
||
|
||
.player-name {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
color: #333333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.player-details {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.detail-item {
|
||
font-size: 26rpx;
|
||
color: #CD8B6F;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* 评分提示 */
|
||
.score-tip {
|
||
padding: 0 30rpx;
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
/* 分数控制 */
|
||
.score-control {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 60rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.control-btn {
|
||
width: 140rpx;
|
||
height: 140rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #F5F5F5;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.control-btn.decrease {
|
||
background-color: #FFE5E5;
|
||
}
|
||
|
||
.control-btn.increase {
|
||
background-color: #E5F5F0;
|
||
}
|
||
|
||
.btn-symbol {
|
||
font-size: 48rpx;
|
||
font-weight: 300;
|
||
}
|
||
|
||
.control-btn.decrease .btn-symbol {
|
||
color: #FF4D6A;
|
||
}
|
||
|
||
.control-btn.increase .btn-symbol {
|
||
color: #1B7C5E;
|
||
}
|
||
|
||
.btn-value {
|
||
font-size: 24rpx;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.control-btn.decrease .btn-value {
|
||
color: #FF4D6A;
|
||
}
|
||
|
||
.control-btn.increase .btn-value {
|
||
color: #1B7C5E;
|
||
}
|
||
|
||
.score-display {
|
||
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 {
|
||
font-size: 80rpx;
|
||
font-weight: 600;
|
||
color: #1B7C5E;
|
||
}
|
||
|
||
.edit-hint {
|
||
font-size: 22rpx;
|
||
color: #999999;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.judge-tip {
|
||
padding: 0 30rpx;
|
||
font-size: 24rpx;
|
||
color: #FF4D6A;
|
||
text-align: center;
|
||
line-height: 1.6;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
/* 扣分项 */
|
||
.deduction-section {
|
||
margin: 30rpx;
|
||
}
|
||
|
||
.deduction-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.deduction-label {
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.deduction-hint {
|
||
font-size: 24rpx;
|
||
color: #FF4D6A;
|
||
}
|
||
|
||
.deduction-list {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.deduction-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx;
|
||
background-color: #FFFFFF;
|
||
border-radius: 12rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.checkbox {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
border: 2rpx solid #CCCCCC;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 16rpx;
|
||
flex-shrink: 0;
|
||
background-color: #F5F5F5;
|
||
}
|
||
|
||
.checkbox.checked {
|
||
background-color: #1B7C5E;
|
||
border-color: #1B7C5E;
|
||
}
|
||
|
||
.check-icon {
|
||
color: #FFFFFF;
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.deduction-text {
|
||
font-size: 26rpx;
|
||
color: #333333;
|
||
line-height: 1.4;
|
||
flex: 1;
|
||
}
|
||
|
||
/* 备注 */
|
||
.note-section {
|
||
margin: 30rpx;
|
||
}
|
||
|
||
.note-label {
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.note-input-wrapper {
|
||
background-color: #FFFFFF;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
position: relative;
|
||
}
|
||
|
||
.note-input {
|
||
width: 100%;
|
||
min-height: 120rpx;
|
||
font-size: 28rpx;
|
||
color: #333333;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.note-input::placeholder {
|
||
color: #CCCCCC;
|
||
}
|
||
|
||
.optional-text {
|
||
position: absolute;
|
||
right: 30rpx;
|
||
bottom: 30rpx;
|
||
font-size: 24rpx;
|
||
color: #FF4D6A;
|
||
}
|
||
|
||
/* 提交按钮 */
|
||
.submit-btn {
|
||
margin: 30rpx;
|
||
height: 90rpx;
|
||
background: linear-gradient(135deg, #1B7C5E 0%, #2A9D7E 100%);
|
||
border-radius: 16rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #FFFFFF;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 8rpx 20rpx rgba(27, 124, 94, 0.3);
|
||
}
|
||
|
||
.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;
|
||
}
|
||
</style>
|