feat: 项目筛选改为横向滑动布局

- 使用 scroll-view + scroll-x 实现横向滚动
- 项目标签一行显示,超出可滑动
- 优化移动端交互体验

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
DevOps
2025-12-26 10:46:48 +08:00
parent 88a931976d
commit edd64cda47

View File

@@ -23,9 +23,9 @@
<view class="refresh-link" @click="handleRefresh">刷新</view>
</view>
<!-- 项目筛选 -->
<view class="project-row">
<view class="project-grid">
<!-- 项目筛选 - 横向滑动 -->
<scroll-view class="project-scroll" scroll-x="true" :show-scrollbar="false">
<view class="project-row">
<view
class="project-chip"
:class="{ active: index === currentProjectIndex }"
@@ -36,7 +36,7 @@
{{ project.projectName }}
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 评分统计 -->
@@ -193,7 +193,6 @@ export default {
},
async onShow() {
// 从评分详情页返回时刷新数据
if (!this.isFirstLoad) {
if (config.debug) {
console.log('页面显示,刷新数据')
@@ -232,34 +231,23 @@ export default {
},
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
},
/**
* 计算选手总分
* 规则:所有裁判评分完成后,去掉一个最高分和一个最低分,取剩余分数的平均值
* @param {Object} player - 选手对象
* @returns {Number|null} 计算后的总分,如果未完成评分返回 null
*/
calculateTotalScore(player) {
// 检查是否有裁判评分数据
if (!player.judgeScores || !Array.isArray(player.judgeScores)) {
return null
}
// 检查是否所有裁判都已评分
const totalJudges = player.totalJudges || 0
const scoredCount = player.judgeScores.length
@@ -267,34 +255,22 @@ export default {
return null
}
// 提取所有分数
const scores = player.judgeScores.map(j => parseFloat(j.score)).filter(s => !isNaN(s))
if (scores.length < 3) {
// 少于3个评分无法去掉最高最低直接取平均
if (scores.length === 0) return null
const sum = scores.reduce((a, b) => a + b, 0)
return sum / scores.length
}
// 排序
scores.sort((a, b) => a - b)
// 去掉最高分和最低分
const trimmedScores = scores.slice(1, -1)
// 计算平均分
const sum = trimmedScores.reduce((a, b) => a + b, 0)
const average = sum / trimmedScores.length
return average
},
/**
* 检查选手是否所有裁判都已评分
* @param {Object} player - 选手对象
* @returns {Boolean}
*/
isAllJudgesScored(player) {
if (!player.judgeScores || !Array.isArray(player.judgeScores)) {
return false
@@ -303,11 +279,6 @@ export default {
return totalJudges > 0 && player.judgeScores.length >= totalJudges
},
/**
* 获取选手的显示总分
* @param {Object} player - 选手对象
* @returns {String} 格式化后的总分或 '--'
*/
getDisplayTotalScore(player) {
const score = this.calculateTotalScore(player)
if (score === null) {
@@ -316,11 +287,6 @@ export default {
return score.toFixed(3)
},
/**
* 获取裁判评分进度
* @param {Object} player - 选手对象
* @returns {String} 进度字符串,如 "3/6"
*/
getJudgeProgress(player) {
const scored = player.judgeScores ? player.judgeScores.length : 0
const total = player.totalJudges || '?'
@@ -521,28 +487,30 @@ export default {
color: #4A90D9;
}
.project-row {
display: flex;
flex-direction: column;
/* ==================== 项目筛选 - 横向滑动 ==================== */
.project-scroll {
width: 100%;
white-space: nowrap;
}
.project-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
.project-row {
display: inline-flex;
flex-direction: row;
gap: 16rpx;
padding: 4rpx 0;
}
.project-chip {
padding: 20rpx 12rpx;
display: inline-block;
padding: 20rpx 32rpx;
border: 2rpx solid #1B7C5E;
border-radius: 8rpx;
font-size: 26rpx;
color: #1B7C5E;
background-color: #FFFFFF;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 0;
}
.project-chip.active {