fix: 修复UI样式和轮询逻辑问题

- 修复ActionButton禁用状态颜色错误
- 调整CompetitionLayout布局和z-index层级
- 修正analysis页面评委评分显示位置
- 优化QuestionRenderer字体大小和间距
- 改进cover页面卡片翻转动画效果
- 修复results-detail页面轮询逻辑和时间同步
This commit is contained in:
2026-04-02 15:14:50 +08:00
parent 9bc58c6270
commit a76263375a
7 changed files with 36 additions and 39 deletions

View File

@ -151,8 +151,8 @@ function handleClick() {
}
&.is-disabled {
color: #eb5e55;
filter: grayscale(0.5);
color: red;
// filter: grayscale(0.5);
opacity: 0.6;
}

View File

@ -229,12 +229,12 @@ watch(titleBgUrl, (newUrl) => {
<!-- Header -->
<header class="page-header flex items-center px-8 text-[30px] text-[#333333] font-bold">
<!-- 左侧logo -->
<div class="flex cursor-pointer items-center" @click="handleBackHome">
<div class="!z-index-99 flex cursor-pointer items-center" @click="handleBackHome">
<img :src="cqLogo" alt="重庆logo" class="h-18 w-auto">
</div>
<!-- 中间文字 -->
<div class="flex flex-1 justify-center">
<div class="!z-index-99 flex flex-1 justify-center">
<img :src="qwLogo" alt="重庆logo" class="h-14 w-auto">
</div>
@ -450,16 +450,15 @@ watch(titleBgUrl, (newUrl) => {
.page-header {
position: absolute;
top: -50px;
top: -58px;
left: 0;
width: 100%;
height: 180px;
height: 196px;
display: flex;
justify-content: space-between;
padding: 20px 44px;
font-weight: 700;
color: $secondary-color;
z-index: 10;
}
.main-content {

View File

@ -1,7 +1,7 @@
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { Icon } from '@iconify/vue'
import { useStorage } from '@vueuse/core'
import { useIntervalFn, useStorage } from '@vueuse/core'
import { NButton, NCard, NImage, NInputNumber, NTag, useMessage } from 'naive-ui'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
@ -33,6 +33,9 @@ const questionInfo = ref<Api.Competition.QuestionListDetailRound>() // 题目详
const currentQuestionDetailID = ref<number | string>('') // 当前选中的题目详情 ID
const nowTs = ref(Date.now())
useIntervalFn(() => {
nowTs.value = Date.now()
}, 1000)
// 判断当前activityId是正在比赛的活动
const isActiveActivityId = computed(() => {
if (!currentQuestion.value)
@ -254,7 +257,9 @@ async function fetchCurrentQuestion(shouldSync = true) {
return
}
currentQuestion.value = data?.data || {}
const endTime = new Date(currentQuestion.value.EndTime)
console.warn('current question', currentQuestion.value)
console.log('当前题目结束时间是:', endTime.toLocaleString())
// 只在初始化时同步选中题,轮询时不同步
if (shouldSync) {
syncCurrentQuestionSelection()
@ -466,9 +471,6 @@ async function handleNexCurrentQuestion() {
currentQuestionId.value = currentQuestion.value?.QuestionID || currentQuestionId.value
currentGroupId.value = currentQuestion.value?.TeamGroupID || currentGroupId.value
}
// 更新当前时间戳,以便重新计算 canPublish
nowTs.value = Date.now()
}
function handlePublish() {
@ -617,25 +619,23 @@ function startPolling() {
}
fetchAnswerData() // 立即获取
nowTs.value = Date.now()
pollingTimer.value = setInterval(() => {
// 每次轮询前再次检查是否过期
const currentEndTime = (currentQuestion.value as any)?.EndTime
if (currentEndTime) {
// 增加 5s 缓冲时间
const endTs = new Date(currentEndTime).getTime() + 3000
// 增加 1s 缓冲时间
const endTs = new Date(currentEndTime).getTime() + 1000
if (Date.now() > endTs) {
console.log('题目时间已到(含3s缓冲停止轮询', currentEndTime)
console.log('题目时间已到(含1s缓冲停止轮询', currentEndTime)
stopPolling()
return
}
}
nowTs.value = Date.now()
// 轮询时同时更新当前题目信息(获取最新的 EndTime但不触发同步
fetchCurrentQuestion(false)
fetchAnswerData()
}, 3000)
}, 2000)
}
function stopPolling() {

View File

@ -168,7 +168,7 @@ onBeforeUnmount(() => {
<!-- Content -->
<div class="w-full flex flex-col flex-1 overflow-hidden">
<div class="mb-2 text-xl text-red-600 font-bold">
备注评委正在评分中请等待
备注评委正在评分中请等待...
</div>
<div v-if="teams && teams.length > 0" class="grid grid-cols-4 h-full gap-6 pb-8">
@ -180,12 +180,12 @@ onBeforeUnmount(() => {
class="mb-3 flex items-center gap-2 rounded-full from-sky-300 to-cyan-200 bg-gradient-to-r px-4 py-2 shadow-sm"
>
<span class="text-lg text-white font-bold drop-shadow">{{ team.TeamName }}</span>
<span class="rounded-full bg-green-100/90 px-5 py-2 text-sm">
评委评分 <span class="text-lg text-orange-600 font-bold">{{ team.ResultPotins }}</span>
</span>
<span class="rounded-full bg-orange-100/60 px-5 py-2 text-sm">
AI评分 <span class="text-md text-orange-600 font-bold">{{ team.Points }}</span>
</span>
<span class="rounded-full bg-green-100/60 px-5 py-2 text-sm">
评委评分 <span class="text-md text-green-600 font-bold">{{ team.ResultPotins }}</span>
</span>
</div>
<!-- Answer Image Area -->

View File

@ -288,7 +288,7 @@ onMounted(async () => {
// [过冲状态]
// 飞到眼前一点点 (Z=50px)
// 角度稍微回弹 (rotateY -15deg)
transform: translate3d(0, -20px, 50px) rotateY(-15deg) rotateX(-10deg) scale(1.05);
transform: translate3d(0, -20px, 50px) rotateY(-15deg) rotateX(-10deg) scale(1.2);
}
100% {
@ -328,8 +328,8 @@ onMounted(async () => {
// [翻转状态]
// rotateY(180deg): 绕Y轴旋转180度实现翻面
// scale(1.05): 翻转同时放大1.05倍,产生"向观众逼近"的视觉冲击力
transform: rotateY(180deg) scale(1.06);
box-shadow: 0 20px 40px -5px rgba(0, 0, 0, 0.3); // [动态阴影] 翻转浮起时阴影更深、更扩散
transform: rotateY(180deg) scale(1.08);
box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.3); // [动态阴影] 翻转浮起时阴影更深、更扩散
}
}
@ -344,7 +344,7 @@ onMounted(async () => {
border-radius: 20px;
overflow: hidden;
// border: 1px solid rgba(255, 255, 255, 0.5); // 增加微妙的边框
// border: 1px solid rgba(231, 215, 144, 0.5); // 增加微妙的边框
}
// 正面(实际是卡背图案)
@ -367,7 +367,7 @@ onMounted(async () => {
// 背面(实际是内容面)
.flip-card-back {
// background-color: #fff;
transform: rotateY(180deg);
transform: rotateY(200deg);
// border: 4px solid #fff;
.card-content-design {
@ -409,7 +409,7 @@ onMounted(async () => {
// animation-delay: 0.2s; 确保卡片翻转到一半(正对屏幕)时才开始闪光,
// 模拟光线随着角度变化掠过卡片表面的物理效果
animation: shine-sweep 3s ease-out forwards;
animation-delay: 0.2s;
animation-delay: 1s;
}
}
@ -455,14 +455,14 @@ onMounted(async () => {
10% {
// 刚进入时瞬间变亮
opacity: 0.8;
opacity: 0.8; // 0.8 是一个半透明值,模拟光束的透明度,值越大越透明
}
100% {
// 扫出视野
top: 50%;
left: 150%;
opacity: 0;
opacity: 0.6;
}
}

View File

@ -185,7 +185,7 @@ watch(
>
<!-- 上方词组 -->
<div class="flex flex-wrap justify-center gap-4">
<div v-for="(word, index) in associationWords" :key="`word-${index}`" class="association-word text-bold">
<div v-for="(word, index) in associationWords" :key="`word-${index}`" class="association-word text-bold text-center text-3xl">
{{ word }}
</div>
</div>
@ -215,9 +215,9 @@ watch(
</div>
</div>
<!-- 模板: 诗词常识 -->
<!-- 模板: 加时赛诗词常识 -->
<div v-else-if="template === QuestionCategoryEnum.PoetryCommonKnowledge" class="w-full flex flex-col items-center">
<div class="mb-1 p-16 text-3xl text-gray-800 font-bold leading-relaxed line-height-20">
<div class="line-height mb-1 p-16 text-3xl text-gray-800 font-bold leading-relaxed">
<div class="rich-content" v-html="content" />
</div>
</div>
@ -445,8 +445,7 @@ watch(
:deep(p),
:deep(span),
:deep(div) {
font-size: 2.2rem;
/* text-5xl */
font-size: 2rem;
}
}
@ -494,15 +493,14 @@ watch(
.association-word {
background: url('@/assets/imgs/user/dui-kuang.png') no-repeat center;
background-size: 100% 100%;
min-width: 160px;
min-width: 170px;
height: 70px;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
font-weight: bold;
color: white;
padding: 0 20px;
letter-spacing: 0.2em;
}
.association-char {

View File

@ -157,13 +157,13 @@ function rowClassName(row: TeamData) {
<template>
<CompetitionLayout :show-back="false" :show-next="false" :show-title="false">
<div class="leaderboard-container h-100%">
<div class="leaderboard-header">
<div class="leaderboard-header !z-index-99">
<NImage :src="title" alt="logo" preview-disabled class="mt--42px" object-fit="contain" />
<!-- <p class="mt--16px text-center text-18px text-#6b778d">
"勤学如春起之苗,不见其增,日有所长"
</p> -->
<ActionButton
v-if="hasExtraTimeBtn" class="z-index-99 position-absolute right-20px top-20px" type="text"
v-if="hasExtraTimeBtn" class="!z-index-100 position-absolute right-20px top-20px" type="text"
text="加时赛" @click="handleAddTime"
/>
</div>