feat: 优化竞赛流程并修复题目禁用功能
- 调整倒计时音效触发时间为剩余10秒,并更新音频文件 - 修复题目禁用功能,将IsDisabled类型从number改为boolean - 优化抽题页面,替换为静态图片并禁用放大预览 - 为卡片添加3D悬停效果,提升交互体验 - 在结果发布前检查倒计时是否结束,防止提前发布 - 优化团队选择页面样式,更新图标和背景 - 修复Typewriter组件内容重复累加的问题 - 更新图表标签从"正确数量"改为"预估得分" - 优化竞赛布局,统一"下一步"按钮文本
BIN
apps/admin/src/assets/audio/boy-10s.mp3
Normal file
BIN
apps/admin/src/assets/audio/girl-10.mp3
Normal file
BIN
apps/admin/src/assets/audio/start3.mp3
Normal file
BIN
apps/admin/src/assets/audio/system-10.mp3
Normal file
26
apps/admin/src/assets/imgs/user/draw.svg
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
41
apps/admin/src/assets/imgs/user/g1.svg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
30
apps/admin/src/assets/imgs/user/g2.svg
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 5.2 MiB After Width: | Height: | Size: 10 MiB |
14
apps/admin/src/assets/imgs/user/team-title-bg.svg
Normal file
|
After Width: | Height: | Size: 4.0 MiB |
48
apps/admin/src/assets/imgs/user/team-title-icon.svg
Normal file
|
After Width: | Height: | Size: 5.5 MiB |
|
Before Width: | Height: | Size: 4.0 MiB After Width: | Height: | Size: 3.0 MiB |
@ -112,6 +112,7 @@ export function fetchUpdateQuestionLibrary(params: Api.Question.AddQuestionLibra
|
||||
Type: params.type,
|
||||
IsGood: params.IsGood,
|
||||
ImageUrl: params.imageUrl,
|
||||
IsDisabled: params.IsDisabled,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -93,9 +93,9 @@ export const useCompetitionStore = defineStore('competition', () => {
|
||||
timerInterval.value = window.setInterval(() => {
|
||||
if (timeLeft.value > 0) {
|
||||
timeLeft.value--
|
||||
// 剩余5秒播放倒计时音效
|
||||
if (timeLeft.value <= 5) {
|
||||
audioController.play('tick')
|
||||
// 剩余10秒播放倒计时音效
|
||||
if (timeLeft.value <= 10) {
|
||||
audioController.play('tick10')
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
4
apps/admin/src/typings/api/question.d.ts
vendored
@ -68,8 +68,8 @@ declare namespace Api {
|
||||
type: QuestionScoreType
|
||||
/** is priority 0: no 1: yes */
|
||||
IsGood: number
|
||||
/** is disabled 0: no 1: yes */
|
||||
IsDisabled: number
|
||||
/** is disabled */
|
||||
IsDisabled: boolean
|
||||
}
|
||||
|
||||
/** common search params of table */
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
import system10 from '@/assets/audio/boy-10s.mp3'
|
||||
|
||||
export class AudioController {
|
||||
private audioContext: AudioContext | null = null
|
||||
private soundFiles: Record<string, string> = {}
|
||||
private audioCache: Record<string, HTMLAudioElement> = {}
|
||||
|
||||
constructor(soundFiles: Record<string, string> = {}) {
|
||||
this.soundFiles = soundFiles
|
||||
this.soundFiles = {
|
||||
tick10: system10,
|
||||
...soundFiles,
|
||||
}
|
||||
}
|
||||
|
||||
private initAudioContext() {
|
||||
@ -17,7 +22,7 @@ export class AudioController {
|
||||
* 播放指定类型的音效
|
||||
* 优先使用预设的音频文件,如果没有配置或加载失败,则使用 Web Audio API 合成音效
|
||||
*/
|
||||
async play(type: 'start' | 'tick' | 'flip') {
|
||||
async play(type: 'start' | 'tick10' | 'flip') {
|
||||
// 尝试播放音频文件
|
||||
if (this.soundFiles[type]) {
|
||||
try {
|
||||
@ -54,7 +59,7 @@ export class AudioController {
|
||||
})
|
||||
}
|
||||
|
||||
private playSynth(type: 'start' | 'tick' | 'flip') {
|
||||
private playSynth(type: 'start' | 'tick10' | 'flip') {
|
||||
this.initAudioContext()
|
||||
if (!this.audioContext)
|
||||
return
|
||||
@ -75,7 +80,7 @@ export class AudioController {
|
||||
osc.start(ctxTime)
|
||||
osc.stop(ctxTime + 0.3)
|
||||
}
|
||||
else if (type === 'tick') {
|
||||
else if (type === 'tick10') {
|
||||
const osc = this.audioContext.createOscillator()
|
||||
osc.connect(gain)
|
||||
// 倒计时音效:急促的滴答声
|
||||
|
||||
@ -113,7 +113,7 @@ const questionForm = ref({
|
||||
type: QuestionType.SingleChoice as QuestionType | number, // 题目类型
|
||||
imageUrl: '',
|
||||
IsGood: 0,
|
||||
IsDisabled: 0,
|
||||
IsDisabled: false,
|
||||
})
|
||||
|
||||
const fileList = ref<UploadFileInfo[]>([])
|
||||
@ -185,6 +185,7 @@ async function handleBatchDisable(disabled: boolean) {
|
||||
}
|
||||
|
||||
const payload = selectedQuestionIds.value.map(id => ({
|
||||
id,
|
||||
Id: id,
|
||||
IsDisabled: disabled,
|
||||
}))
|
||||
@ -266,7 +267,7 @@ function handleAddQuestion() {
|
||||
type: props.currentCategory?.QuestionType || QuestionType.SingleChoice,
|
||||
imageUrl: '',
|
||||
IsGood: 0,
|
||||
IsDisabled: 0,
|
||||
IsDisabled: false,
|
||||
}
|
||||
fileList.value = []
|
||||
showQuestionModal.value = true
|
||||
@ -291,7 +292,7 @@ function handleEditQuestion(id: number) {
|
||||
type: question.Type,
|
||||
imageUrl: question.ImageUrl || '',
|
||||
IsGood: question.IsPriority || 0,
|
||||
IsDisabled: question.IsDisabled || 0,
|
||||
IsDisabled: !!question.IsDisabled,
|
||||
}
|
||||
fileList.value = []
|
||||
if (question.ImageUrl) {
|
||||
@ -344,6 +345,7 @@ async function submitQuestion() {
|
||||
type: questionForm.value.type as any,
|
||||
questionId: props.currentCategory.Id,
|
||||
IsGood: questionForm.value.IsGood,
|
||||
// 传给后端为 boolean
|
||||
IsDisabled: questionForm.value.IsDisabled,
|
||||
}
|
||||
|
||||
@ -616,10 +618,10 @@ async function submitQuestion() {
|
||||
<!-- 是否禁用 -->
|
||||
<NFormItem label="是否禁用" path="IsDisabled">
|
||||
<NRadioGroup v-model:value="questionForm.IsDisabled">
|
||||
<NRadio :value="0">
|
||||
<NRadio :value="false">
|
||||
否
|
||||
</NRadio>
|
||||
<NRadio :value="1">
|
||||
<NRadio :value="true">
|
||||
是
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
|
||||
@ -282,7 +282,7 @@ async function fetchAnswerData() {
|
||||
|
||||
// 假设返回的数据结构是数组,取第一条或者根据逻辑取特定的一条
|
||||
const result = data?.data || []
|
||||
console.log('接口返回的游戏统计数据:', result)
|
||||
// console.log('接口返回的游戏统计数据:', result)
|
||||
|
||||
// 获取题目详情 ID
|
||||
let detailId = 0
|
||||
@ -364,24 +364,11 @@ async function fetchAnswerData() {
|
||||
// 优先使用 ans 中的图片,如果没有则回退到 answerData 中的图片
|
||||
const imageUrl = ans.AnswerValuePicture || (parsedAnswers.length === 1 && parsedAnswers[0] === ans ? answerData.UserAnswerPicture : '')
|
||||
let finalImageUrl = imageUrl
|
||||
let cleanBaseUrl = ''
|
||||
let timestamp = new Date().getTime()
|
||||
const cleanBaseUrl = ''
|
||||
const timestamp = new Date().getTime()
|
||||
|
||||
if (imageUrl) {
|
||||
// 清理 URL 中的反引号、引号和空格
|
||||
cleanBaseUrl = imageUrl.replace(/[`'"]/g, '').trim()
|
||||
|
||||
// 尝试复用旧的时间戳以防止闪烁
|
||||
// 只有当 URL 发生变化,或者 AI 状态/分数发生变化时才更新时间戳
|
||||
// 注意:如果 ans.AnswerValuePicture 发生了变化(即使只是参数变化),cleanBaseUrl 会变
|
||||
if (oldAns && oldAns._baseImgUrl === cleanBaseUrl && oldAns._aiStatus === aiStatus && oldAns._aiScore === aiScore && oldAns._t) {
|
||||
timestamp = oldAns._t
|
||||
}
|
||||
|
||||
// 强制刷新:每次都添加新的时间戳
|
||||
const separator = cleanBaseUrl.includes('?') ? '&' : '?'
|
||||
finalImageUrl = `${cleanBaseUrl}${separator}_t=${timestamp}`
|
||||
}
|
||||
finalImageUrl = `${finalImageUrl}?_t=${timestamp}`
|
||||
console.log(finalImageUrl, 'finalImageUrl')
|
||||
|
||||
// 判断是否手动干预:
|
||||
// 1. 本地存储有状态 (hasStoredStatus) 或有分数 (hasStoredScore)
|
||||
@ -479,6 +466,11 @@ async function handleNexCurrentQuestion() {
|
||||
}
|
||||
|
||||
function handlePublish() {
|
||||
const endTimeStr = (currentQuestion.value as any)?.EndTime
|
||||
if (endTimeStr && Date.now() < new Date(endTimeStr).getTime()) {
|
||||
window.$message?.warning('倒计时未结束,暂不能发布')
|
||||
return
|
||||
}
|
||||
if (currentQuestion.value?.TeamGroupQuestionID) {
|
||||
// 检查是否有未评分的题目
|
||||
let hasUnrated = false
|
||||
@ -586,6 +578,14 @@ function handlePublish() {
|
||||
* 消费并发布当前题目
|
||||
*/
|
||||
const pollingTimer = ref<NodeJS.Timeout | null>(null)
|
||||
const nowTs = ref(Date.now())
|
||||
const canPublish = computed(() => {
|
||||
const endTime = (currentQuestion.value as any)?.EndTime
|
||||
if (!endTime)
|
||||
return false
|
||||
const end = new Date(endTime).getTime()
|
||||
return nowTs.value >= end
|
||||
})
|
||||
|
||||
function startPolling() {
|
||||
stopPolling()
|
||||
@ -611,6 +611,7 @@ function startPolling() {
|
||||
}
|
||||
|
||||
fetchAnswerData() // 立即获取
|
||||
nowTs.value = Date.now()
|
||||
pollingTimer.value = setInterval(() => {
|
||||
// 每次轮询前再次检查是否过期
|
||||
const currentEndTime = (currentQuestion.value as any)?.EndTime
|
||||
@ -623,6 +624,7 @@ function startPolling() {
|
||||
return
|
||||
}
|
||||
}
|
||||
nowTs.value = Date.now()
|
||||
fetchAnswerData()
|
||||
}, 3000)
|
||||
}
|
||||
@ -714,7 +716,7 @@ onUnmounted(() => {
|
||||
<NButton secondary strong @click="handleNext">
|
||||
下一题
|
||||
</NButton>
|
||||
<NButton type="tertiary" strong class="px-6" @click="handlePublish">
|
||||
<NButton type="tertiary" strong class="px-6" :disabled="!canPublish" @click="handlePublish">
|
||||
发布结果
|
||||
</NButton>
|
||||
</div>
|
||||
@ -776,7 +778,7 @@ onUnmounted(() => {
|
||||
!item._isManual ? 'border-gray-300 bg-gray-50/30' : (item.Status === 1 ? 'border-green-500 bg-green-50/30' : 'border-red-500 bg-red-50/30'),
|
||||
]"
|
||||
>
|
||||
<div v-if="item.AnswerText" class="text-lg text-gray-800 font-bold">
|
||||
<div v-if="item.AnswerText" class="border-b border-gray-200 pb-2 text-lg text-gray-800 font-bold">
|
||||
<span> 由 ai识别出的答题文本:</span>
|
||||
<Typewriter :text="item.AnswerText" />
|
||||
</div>
|
||||
|
||||
@ -17,6 +17,11 @@ function init() {
|
||||
typeItInstance.destroy()
|
||||
}
|
||||
|
||||
// 清空上一次的内容,避免重复累加显示
|
||||
if (textRef.value) {
|
||||
textRef.value.textContent = ''
|
||||
}
|
||||
|
||||
const options: Options = {
|
||||
strings: props.text || '',
|
||||
lifeLike: true,
|
||||
|
||||
@ -128,8 +128,10 @@ function toggleFlip(index: number) {
|
||||
}
|
||||
else {
|
||||
flippedCards.value.add(index)
|
||||
audioController.play('flip') // 播放翻牌音效
|
||||
audioController.play('flip') // 翻牌动效
|
||||
}
|
||||
// 每次点击都播放翻牌音效(无论翻开还是翻回去)
|
||||
// audioController.play('flip')
|
||||
}
|
||||
|
||||
async function initSyncRouteParams() {
|
||||
@ -148,6 +150,39 @@ async function initSyncRouteParams() {
|
||||
|
||||
const showCards = ref(false)
|
||||
|
||||
// 3D 悬停效果逻辑
|
||||
const cardStyles = ref<Record<number, any>>({})
|
||||
|
||||
function handleMouseMove(e: MouseEvent, index: number) {
|
||||
const card = e.currentTarget as HTMLElement
|
||||
const rect = card.getBoundingClientRect()
|
||||
const x = e.clientX - rect.left
|
||||
const y = e.clientY - rect.top
|
||||
const centerX = rect.width / 2
|
||||
const centerY = rect.height / 2
|
||||
|
||||
// 计算旋转角度
|
||||
// 鼠标在上方(y < centerY) -> rotateX > 0 (上半部分凸起)
|
||||
// 鼠标在下方(y > centerY) -> rotateX < 0 (下半部分凸起)
|
||||
const rotateX = ((centerY - y) / centerY) * 10
|
||||
|
||||
// 鼠标在左方(x < centerX) -> rotateY < 0 (左半部分凸起)
|
||||
// 鼠标在右方(x > centerX) -> rotateY > 0 (右半部分凸起)
|
||||
const rotateY = ((x - centerX) / centerX) * 10
|
||||
|
||||
cardStyles.value[index] = {
|
||||
transform: `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.02, 1.02, 1.02)`,
|
||||
transition: 'transform 0.1s ease-out', // 移动时响应要快
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseLeave(index: number) {
|
||||
cardStyles.value[index] = {
|
||||
transform: 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)',
|
||||
transition: 'transform 0.5s ease', // 离开时平滑复位
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await initSyncRouteParams()
|
||||
await getQuestions()
|
||||
@ -160,8 +195,8 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<CompetitionLayout
|
||||
:show-back="true" :show-next="showNextButton" :title="activityName" :title-bg-type="2"
|
||||
@back="handleBack" @next="handleNext"
|
||||
:show-back="true" :show-next="showNextButton" next-btn-text="下一步" :title="activityName"
|
||||
:title-bg-type="2" @back="handleBack" @next="handleNext"
|
||||
>
|
||||
<div class="h-screen w-full overflow-y-auto font-sans">
|
||||
<div class="relative z-10 min-h-full w-full">
|
||||
@ -172,9 +207,12 @@ onMounted(async () => {
|
||||
class="perspective-container max-w-[1800px] w-full flex flex-wrap justify-center gap-4 px-4 md:gap-10 md:px-12"
|
||||
>
|
||||
<div
|
||||
v-for="(node, index) in showCards ? questions : []" :key="node.id"
|
||||
class="w-[44%] card-wrapper 2xl:w-[14%] lg:w-[21%] md:w-[28%] xl:w-[17%]"
|
||||
:style="{ animationDelay: `${index * 0.2}s` }" @click="toggleFlip(index)"
|
||||
v-for="(node, index) in showCards ? questions : []" :key="index"
|
||||
class="w-[44%] card-wrapper 2xl:w-[14%] lg:w-[21%] md:w-[28%] xl:w-[17%]" :style="{
|
||||
animationDelay: `${index * 0.2}s`,
|
||||
...(cardStyles[index] || {}),
|
||||
}" @click="toggleFlip(index)" @mousemove="(e) => handleMouseMove(e, index)"
|
||||
@mouseleave="handleMouseLeave(index)"
|
||||
>
|
||||
<div class="flip-card-inner" :class="{ 'is-flipped': flippedCards.has(index) }">
|
||||
<!-- 正面 (Front) - 显示背面图案 -->
|
||||
@ -259,10 +297,6 @@ onMounted(async () => {
|
||||
cursor: pointer;
|
||||
transition: transform 0.3s ease;
|
||||
box-shadow: none !important;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-10px); // [悬停效果] 鼠标移上去时卡片轻微上浮
|
||||
}
|
||||
}
|
||||
|
||||
.flip-card-inner {
|
||||
@ -278,7 +312,7 @@ onMounted(async () => {
|
||||
|
||||
transform-style: preserve-3d; // [3D空间] 确保子元素(正反面)在3D空间中渲染,而不是压平在平面上
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.2); // [静态阴影] 默认状态下的投影
|
||||
// box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.2); // [静态阴影] 默认状态下的投影
|
||||
|
||||
&.is-flipped {
|
||||
// [翻转状态]
|
||||
@ -300,7 +334,7 @@ onMounted(async () => {
|
||||
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.5); // 增加微妙的边框
|
||||
// border: 1px solid rgba(255, 255, 255, 0.5); // 增加微妙的边框
|
||||
}
|
||||
|
||||
// 正面(实际是卡背图案)
|
||||
@ -370,8 +404,8 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.inner-circle-decoration {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
width: 98px;
|
||||
height: 98px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import drawImg from '@/assets/imgs/user/draw.svg'
|
||||
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
|
||||
import { useRouterPush } from '@/hooks/common/router'
|
||||
import { fetchGetCurrentQuestion } from '@/service/api/game'
|
||||
@ -130,29 +131,29 @@ function handleBack() {
|
||||
}
|
||||
|
||||
const questionMainTitle = computed(() => question.value?.QuestionList?.Name || '')
|
||||
const questionTitle = computed(() => question.value?.QuestionList?.QuestionContent || question.value?.QuestionList?.Name || '')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CompetitionLayout :show-back="true" :show-next="false" :title="questionMainTitle || '抽题'" @back="handleBack">
|
||||
<div class="h-full w-full flex flex-col items-center pt-10 font-sans">
|
||||
<!-- <div v-if="question" class="mb-10 max-w-4xl text-center">
|
||||
<div v-if="question" class="mb-10 max-w-4xl text-center">
|
||||
<div class="text-2xl text-gray-800 font-medium leading-relaxed tracking-wide">
|
||||
{{ questionMainTitle || '' }}
|
||||
{{ questionTitle || '' }}
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 题目卡片列表 -->
|
||||
<div v-if="loading" class="text-xl text-gray-500">
|
||||
加载中...
|
||||
</div>
|
||||
<div v-else class="w-full flex flex-1 items-center justify-center pb-10">
|
||||
<div v-else class="w-full flex items-center justify-center pb-10">
|
||||
<div v-if="question" class="lottery-stick-container">
|
||||
<div
|
||||
class="lottery-stick" :class="{ 'is-selected': flippedId === question?.Activity_Question?.ID }"
|
||||
@click="handleCardClick(question)"
|
||||
>
|
||||
<!-- 签身 (默认显示) -->
|
||||
<div class="stick-face stick-body">
|
||||
<!-- <div class="stick-face stick-body">
|
||||
<div class="stick-top-mark" />
|
||||
<div
|
||||
class="writing-mode-vertical-rl h-full flex items-center justify-center text-xl text-yellow-900 font-bold tracking-widest opacity-80"
|
||||
@ -160,11 +161,12 @@ const questionMainTitle = computed(() => question.value?.QuestionList?.Name || '
|
||||
抽 题
|
||||
</div>
|
||||
</div>
|
||||
<!-- 签面 (翻转后显示 - 实际上是放大显示的) -->
|
||||
<div class="stick-face stick-content">
|
||||
<span class="writing-mode-vertical-rl text-2xl text-red-600 font-bold">{{ questionMainTitle
|
||||
}}</span>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- 禁用放大 -->
|
||||
<NImage :src="drawImg" class="h-full w-full object-cover" :preview-disabled="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -178,8 +180,8 @@ const questionMainTitle = computed(() => question.value?.QuestionList?.Name || '
|
||||
|
||||
<style scoped>
|
||||
.lottery-stick-container {
|
||||
width: 50px;
|
||||
height: 240px;
|
||||
/* width: 50px;
|
||||
height: 240px; */
|
||||
perspective: 1000px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.3s;
|
||||
@ -236,7 +238,7 @@ const questionMainTitle = computed(() => question.value?.QuestionList?.Name || '
|
||||
|
||||
/* 选中(抽出)动画状态 */
|
||||
.lottery-stick.is-selected {
|
||||
transform: translateY(-100px) scale(2) rotateY(180deg);
|
||||
transform: translateY(-100px) scale(1.4) rotateY(180deg);
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
|
||||
@ -83,7 +83,7 @@ function buildOption(list: BarDatum[]): ECOption {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '正确数量',
|
||||
name: '预估得分',
|
||||
type: 'bar',
|
||||
data: correct,
|
||||
barWidth: 24,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import startIcon from '@/assets/imgs/user/star-icon.svg'
|
||||
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
|
||||
import { useRouterPush } from '@/hooks/common/router'
|
||||
import { fetchGetGroupListByActivityID } from '@/service/api/game'
|
||||
@ -94,7 +95,7 @@ onMounted(() => {
|
||||
<div class="icon-wrapper">
|
||||
<div class="flower-bg" />
|
||||
<div class="inner-icon">
|
||||
<img src="@/assets/imgs/user/star-icon.svg" alt="star" class="star-img">
|
||||
<NImage :src="startIcon" alt="star" class="star-img" width="180" height="187" :preview-disabled="true" object-fit="contain" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="group-name-tag">
|
||||
@ -153,8 +154,8 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
// width: 100px;
|
||||
// height: 100px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -49,10 +49,7 @@ function handleNext() {
|
||||
|
||||
<template>
|
||||
<CompetitionLayout
|
||||
:show-back="true"
|
||||
:show-next="true"
|
||||
:title="activityName"
|
||||
@back="handleBack"
|
||||
:show-back="true" :show-next="true" :title="activityName" next-btn-text="下一步" @back="handleBack"
|
||||
@next="handleNext"
|
||||
>
|
||||
<div class="items-flex-start h-full w-full flex justify-center font-sans">
|
||||
|
||||
@ -113,7 +113,7 @@ onMounted(() => {
|
||||
@click="selectTeam(item.id)"
|
||||
>
|
||||
<div class="icon-wrapper">
|
||||
<img src="@/assets/imgs/user/star-icon.svg" alt="team-icon" class="h-full w-full object-cover">
|
||||
<img src="@/assets/imgs/user/team-title-icon.svg" alt="team-icon" class="h-full w-full object-cover">
|
||||
</div>
|
||||
<div class="team-name">
|
||||
{{ item.name }}
|
||||
@ -263,7 +263,7 @@ onMounted(() => {
|
||||
justify-content: center;
|
||||
// background: url('@/assets/imgs/team-icon-bg.svg') no-repeat center center;
|
||||
background-size: contain;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
@ -272,6 +272,10 @@ onMounted(() => {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8);
|
||||
background: url('@/assets/imgs/user/team-title-bg.svg') no-repeat center center;
|
||||
background-size: contain;
|
||||
padding: 15px 30px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||