feat(admin): 新增品牌logo资源并优化用户界面组件
- 新增重庆、树人、文字logo资源(PNG和WebP格式) - 新增用户界面背景图片资源(内容背景、对框、主页背景等) - 优化ActionButton组件样式(自适应宽度、禁用状态样式) - 更新CompetitionLayout组件header布局,集成新logo资源 - 优化TianZiGe组件功能和交互体验 - 更新竞赛相关页面组件(QuestionConfig、draw、QuestionRenderer等) - 更新排名列表页面样式和功能 - 更新诗词常识题库数据 - 完善Competition类型定义
This commit is contained in:
@ -1,77 +1,65 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from 'vue'
|
||||
import TianZiGe from '@/components/custom/user/TianZiGe.vue'
|
||||
import { QuestionCategoryEnum } from '@/enum/business'
|
||||
import { useCompetitionStore } from '@/store/modules/competition'
|
||||
|
||||
const store = useCompetitionStore()
|
||||
const currentQuestionMainInfo = computed(() => store.currentQuestionMainInfo)
|
||||
const currentQuestionDetail = computed(() => store.currentQuestionDetail)
|
||||
// console.log(currentQuestionMainInfo.value, 'currentQuestionMainInfo')
|
||||
|
||||
// 题目
|
||||
const title = computed(() => currentQuestionMainInfo.value?.QuestionList?.QuestionContent)
|
||||
// 题目内容
|
||||
const content = computed(() => currentQuestionDetail.value.Name)
|
||||
// 图片
|
||||
const ImageUrl = computed(() => currentQuestionDetail.value.ImageUrl)
|
||||
// 模版类型
|
||||
const template = computed(() => currentQuestionMainInfo.value?.Activity_Question?.UIType)
|
||||
|
||||
/**
|
||||
* 组合后的标题(用于汉字加一加模板)
|
||||
* 将 content 插入到 title 的引号中,并拆分以支持不同样式
|
||||
*/
|
||||
const parsedComponentAddTitle = computed(() => {
|
||||
const t = title.value || ''
|
||||
const c = content.value || ''
|
||||
|
||||
// 尝试替换全角空引号
|
||||
if (t.includes('“”')) {
|
||||
const [prefix, suffix] = t.split('“”')
|
||||
return {
|
||||
type: 'quote_full',
|
||||
prefix,
|
||||
content: c,
|
||||
suffix,
|
||||
}
|
||||
}
|
||||
// 尝试替换半角空引号
|
||||
if (t.includes('""')) {
|
||||
const [prefix, suffix] = t.split('""')
|
||||
return {
|
||||
type: 'quote_half',
|
||||
prefix,
|
||||
content: c,
|
||||
suffix,
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到空引号,直接追加
|
||||
return {
|
||||
type: 'normal',
|
||||
prefix: t,
|
||||
content: c,
|
||||
suffix: '',
|
||||
}
|
||||
})
|
||||
|
||||
/** 获取富文本里面的text */
|
||||
const pinyinChars = computed(() => {
|
||||
// 汉字听写1:按 # 分割内容
|
||||
const dictationParts = computed(() => {
|
||||
if (content.value) {
|
||||
// 创建临时元素提取HTML文本内容
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = content.value
|
||||
const text = div.textContent || ''
|
||||
return text.trim().split(/\s+/).filter(Boolean)
|
||||
return content.value.split('#').filter(Boolean)
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
// 联想对对碰:上方词组
|
||||
const associationWords = computed(() => {
|
||||
const name = currentQuestionDetail.value?.Name || ''
|
||||
return name.split(/[,,、]/).filter(Boolean)
|
||||
})
|
||||
|
||||
// 联想对对碰:答案按逗号分行,只保留汉字
|
||||
const answerLines = computed(() => {
|
||||
const answer = currentQuestionDetail.value?.Answer || ''
|
||||
return answer.split(/[,,]/)
|
||||
.map(line => line.split('').filter(char => /[\u4E00-\u9FA5]/.test(char)))
|
||||
.filter(line => line.length > 0)
|
||||
})
|
||||
|
||||
// 联想对对碰:关键词索引和文字
|
||||
const keywordInfo = computed(() => ({
|
||||
index: currentQuestionDetail.value?.KeyWordsIndex ?? -1,
|
||||
word: currentQuestionDetail.value?.KeyWord || '',
|
||||
}))
|
||||
|
||||
// 计算全局字符索引(用于匹配 KeyWordsIndex)
|
||||
function getGlobalCharIndex(lineIndex: number, charIndex: number) {
|
||||
let globalIndex = 0
|
||||
for (let i = 0; i < lineIndex; i++) {
|
||||
globalIndex += answerLines.value[i].length
|
||||
}
|
||||
return globalIndex + charIndex
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [currentQuestionMainInfo, currentQuestionDetail],
|
||||
() => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Current currentQuestionMainInfo:', currentQuestionMainInfo.value)
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Current currentQuestionMainInfo:', currentQuestionMainInfo)
|
||||
console.log('Current currentQuestionDetail:', currentQuestionDetail.value)
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
)
|
||||
@ -81,64 +69,59 @@ watch(
|
||||
<div class="w-full flex p-6">
|
||||
<!-- <p>template:{{ template }}</p> -->
|
||||
<!-- 模板A: 汉字听写1-提示 (拼音+提示) -->
|
||||
<div v-if="template === QuestionCategoryEnum.ChineseCharacterDictation1 || template === QuestionCategoryEnum.ChineseCharacterDictation2" class="text-center">
|
||||
<div v-if="template === QuestionCategoryEnum.ChineseCharacterDictation1" class="text-center">
|
||||
<div class="mb-6 inline-block text-5xl font-bold leading-none">
|
||||
<div class="ptions-container1 mb-2 text-center text-2xl">
|
||||
{{ title }}
|
||||
<div class="flex items-center justify-center gap-4">
|
||||
<div
|
||||
v-for="(part, index) in dictationParts" :key="`part-${index}`"
|
||||
class="text-4xl"
|
||||
:class="index === 0 ? 'short-content-bg' : 'content-with-bg'"
|
||||
>
|
||||
{{ part }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rich-content ml-3 mt-4 flex gap-1 color-red-600">
|
||||
<!-- <TianZiGe v-for="(char, index) in pinyinChars" :key="index" :char="char" /> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板D: 汉字听写 2 词语听写 -->
|
||||
<div
|
||||
v-else-if="template === QuestionCategoryEnum.ChineseCharacterDictation2 || template === QuestionCategoryEnum.WordDictation"
|
||||
class="flex flex-col items-center"
|
||||
>
|
||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="rich-content content-with-bg ml-3 mt-4 flex text-6xl !px-16 !py-10 !tracking-[0.1em]">
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板B: 汉字听写-同音字 (大字) -->
|
||||
<!-- 暂时未匹配到枚举,保持原样或删除 -->
|
||||
<!-- <div v-else-if="template === 'TEMPLATE_DICTATION_HOMOPHONE'" class="text-center"> -->
|
||||
|
||||
<!-- 模板C: 汉字加一加 (提示+部件) -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.CharacterRadicalAddition" class="text-center">
|
||||
<div class="text-[50px] font-bold">
|
||||
<template v-if="parsedComponentAddTitle.type === 'quote_full'">
|
||||
<span class="text-black">{{ parsedComponentAddTitle.prefix }}“</span>
|
||||
<span class="text-red-600">{{ parsedComponentAddTitle.content }}</span>
|
||||
<span class="text-black">”{{ parsedComponentAddTitle.suffix }}</span>
|
||||
</template>
|
||||
|
||||
<template v-else-if="parsedComponentAddTitle.type === 'quote_half'">
|
||||
<span class="text-black">{{ parsedComponentAddTitle.prefix }}"</span>
|
||||
<span class="text-red-600">{{ parsedComponentAddTitle.content }}</span>
|
||||
<span class="text-black">"{{ parsedComponentAddTitle.suffix }}</span>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<span class="text-black">{{ parsedComponentAddTitle.prefix }}</span>
|
||||
<span class="ml-4 text-red-600">{{ parsedComponentAddTitle.content }}</span>
|
||||
</template>
|
||||
<div class="mb-6 inline-block text-5xl font-bold leading-none">
|
||||
<div class="rich-content ml-3 mt-4 flex gap-1 text-5xl tracking-[0.1em]">
|
||||
请写出含有“ <span class="text-color-red !text-6xl">{{ content }}</span>”的汉字,书写时间为60秒。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板D: 词语听写 (拼音+提示) -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.WordDictation" class="flex flex-col items-center">
|
||||
<div class="mb-8 flex flex-wrap justify-center gap-6">
|
||||
<TianZiGe v-for="(char, index) in pinyinChars" :key="index" :char="char" />
|
||||
<!-- 模板D: 成语写一写1 (拼音+提示) -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.IdiomWriting1" class="flex flex-col items-center">
|
||||
<div class="mb-1 text-gray-800 font-bold leading-relaxed">
|
||||
<div class="rich-content ml-3 mt-4 flex gap-1 text-4xl">
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板E: 成语-文字要求 -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.IdiomWriting1 || template === QuestionCategoryEnum.IdiomWriting2" class="text-center">
|
||||
<div v-else-if="template === QuestionCategoryEnum.IdiomWriting2" class="text-center">
|
||||
<div class="mb-8 text-4xl text-gray-800 font-bold">
|
||||
<!-- {{ content }} -->
|
||||
<div class="rich-content" v-html="content" />
|
||||
<NImage :src="ImageUrl" preview-disabled width="300" object-fit="contain" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板G: 诗词理解-选择题 (通用选择题模板) -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.PoetryComprehension" class="w-full flex flex-col items-center">
|
||||
<div class="options-container text-2xl">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="rich-content" v-html="content" />
|
||||
</div>
|
||||
@ -146,57 +129,65 @@ watch(
|
||||
|
||||
<!-- 模板ChangeWords: 换字组成语 -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.ChangeWords" class="w-full flex flex-col items-center">
|
||||
<div class="options-container text-2xl">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="rich-content" v-html="content" />
|
||||
<div class="content-with-bg mb-1 mt-10 p-6 text-6xl text-gray-800 font-bold !px-16 !py-8">
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板: 场景猜诗句 -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.SceneBasedPoemGuessing" class="w-full flex flex-col items-center">
|
||||
<div class="options-container text-2xl">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="mb-1 p-16 text-3xl text-gray-800 font-bold leading-relaxed line-height-20">
|
||||
<div class="rich-content" v-html="content" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板: 联想对对碰 -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.AssociationMatching" class="w-full flex flex-col items-center">
|
||||
<div class="options-container text-2xl">
|
||||
{{ title }}
|
||||
<div
|
||||
v-else-if="template === QuestionCategoryEnum.AssociationMatching"
|
||||
class="w-full flex flex-col items-center gap-8"
|
||||
>
|
||||
<!-- 上方:词组 -->
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<div v-for="(word, index) in associationWords" :key="`word-${index}`" class="association-word text-bold">
|
||||
{{ word }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="rich-content" v-html="content" />
|
||||
|
||||
<!-- 下方:答案字符(按逗号分行) -->
|
||||
<div class="flex flex-col items-center gap-3">
|
||||
<div v-for="(line, lineIndex) in answerLines" :key="`line-${lineIndex}`" class="flex gap-4">
|
||||
<div
|
||||
v-for="(char, charIndex) in line" :key="`char-${lineIndex}-${charIndex}`"
|
||||
class="association-char text-5xl"
|
||||
>
|
||||
<span v-if="getGlobalCharIndex(lineIndex, charIndex) === keywordInfo.index">
|
||||
{{ keywordInfo.word }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板: 字词飞花令 -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.CharacterWordFlowerDrinkingGame" class="w-full flex flex-col items-center">
|
||||
<div class="options-container text-2xl">
|
||||
<div
|
||||
v-else-if="template === QuestionCategoryEnum.CharacterWordFlowerDrinkingGame"
|
||||
class="w-full flex flex-col items-center"
|
||||
>
|
||||
<div class="options-container text-5xl">
|
||||
请回答带有“{{ content }}”的诗词。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板: 诗词常识 -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.PoetryCommonKnowledge" class="w-full flex flex-col items-center">
|
||||
<div class="options-container text-2xl">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="mb-1 p-16 text-3xl text-gray-800 font-bold leading-relaxed line-height-20">
|
||||
<div class="rich-content" v-html="content" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板: 逆向接诗句 -->
|
||||
<div v-else-if="template === QuestionCategoryEnum.ReversePoemMatching" class="w-full flex flex-col items-center">
|
||||
<div class="options-container text-2xl">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="mb-1 mt-20 text-5xl text-gray-800 font-bold leading-relaxed">
|
||||
<div class="rich-content" v-html="content" />
|
||||
</div>
|
||||
</div>
|
||||
@ -206,7 +197,7 @@ watch(
|
||||
<div class="ptions-container1 mb-2 text-center text-2xl">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="rich-content ml-3 mt-4 flex gap-1 color-red-600">
|
||||
<div class="rich-content ml-3 mt-4 flex gap-1">
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
@ -413,5 +404,53 @@ watch(
|
||||
margin: 0 auto;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
:deep(p),
|
||||
:deep(span),
|
||||
:deep(div) {
|
||||
font-size: 2rem; /* text-5xl */
|
||||
}
|
||||
}
|
||||
|
||||
.content-with-bg {
|
||||
background: url('@/assets/imgs/user/content-bg.png') no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 12px;
|
||||
padding: 20px 30px;
|
||||
letter-spacing: 0.4em;
|
||||
}
|
||||
|
||||
.short-content-bg {
|
||||
background: url('@/assets/imgs/user/short-content-bg.png') no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 12px;
|
||||
padding: 20px 30px;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.association-word {
|
||||
background: url('@/assets/imgs/user/dui-kuang.png') no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
min-width: 160px;
|
||||
height: 70px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.association-char {
|
||||
background: url('@/assets/imgs/user/dui-text-bg.png') no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user