763 lines
17 KiB
Vue
763 lines
17 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-header">
|
||
<view class="player-name">{{ athleteInfo.name }}</view>
|
||
<view class="total-score-label">
|
||
<text class="label-text">总分:</text>
|
||
<text class="score-value">{{ athleteInfo.totalScore }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="player-details">
|
||
<view class="detail-item">身份证:{{ athleteInfo.idCard }}</view>
|
||
<view class="detail-item">队伍:{{ athleteInfo.team }}</view>
|
||
<view class="detail-item">编号:{{ athleteInfo.number }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 评委评分统计 -->
|
||
<view class="judges-section">
|
||
<view class="section-title">共有{{ judgeScores.length }}位评委完成评分</view>
|
||
<view class="judges-scores">
|
||
<view
|
||
class="judge-score-item"
|
||
v-for="judge in judgeScores"
|
||
:key="judge.judgeId"
|
||
>
|
||
<text class="judge-name">{{ judge.judgeName }}:</text>
|
||
<text class="judge-score">{{ judge.score }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 修改总分区域 -->
|
||
<view class="modify-section">
|
||
<view class="modify-header">
|
||
<text class="modify-label">修改总分(+-0.005分)</text>
|
||
</view>
|
||
|
||
<view class="score-control">
|
||
<!-- 减分按钮 - 使用 catchtouchstart 阻止事件冒泡 -->
|
||
<view
|
||
class="control-btn decrease"
|
||
@touchstart="onDecreaseStart"
|
||
@touchend="onDecreaseEnd"
|
||
@touchcancel="onTouchCancel"
|
||
>
|
||
<text class="btn-symbol">-</text>
|
||
<text class="btn-value">-0.001</text>
|
||
</view>
|
||
|
||
<view class="score-display">
|
||
<text class="current-score">{{ currentScore.toFixed(3) }}</text>
|
||
<text class="no-modify-text">可不改</text>
|
||
</view>
|
||
|
||
<!-- 加分按钮 - 使用 catchtouchstart 阻止事件冒泡 -->
|
||
<view
|
||
class="control-btn increase"
|
||
@touchstart="onIncreaseStart"
|
||
@touchend="onIncreaseEnd"
|
||
@touchcancel="onTouchCancel"
|
||
>
|
||
<text class="btn-symbol">+</text>
|
||
<text class="btn-value">+0.001</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"
|
||
/>
|
||
<text class="optional-text">可不填</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 修改按钮 -->
|
||
<button class="modify-btn" @click="handleModify">修改</button>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import dataAdapter from '@/utils/dataAdapter.js'
|
||
import config from '@/config/env.config.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
athleteInfo: {
|
||
athleteId: '',
|
||
name: '',
|
||
idCard: '',
|
||
team: '',
|
||
number: '',
|
||
totalScore: 0
|
||
},
|
||
judgeScores: [],
|
||
modification: null,
|
||
modifierId: '',
|
||
currentScore: 8.000,
|
||
originalScore: 8.000,
|
||
note: '',
|
||
minScore: 5.0,
|
||
maxScore: 10.0,
|
||
// 防止双击的状态管理
|
||
isTouching: false,
|
||
touchTimer: null,
|
||
lastTouchTime: 0,
|
||
// 长按相关
|
||
longPressTimer: null,
|
||
longPressInterval: null,
|
||
isLongPressing: false
|
||
}
|
||
},
|
||
|
||
async onLoad() {
|
||
// 获取全局数据
|
||
const app = getApp()
|
||
const globalData = app.globalData || {}
|
||
|
||
// 获取当前选手信息(从 score-list-multi 页面传递)
|
||
const currentAthlete = globalData.currentAthlete ||
|
||
|
||
// 获取裁判长ID
|
||
this.modifierId = globalData.judgeId
|
||
|
||
// 调试信息
|
||
if (config.debug) {
|
||
console.log('修改评分页加载:', {
|
||
athleteId: currentAthlete.athleteId,
|
||
modifierId: this.modifierId
|
||
})
|
||
}
|
||
|
||
// 加载选手评分详情
|
||
if (currentAthlete.athleteId) {
|
||
await this.loadScoreDetail(currentAthlete.athleteId)
|
||
}
|
||
|
||
// H5 平台特殊处理:禁用双击缩放
|
||
// #ifdef H5
|
||
this.disableDoubleTapZoom()
|
||
// #endif
|
||
},
|
||
|
||
onUnload() {
|
||
// 清理定时器
|
||
this.clearAllTimers()
|
||
},
|
||
|
||
methods: {
|
||
// #ifdef H5
|
||
disableDoubleTapZoom() {
|
||
// 在 H5 环境下,添加额外的事件监听来防止双击缩放
|
||
this.$nextTick(() => {
|
||
const decreaseBtn = document.querySelector('.control-btn.decrease')
|
||
const increaseBtn = document.querySelector('.control-btn.increase')
|
||
|
||
const preventZoom = (e) => {
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
e.stopImmediatePropagation()
|
||
return false
|
||
}
|
||
|
||
if (decreaseBtn) {
|
||
decreaseBtn.addEventListener('touchstart', preventZoom, { passive: false, capture: true })
|
||
decreaseBtn.addEventListener('touchend', preventZoom, { passive: false, capture: true })
|
||
decreaseBtn.addEventListener('touchmove', preventZoom, { passive: false, capture: true })
|
||
decreaseBtn.addEventListener('click', preventZoom, { passive: false, capture: true })
|
||
}
|
||
|
||
if (increaseBtn) {
|
||
increaseBtn.addEventListener('touchstart', preventZoom, { passive: false, capture: true })
|
||
increaseBtn.addEventListener('touchend', preventZoom, { passive: false, capture: true })
|
||
increaseBtn.addEventListener('touchmove', preventZoom, { passive: false, capture: true })
|
||
increaseBtn.addEventListener('click', preventZoom, { passive: false, capture: true })
|
||
}
|
||
})
|
||
},
|
||
// #endif
|
||
|
||
clearAllTimers() {
|
||
if (this.touchTimer) {
|
||
clearTimeout(this.touchTimer)
|
||
this.touchTimer = null
|
||
}
|
||
if (this.longPressTimer) {
|
||
clearTimeout(this.longPressTimer)
|
||
this.longPressTimer = null
|
||
}
|
||
if (this.longPressInterval) {
|
||
clearInterval(this.longPressInterval)
|
||
this.longPressInterval = null
|
||
}
|
||
},
|
||
|
||
// 减分按钮 - touchstart
|
||
onDecreaseStart(e) {
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
|
||
const now = Date.now()
|
||
|
||
// 防止快速连续触摸(300ms内的触摸被忽略)
|
||
if (now - this.lastTouchTime < 300) {
|
||
return
|
||
}
|
||
|
||
this.lastTouchTime = now
|
||
this.isTouching = true
|
||
|
||
// 立即执行一次减分
|
||
this.decreaseScore()
|
||
|
||
// 设置长按定时器(500ms后开始连续减分)
|
||
this.longPressTimer = setTimeout(() => {
|
||
this.isLongPressing = true
|
||
// 每100ms执行一次减分
|
||
this.longPressInterval = setInterval(() => {
|
||
this.decreaseScore()
|
||
}, 100)
|
||
}, 500)
|
||
},
|
||
|
||
// 减分按钮 - touchend
|
||
onDecreaseEnd(e) {
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
|
||
this.isTouching = false
|
||
this.isLongPressing = false
|
||
this.clearAllTimers()
|
||
},
|
||
|
||
// 加分按钮 - touchstart
|
||
onIncreaseStart(e) {
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
|
||
const now = Date.now()
|
||
|
||
// 防止快速连续触摸(300ms内的触摸被忽略)
|
||
if (now - this.lastTouchTime < 300) {
|
||
return
|
||
}
|
||
|
||
this.lastTouchTime = now
|
||
this.isTouching = true
|
||
|
||
// 立即执行一次加分
|
||
this.increaseScore()
|
||
|
||
// 设置长按定时器(500ms后开始连续加分)
|
||
this.longPressTimer = setTimeout(() => {
|
||
this.isLongPressing = true
|
||
// 每100ms执行一次加分
|
||
this.longPressInterval = setInterval(() => {
|
||
this.increaseScore()
|
||
}, 100)
|
||
}, 500)
|
||
},
|
||
|
||
// 加分按钮 - touchend
|
||
onIncreaseEnd(e) {
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
|
||
this.isTouching = false
|
||
this.isLongPressing = false
|
||
this.clearAllTimers()
|
||
},
|
||
|
||
// 触摸取消
|
||
onTouchCancel(e) {
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
|
||
this.isTouching = false
|
||
this.isLongPressing = false
|
||
this.clearAllTimers()
|
||
},
|
||
|
||
async loadScoreDetail(athleteId) {
|
||
try {
|
||
uni.showLoading({
|
||
title: '加载中...',
|
||
mask: true
|
||
})
|
||
|
||
const response = await dataAdapter.getData('getScoreDetail', {
|
||
athleteId: athleteId
|
||
})
|
||
|
||
uni.hideLoading()
|
||
|
||
// 保存选手信息和评分详情
|
||
this.athleteInfo = response.data.athleteInfo || {}
|
||
this.judgeScores = response.data.judgeScores || []
|
||
this.modification = response.data.modification || null
|
||
|
||
// 设置初始分数
|
||
this.originalScore = this.athleteInfo.totalScore || 8.000
|
||
this.currentScore = this.originalScore
|
||
|
||
// 如果之前已修改过,加载修改后的分数
|
||
if (this.modification && this.modification.modifiedScore) {
|
||
this.currentScore = this.modification.modifiedScore
|
||
}
|
||
|
||
// 调试信息
|
||
if (config.debug) {
|
||
console.log('评分详情加载成功:', {
|
||
athlete: this.athleteInfo,
|
||
judges: this.judgeScores.length,
|
||
originalScore: this.originalScore,
|
||
currentScore: this.currentScore,
|
||
modification: this.modification
|
||
})
|
||
}
|
||
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
console.error('加载评分详情失败:', error)
|
||
uni.showToast({
|
||
title: error.message || '加载失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
goBack() {
|
||
uni.navigateBack()
|
||
},
|
||
|
||
decreaseScore() {
|
||
if (this.currentScore > this.minScore) {
|
||
this.currentScore = parseFloat((this.currentScore - 0.001).toFixed(3))
|
||
|
||
// 添加触觉反馈(仅在支持的平台)
|
||
// #ifndef H5
|
||
uni.vibrateShort({
|
||
type: 'light'
|
||
})
|
||
// #endif
|
||
}
|
||
},
|
||
|
||
increaseScore() {
|
||
if (this.currentScore < this.maxScore) {
|
||
this.currentScore = parseFloat((this.currentScore + 0.001).toFixed(3))
|
||
|
||
// 添加触觉反馈(仅在支持的平台)
|
||
// #ifndef H5
|
||
uni.vibrateShort({
|
||
type: 'light'
|
||
})
|
||
// #endif
|
||
}
|
||
},
|
||
|
||
async handleModify() {
|
||
// 验证评分范围
|
||
if (this.currentScore < this.minScore || this.currentScore > this.maxScore) {
|
||
uni.showToast({
|
||
title: `评分必须在${this.minScore}-${this.maxScore}分之间`,
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 检查是否有修改
|
||
if (this.currentScore === this.originalScore && !this.note) {
|
||
uni.showToast({
|
||
title: '请修改分数或填写备注',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
try {
|
||
uni.showLoading({
|
||
title: '提交中...',
|
||
mask: true
|
||
})
|
||
|
||
// 获取场地ID
|
||
const app = getApp()
|
||
const venueId = app.globalData?.currentVenueId
|
||
|
||
const response = await dataAdapter.getData('modifyScore', {
|
||
athleteId: this.athleteInfo.athleteId,
|
||
modifierId: this.modifierId,
|
||
modifiedScore: this.currentScore,
|
||
note: this.note,
|
||
venueId: venueId // 添加场地ID
|
||
})
|
||
|
||
uni.hideLoading()
|
||
|
||
// 调试信息
|
||
if (config.debug) {
|
||
console.log('修改评分成功:', {
|
||
athleteId: this.athleteInfo.athleteId,
|
||
originalScore: this.originalScore,
|
||
modifiedScore: this.currentScore,
|
||
note: this.note,
|
||
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: 30rpx;
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.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;
|
||
background-color: #FFFFFF;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
.player-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.player-name {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
color: #333333;
|
||
}
|
||
|
||
.total-score-label {
|
||
display: flex;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.label-text {
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
}
|
||
|
||
.score-value {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #333333;
|
||
margin-left: 8rpx;
|
||
}
|
||
|
||
.player-details {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.detail-item {
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* 评委评分统计 */
|
||
.judges-section {
|
||
margin: 30rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #333333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.judges-scores {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.judge-score-item {
|
||
font-size: 26rpx;
|
||
color: #333333;
|
||
}
|
||
|
||
.judge-name {
|
||
color: #666666;
|
||
}
|
||
|
||
.judge-score {
|
||
color: #333333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 修改总分区域 */
|
||
.modify-section {
|
||
margin: 30rpx;
|
||
background-color: #FFFFFF;
|
||
border-radius: 16rpx;
|
||
padding: 40rpx 30rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
.modify-header {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.modify-label {
|
||
font-size: 28rpx;
|
||
color: #666666;
|
||
}
|
||
|
||
.score-control {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.control-btn {
|
||
width: 140rpx;
|
||
height: 140rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 12rpx;
|
||
cursor: pointer;
|
||
position: relative;
|
||
|
||
/* 关键:禁用所有可能导致缩放的触摸行为 */
|
||
touch-action: none;
|
||
-webkit-tap-highlight-color: transparent;
|
||
-webkit-touch-callout: none;
|
||
-webkit-user-select: none;
|
||
user-select: none;
|
||
}
|
||
|
||
.control-btn.decrease {
|
||
background-color: #FFE5E5;
|
||
}
|
||
|
||
.control-btn.increase {
|
||
background-color: #E5F5F0;
|
||
}
|
||
|
||
.btn-symbol {
|
||
font-size: 48rpx;
|
||
font-weight: 300;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.control-btn.decrease .btn-symbol {
|
||
color: #FF4D6A;
|
||
}
|
||
|
||
.control-btn.increase .btn-symbol {
|
||
color: #1B7C5E;
|
||
}
|
||
|
||
.btn-value {
|
||
font-size: 24rpx;
|
||
margin-top: 8rpx;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.control-btn.decrease .btn-value {
|
||
color: #FF4D6A;
|
||
}
|
||
|
||
.control-btn.increase .btn-value {
|
||
color: #1B7C5E;
|
||
}
|
||
|
||
.score-display {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.current-score {
|
||
font-size: 60rpx;
|
||
font-weight: 600;
|
||
color: #1B7C5E;
|
||
}
|
||
|
||
.no-modify-text {
|
||
font-size: 24rpx;
|
||
color: #FF4D6A;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
/* 备注 */
|
||
.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;
|
||
}
|
||
|
||
/* 修改按钮 */
|
||
.modify-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);
|
||
}
|
||
|
||
.modify-btn:active {
|
||
opacity: 0.9;
|
||
}
|
||
</style>
|