feat: 添加排行榜分数编辑和题目详情展示功能

- 在排行榜详情页中,添加队伍题目分数编辑功能,支持批量保存
- 新增打字机组件用于题目答案的动态展示
- 优化游戏页面的答题数量统计逻辑,使用 UserAnswerFont 解析
- 更新题目导入工具,支持更多 JSON 格式
- 调整游戏倒计时逻辑,优先使用题目详情中的时间
- 移除排行榜中的部分冗余列,优化界面显示
This commit is contained in:
2026-03-05 18:08:17 +08:00
parent ed3c815cd7
commit e8cd6732d7
29 changed files with 1879 additions and 1238 deletions

View File

@ -20,7 +20,7 @@ const currentQuestionDetail = computed(() => store.currentQuestionDetail)
const TeamGroup_QuestionID = computed(() => currentQuestionMainInfo.value?.TeamGroup_QuestionID || 0)
const QuestionID = computed(() => currentQuestionMainInfo.value?.Activity_Question.ID || 0)
const QuestionDetaiID = computed(() => currentQuestionDetail.value?.Id || 0)
const QuestionDetailID = computed(() => currentQuestionDetail.value?.Id || 0)
const zoomedImage = ref<string | null>(null)
const isCompleted = ref(false)
@ -123,7 +123,7 @@ async function fetchGetGameStatisticsData() {
const _params = {
TeamGroupID: Number(groupsId.value),
QuestionID: Number(QuestionID.value),
QuestionDetaiID: Number(QuestionDetaiID.value),
QuestionDetaiID: Number(QuestionDetailID.value),
}
const { data } = await fetchGetGameStatistics(_params)
teams.value = (data?.data as any[]) || []

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { computed, onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
import { useRouterPush } from '@/hooks/common/router'
@ -28,10 +28,12 @@ const activityName = computed(() => activityInfo.value?.ActivityTitle || '星·
const flippedCards = ref<Set<number>>(new Set())
// 计算是否所有卡片都已翻转 (当前显示4张卡片)
// eslint-disable-next-line unused-imports/no-unused-vars
const isAllFlipped = computed(() => flippedCards.value.size === questions.value.length)
// 控制下一步按钮的显示(带延迟)
const showNextButton = ref(false)
const showNextButton = ref(true)
// eslint-disable-next-line prefer-const, unused-imports/no-unused-vars
let timer: ReturnType<typeof setTimeout> | null = null
// 获取路由参数
@ -70,22 +72,22 @@ async function getQuestions() {
loading.value = false
}
}
// 测试先注释掉
// watch(isAllFlipped, (val) => {
// if (timer) {
// clearTimeout(timer)
// timer = null
// }
watch(isAllFlipped, (val) => {
if (timer) {
clearTimeout(timer)
timer = null
}
if (val) {
timer = setTimeout(() => {
showNextButton.value = true
}, 1500)
}
else {
showNextButton.value = false
}
})
// if (val) {
// timer = setTimeout(() => {
// showNextButton.value = true
// }, 1500)
// }
// else {
// showNextButton.value = false
// }
// })
function handleBack() {
routerBack()

View File

@ -130,7 +130,15 @@ async function handleNext() {
// 点击开始答题
if (!isStarted.value) {
isStarted.value = true
store.startTimer(store.currentQuestionInfo?.QuestionTime || 10)
// 获取题目时间,优先从 currentQuestionInfo 获取,兼容大小写
// 并在获取失败时尝试从 detail 获取(如果后端在详情接口也返回了时间)
const infoTime = store.currentQuestionInfo?.QuestionTime || (store.currentQuestionInfo as any)?.questionTime
const detailTime = (store.currentQuestionDetail as any)?.QuestionTime || (store.currentQuestionDetail as any)?.questionTime
const duration = Number(infoTime || detailTime || 120) // 默认值改为 120s 或者保持 10s用户说是 120s
console.log('开始倒计时,时长:', duration, 'InfoTime:', infoTime, 'DetailTime:', detailTime)
store.startTimer(duration)
// 提交题目使用记录
try {
@ -207,10 +215,34 @@ async function fetchGetGameStatisticsData(_params: Api.Competition.QuestionAddPa
// 使用 Map 去重,以 TeamId 为准,保留最新的状态
const teamMap = new Map()
list.forEach((item) => {
let answerCount = 0
try {
if (item.UserAnswerFont) {
const parsed = JSON.parse(item.UserAnswerFont)
if (Array.isArray(parsed) && parsed.length > 0) {
// 如果 AnswerText 存在,取其长度;否则(如选择题)如果对象存在则算 1 个
// 逻辑:如果是填空/听写类AnswerText 是字符串,取长度?
// 根据需求:答题数量用 UserAnswerFont 里面 AnswerText 字段的 length 长度
// 注意AnswerText 可能是 "B" (选择题) 或 "汉字" (听写)
// 如果是数组,是否需要累加所有项的 AnswerText 长度?
// 假设 UserAnswerFont 是一个数组 [{"AnswerText": "..."}]
// 这里我们遍历数组累加长度
parsed.forEach((p: any) => {
if (p.AnswerText) {
answerCount += String(p.AnswerText).length
}
})
}
}
}
catch (e) {
console.error('解析 UserAnswerFont 失败', e)
}
teamMap.set(item.TeamName, {
group: item.TeamName || '未知队伍',
total: item.Points || 0,
correct: item.ResultPotins || 0,
total: answerCount, // 答题数量
correct: item.Points || 0, // 预估得分 (使用外层 Points)
})
})
chartData.value = Array.from(teamMap.values())

View File

@ -30,7 +30,7 @@ function buildOption(list: BarDatum[]): ECOption {
axisPointer: { type: 'shadow' },
},
legend: {
data: ['答题数量', '正确数量'],
data: ['答题数量', '预估得分'],
top: 0,
right: 0,
icon: 'circle',