feat(admin): 新增品牌logo资源并优化用户界面组件
- 新增重庆、树人、文字logo资源(PNG和WebP格式) - 新增用户界面背景图片资源(内容背景、对框、主页背景等) - 优化ActionButton组件样式(自适应宽度、禁用状态样式) - 更新CompetitionLayout组件header布局,集成新logo资源 - 优化TianZiGe组件功能和交互体验 - 更新竞赛相关页面组件(QuestionConfig、draw、QuestionRenderer等) - 更新排名列表页面样式和功能 - 更新诗词常识题库数据 - 完善Competition类型定义
BIN
apps/admin/src/assets/imgs/logo/cq-logo.png
Normal file
|
After Width: | Height: | Size: 578 KiB |
BIN
apps/admin/src/assets/imgs/logo/cq-logo.webp
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
apps/admin/src/assets/imgs/logo/qw-logo.png
Normal file
|
After Width: | Height: | Size: 487 KiB |
BIN
apps/admin/src/assets/imgs/logo/qw-logo.webp
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
apps/admin/src/assets/imgs/logo/text-logo.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
apps/admin/src/assets/imgs/logo/text-logo.webp
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
apps/admin/src/assets/imgs/user/3 310372448.png
Normal file
|
After Width: | Height: | Size: 487 KiB |
BIN
apps/admin/src/assets/imgs/user/content-bg.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
apps/admin/src/assets/imgs/user/dui-kuang.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
apps/admin/src/assets/imgs/user/dui-text-bg.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
apps/admin/src/assets/imgs/user/home-bg1.webp
Normal file
|
After Width: | Height: | Size: 811 KiB |
BIN
apps/admin/src/assets/imgs/user/short-content-bg.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
@ -130,8 +130,10 @@ function handleClick() {
|
|||||||
.custom-btn {
|
.custom-btn {
|
||||||
background: v-bind(customBg);
|
background: v-bind(customBg);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
width: 220px;
|
min-width: 210px;
|
||||||
|
width: auto;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
|
padding: 0 20px;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
color: rgb(0, 94, 174);
|
color: rgb(0, 94, 174);
|
||||||
|
|
||||||
@ -142,6 +144,12 @@ function handleClick() {
|
|||||||
margin-bottom: 7px;
|
margin-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-disabled {
|
||||||
|
color: #eb5e55;
|
||||||
|
filter: none;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import VScaleScreen from 'v-scale-screen'
|
import VScaleScreen from 'v-scale-screen'
|
||||||
import { computed, onMounted, ref, watch } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import _defaultBg from '@/assets/imgs/user/home-bg.webp'
|
import cqLogo from '@/assets/imgs/logo/cq-logo.webp'
|
||||||
|
import srLogo from '@/assets/imgs/logo/qw-logo.webp'
|
||||||
|
import qwLogo from '@/assets/imgs/logo/text-logo.webp'
|
||||||
|
import _defaultBg from '@/assets/imgs/user/home-bg1.webp'
|
||||||
import titleBg2 from '@/assets/imgs/user/title-bg2.webp'
|
import titleBg2 from '@/assets/imgs/user/title-bg2.webp'
|
||||||
import titleBg3 from '@/assets/imgs/user/title-bg3.png'
|
import titleBg3 from '@/assets/imgs/user/title-bg3.png'
|
||||||
import titleBg4 from '@/assets/imgs/user/title-bg4.png'
|
import titleBg4 from '@/assets/imgs/user/title-bg4.png'
|
||||||
@ -224,11 +227,22 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
<VScaleScreen width="2048" height="1080">
|
<VScaleScreen width="2048" height="1080">
|
||||||
<div class="competition-layout">
|
<div class="competition-layout">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<!-- <header class="page-header flex items-center text-[30px] text-[#333333] font-bold">
|
<header class="page-header flex items-center px-8 text-[30px] text-[#333333] font-bold">
|
||||||
<span class="org-name" @click="handleBackHome">重庆市教育学会</span>
|
<!-- 左侧logo -->
|
||||||
<img src="@/assets/imgs/ydzx.png" width="100" height="50" alt="logo" class="logo">
|
<div class="flex cursor-pointer items-center" @click="handleBackHome">
|
||||||
<span class="org-name">树人教育研究院</span>
|
<img :src="cqLogo" alt="重庆logo" class="h-20 w-auto">
|
||||||
</header> -->
|
</div>
|
||||||
|
|
||||||
|
<!-- 中间文字 -->
|
||||||
|
<div class="flex flex-1 justify-center">
|
||||||
|
<img :src="qwLogo" alt="重庆logo" class="h-14 w-auto">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧logo组 -->
|
||||||
|
<div class="flex items-center justify-end gap-4">
|
||||||
|
<img :src="srLogo" alt="树人logo" class="h-19 w-auto">
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
<div class="glass-overlay">
|
<div class="glass-overlay">
|
||||||
<!-- title -->
|
<!-- title -->
|
||||||
@ -238,18 +252,11 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
<div class="scroll-bg">
|
<div class="scroll-bg">
|
||||||
<!-- 预渲染所有背景图,用 opacity 切换避免加载抖动 -->
|
<!-- 预渲染所有背景图,用 opacity 切换避免加载抖动 -->
|
||||||
<img
|
<img
|
||||||
v-for="(url, _key) in titleBgUrlMapping"
|
v-for="(url, _key) in titleBgUrlMapping" :key="_key" :src="url" class="scroll-bg-img" :class="{
|
||||||
:key="_key"
|
|
||||||
:src="url"
|
|
||||||
class="scroll-bg-img"
|
|
||||||
:class="{
|
|
||||||
active: titleBgUrl === url && imageLoadStatus[url] !== false,
|
active: titleBgUrl === url && imageLoadStatus[url] !== false,
|
||||||
loading: imageLoadStatus[url] === undefined,
|
loading: imageLoadStatus[url] === undefined,
|
||||||
}"
|
}" :style="{ visibility: imageLoadStatus[url] === false ? 'hidden' : 'visible' }" aria-hidden="true"
|
||||||
:style="{ visibility: imageLoadStatus[url] === false ? 'hidden' : 'visible' }"
|
@load="imageLoadStatus[url] = true" @error="imageLoadStatus[url] = false"
|
||||||
aria-hidden="true"
|
|
||||||
@load="imageLoadStatus[url] = true"
|
|
||||||
@error="imageLoadStatus[url] = false"
|
|
||||||
>
|
>
|
||||||
<Transition name="fade-in-delay" appear>
|
<Transition name="fade-in-delay" appear>
|
||||||
<h1 v-if="showContent" class="main-title" :style="{ color: titleTextColor }">
|
<h1 v-if="showContent" class="main-title" :style="{ color: titleTextColor }">
|
||||||
@ -270,15 +277,13 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
|
|
||||||
<!-- Footer Action -->
|
<!-- Footer Action -->
|
||||||
<footer
|
<footer
|
||||||
v-if="showButton"
|
v-if="showButton" class="page-footer w-full flex items-center justify-between px-20"
|
||||||
class="page-footer w-full flex items-center justify-between px-20"
|
|
||||||
:class="[actionPosition, btnTheme]"
|
:class="[actionPosition, btnTheme]"
|
||||||
>
|
>
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
class="back-btn" :style="{ visibility: showBack ? 'visible' : 'hidden' }"
|
class="back-btn" :style="{ visibility: showBack ? 'visible' : 'hidden' }" type="custom"
|
||||||
type="custom" :text="backBtnText || ''" :theme="btnTheme" :font-size="fontSize"
|
:text="backBtnText || ''" :theme="btnTheme" :font-size="fontSize" @click="handleBack"
|
||||||
@click="handleBack"
|
|
||||||
>
|
>
|
||||||
<SvgIcon v-if="!backBtnText" icon="mdi:arrow-left" size="40" class="arrow-icon" />
|
<SvgIcon v-if="!backBtnText" icon="mdi:arrow-left" size="40" class="arrow-icon" />
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
@ -286,9 +291,8 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
|
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
v-if="showNext" type="custom" :text="nextBtnText || '下一步'"
|
v-if="showNext" type="custom" :text="nextBtnText || '下一步'" :theme="btnTheme"
|
||||||
:theme="btnTheme" :disabled="nextDisabled" :font-size="fontSize"
|
:disabled="nextDisabled" :font-size="fontSize" @click="handleNext"
|
||||||
@click="handleNext"
|
|
||||||
>
|
>
|
||||||
<SvgIcon v-if="!nextBtnText" icon="mdi:arrow-right" class="arrow-icon" size="40" />
|
<SvgIcon v-if="!nextBtnText" icon="mdi:arrow-right" class="arrow-icon" size="40" />
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
@ -313,25 +317,29 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
width: 412px;
|
width: 412px;
|
||||||
height: 165px;
|
height: 165px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center; /* Ensure wrapper stays centered during expansion */
|
justify-content: center;
|
||||||
|
/* Ensure wrapper stays centered during expansion */
|
||||||
|
|
||||||
.title-wrapper {
|
.title-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center; /* Keep the background image centered */
|
justify-content: center;
|
||||||
|
/* Keep the background image centered */
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-bg {
|
.scroll-bg {
|
||||||
width: 400px !important; /* Fixed width to prevent squishing during animation */
|
width: 400px !important;
|
||||||
|
/* Fixed width to prevent squishing during animation */
|
||||||
height: 155px !important;
|
height: 155px !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
flex-shrink: 0; /* Prevent shrinking */
|
flex-shrink: 0;
|
||||||
|
/* Prevent shrinking */
|
||||||
|
|
||||||
.scroll-bg-img {
|
.scroll-bg-img {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -360,7 +368,8 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
letter-spacing: 4px;
|
letter-spacing: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap; /* Prevent text wrapping */
|
white-space: nowrap;
|
||||||
|
/* Prevent text wrapping */
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
@ -435,7 +444,7 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: -20px;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -489,7 +498,8 @@ watch(titleBgUrl, (newUrl) => {
|
|||||||
|
|
||||||
.fade-in-delay-enter-active {
|
.fade-in-delay-enter-active {
|
||||||
transition: opacity 0.8s ease;
|
transition: opacity 0.8s ease;
|
||||||
transition-delay: 1s; /* Wait for scroll to unfold */
|
transition-delay: 1s;
|
||||||
|
/* Wait for scroll to unfold */
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-in-delay-enter-from {
|
.fade-in-delay-enter-from {
|
||||||
|
|||||||
@ -43,6 +43,3 @@ const _props = withDefaults(defineProps<Props>(), {
|
|||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
</style>
|
|
||||||
|
|||||||
2
apps/admin/src/typings/api/Competition.d.ts
vendored
@ -106,6 +106,8 @@ declare namespace Api {
|
|||||||
Image: string
|
Image: string
|
||||||
ImageUrl: string
|
ImageUrl: string
|
||||||
Answer: string
|
Answer: string
|
||||||
|
KeyWordsIndex?: number
|
||||||
|
KeyWord?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get current question params */
|
/** get current question params */
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NButton, NForm, NFormItem, NInputNumber, NModal, NSelect, type SelectOption } from 'naive-ui'
|
import { NButton, NForm, NFormItem, NInputNumber, NModal, NSelect, type SelectOption } from 'naive-ui'
|
||||||
import { onMounted, ref, watch } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import { VueDraggable } from 'vue-draggable-plus'
|
import { VueDraggable } from 'vue-draggable-plus'
|
||||||
import { useDict } from '@/hooks/business/useDict'
|
import { useDict } from '@/hooks/business/useDict'
|
||||||
import { fetchGetQuestionListAll } from '@/service/api/question'
|
import { fetchGetQuestionListAll } from '@/service/api/question'
|
||||||
@ -29,7 +29,10 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const { options: roundTypeOptions } = useDict('round_type')
|
const { options: roundTypeOptions } = useDict('round_type')
|
||||||
const { options: scoreTypeOptions } = useDict('score_type')
|
const { options: scoreTypeOptions } = useDict('score_type')
|
||||||
const { options: timeOptions } = useDict('time_out')
|
const { options: timeOptionsRaw } = useDict('time_out')
|
||||||
|
const timeOptions = computed(() =>
|
||||||
|
[...timeOptionsRaw.value].sort((a, b) => Number(a.value) - Number(b.value)),
|
||||||
|
)
|
||||||
// const { options: uiTypeOptions } = useDict('ui_type', 'string')
|
// const { options: uiTypeOptions } = useDict('ui_type', 'string')
|
||||||
const { options: uiTypeOptions } = useDict('question_category_name', 'string')
|
const { options: uiTypeOptions } = useDict('question_category_name', 'string')
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,6 @@ function handleAdd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleCopy(item: Api.Competition.CompetitionItem) {
|
async function handleCopy(item: Api.Competition.CompetitionItem) {
|
||||||
// TODO: 实现复制逻辑
|
|
||||||
try {
|
try {
|
||||||
const { error } = await fetchCopyActivity(item.Id)
|
const { error } = await fetchCopyActivity(item.Id)
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -163,7 +162,3 @@ onMounted(() => fetchActivityList())
|
|||||||
<CompetitionAddModal v-model:show="showAddModal" @success="fetchActivityList" />
|
<CompetitionAddModal v-model:show="showAddModal" @success="fetchActivityList" />
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 针对不同屏幕微调间距 */
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -151,7 +151,7 @@ function edit(item: any) {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="mid-title">
|
<div class="mid-title">
|
||||||
<div class="text-16px font-bold">
|
<div class="text-2xl font-bold">
|
||||||
{{ rankTitle }}
|
{{ rankTitle }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4px text-12px text-gray-500">
|
<div class="mt-4px text-12px text-gray-500">
|
||||||
|
|||||||
@ -241,9 +241,9 @@ async function fetchQuestions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前正在比赛的题目
|
* 获取当前正在比赛的题目(不触发同步选中逻辑)
|
||||||
*/
|
*/
|
||||||
async function fetchCurrentQuestion() {
|
async function fetchCurrentQuestion(shouldSync = true) {
|
||||||
if (!roomId.value)
|
if (!roomId.value)
|
||||||
return
|
return
|
||||||
try {
|
try {
|
||||||
@ -254,9 +254,11 @@ async function fetchCurrentQuestion() {
|
|||||||
}
|
}
|
||||||
currentQuestion.value = data?.data || {}
|
currentQuestion.value = data?.data || {}
|
||||||
console.warn('current question', currentQuestion.value)
|
console.warn('current question', currentQuestion.value)
|
||||||
// 拉取当前题目信息后尝试同步选中题
|
// 只在初始化时同步选中题,轮询时不同步
|
||||||
|
if (shouldSync) {
|
||||||
syncCurrentQuestionSelection()
|
syncCurrentQuestionSelection()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (error: any) {
|
catch (error: any) {
|
||||||
message.error(error.message || '获取当前题目失败')
|
message.error(error.message || '获取当前题目失败')
|
||||||
}
|
}
|
||||||
@ -467,8 +469,8 @@ async function handleNexCurrentQuestion() {
|
|||||||
|
|
||||||
function handlePublish() {
|
function handlePublish() {
|
||||||
const endTimeStr = (currentQuestion.value as any)?.EndTime
|
const endTimeStr = (currentQuestion.value as any)?.EndTime
|
||||||
if (endTimeStr && Date.now() < new Date(endTimeStr).getTime()) {
|
if (endTimeStr && Date.now() < new Date(endTimeStr).getTime() + 5000) {
|
||||||
window.$message?.warning('倒计时未结束,暂不能发布')
|
window.$message?.warning('倒计时未结束(需等待5秒延迟),暂不能发布')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (currentQuestion.value?.TeamGroupQuestionID) {
|
if (currentQuestion.value?.TeamGroupQuestionID) {
|
||||||
@ -583,7 +585,8 @@ const canPublish = computed(() => {
|
|||||||
const endTime = (currentQuestion.value as any)?.EndTime
|
const endTime = (currentQuestion.value as any)?.EndTime
|
||||||
if (!endTime)
|
if (!endTime)
|
||||||
return true
|
return true
|
||||||
const end = new Date(endTime).getTime()
|
// 结束时间 + 5秒延迟才能发布
|
||||||
|
const end = new Date(endTime).getTime() + 5000
|
||||||
return nowTs.value >= end
|
return nowTs.value >= end
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -593,7 +596,7 @@ function startPolling() {
|
|||||||
// 检查是否已经结束
|
// 检查是否已经结束
|
||||||
const endTime = (currentQuestion.value as any)?.EndTime
|
const endTime = (currentQuestion.value as any)?.EndTime
|
||||||
if (endTime) {
|
if (endTime) {
|
||||||
// 增加 8s 缓冲时间
|
// 增加 12s 缓冲时间
|
||||||
const end = new Date(endTime).getTime() + 12000
|
const end = new Date(endTime).getTime() + 12000
|
||||||
const now = new Date().getTime()
|
const now = new Date().getTime()
|
||||||
if (now > end) {
|
if (now > end) {
|
||||||
@ -616,7 +619,7 @@ function startPolling() {
|
|||||||
// 每次轮询前再次检查是否过期
|
// 每次轮询前再次检查是否过期
|
||||||
const currentEndTime = (currentQuestion.value as any)?.EndTime
|
const currentEndTime = (currentQuestion.value as any)?.EndTime
|
||||||
if (currentEndTime) {
|
if (currentEndTime) {
|
||||||
// 增加 8s 缓冲时间
|
// 增加 12s 缓冲时间
|
||||||
const endTs = new Date(currentEndTime).getTime() + 12000
|
const endTs = new Date(currentEndTime).getTime() + 12000
|
||||||
if (Date.now() > endTs) {
|
if (Date.now() > endTs) {
|
||||||
console.log('题目时间已到(含12s缓冲),停止轮询', currentEndTime)
|
console.log('题目时间已到(含12s缓冲),停止轮询', currentEndTime)
|
||||||
@ -625,6 +628,9 @@ function startPolling() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
nowTs.value = Date.now()
|
nowTs.value = Date.now()
|
||||||
|
|
||||||
|
// 轮询时同时更新当前题目信息(获取最新的 EndTime),但不触发同步
|
||||||
|
fetchCurrentQuestion(false)
|
||||||
fetchAnswerData()
|
fetchAnswerData()
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
@ -681,7 +687,7 @@ watch(() => currentQuestionDetailID.value, (newVal) => {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 并行拉取分组、题目与当前题目,完成后做一次同步
|
// 并行拉取分组、题目与当前题目,完成后做一次同步
|
||||||
await Promise.all([fetchGroups(), fetchQuestions(), fetchCurrentQuestion()])
|
await Promise.all([fetchGroups(), fetchQuestions(), fetchCurrentQuestion(true)])
|
||||||
syncCurrentQuestionSelection()
|
syncCurrentQuestionSelection()
|
||||||
startPolling()
|
startPolling()
|
||||||
})
|
})
|
||||||
|
|||||||
@ -144,7 +144,7 @@ const titleBgTypeNum = computed(() => RoundType.value === 0 ? 3 : 4)
|
|||||||
>
|
>
|
||||||
<div class="h-full w-full flex flex-col items-center pt-10 font-sans">
|
<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">
|
<div class="text-4xl text-gray-800 font-medium leading-relaxed tracking-wide">
|
||||||
{{ questionTitle || '' }}
|
{{ questionTitle || '' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,77 +1,65 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, watch } from 'vue'
|
import { computed, watch } from 'vue'
|
||||||
import TianZiGe from '@/components/custom/user/TianZiGe.vue'
|
|
||||||
import { QuestionCategoryEnum } from '@/enum/business'
|
import { QuestionCategoryEnum } from '@/enum/business'
|
||||||
import { useCompetitionStore } from '@/store/modules/competition'
|
import { useCompetitionStore } from '@/store/modules/competition'
|
||||||
|
|
||||||
const store = useCompetitionStore()
|
const store = useCompetitionStore()
|
||||||
const currentQuestionMainInfo = computed(() => store.currentQuestionMainInfo)
|
const currentQuestionMainInfo = computed(() => store.currentQuestionMainInfo)
|
||||||
const currentQuestionDetail = computed(() => store.currentQuestionDetail)
|
const currentQuestionDetail = computed(() => store.currentQuestionDetail)
|
||||||
// console.log(currentQuestionMainInfo.value, 'currentQuestionMainInfo')
|
|
||||||
// 题目
|
// 题目
|
||||||
const title = computed(() => currentQuestionMainInfo.value?.QuestionList?.QuestionContent)
|
const title = computed(() => currentQuestionMainInfo.value?.QuestionList?.QuestionContent)
|
||||||
// 题目内容
|
// 题目内容
|
||||||
const content = computed(() => currentQuestionDetail.value.Name)
|
const content = computed(() => currentQuestionDetail.value.Name)
|
||||||
|
// 图片
|
||||||
|
const ImageUrl = computed(() => currentQuestionDetail.value.ImageUrl)
|
||||||
// 模版类型
|
// 模版类型
|
||||||
const template = computed(() => currentQuestionMainInfo.value?.Activity_Question?.UIType)
|
const template = computed(() => currentQuestionMainInfo.value?.Activity_Question?.UIType)
|
||||||
|
|
||||||
/**
|
// 汉字听写1:按 # 分割内容
|
||||||
* 组合后的标题(用于汉字加一加模板)
|
const dictationParts = computed(() => {
|
||||||
* 将 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(() => {
|
|
||||||
if (content.value) {
|
if (content.value) {
|
||||||
// 创建临时元素提取HTML文本内容
|
return content.value.split('#').filter(Boolean)
|
||||||
const div = document.createElement('div')
|
|
||||||
div.innerHTML = content.value
|
|
||||||
const text = div.textContent || ''
|
|
||||||
return text.trim().split(/\s+/).filter(Boolean)
|
|
||||||
}
|
}
|
||||||
return []
|
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(
|
watch(
|
||||||
() => [currentQuestionMainInfo, currentQuestionDetail],
|
() => [currentQuestionMainInfo, currentQuestionDetail],
|
||||||
() => {
|
() => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log('Current currentQuestionMainInfo:', currentQuestionMainInfo.value)
|
console.log('Current currentQuestionMainInfo:', currentQuestionMainInfo.value)
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log('Current currentQuestionMainInfo:', currentQuestionMainInfo)
|
console.log('Current currentQuestionDetail:', currentQuestionDetail.value)
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true },
|
{ deep: true, immediate: true },
|
||||||
)
|
)
|
||||||
@ -81,64 +69,59 @@ watch(
|
|||||||
<div class="w-full flex p-6">
|
<div class="w-full flex p-6">
|
||||||
<!-- <p>template:{{ template }}</p> -->
|
<!-- <p>template:{{ template }}</p> -->
|
||||||
<!-- 模板A: 汉字听写1-提示 (拼音+提示) -->
|
<!-- 模板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="mb-6 inline-block text-5xl font-bold leading-none">
|
||||||
<div class="ptions-container1 mb-2 text-center text-2xl">
|
<div class="flex items-center justify-center gap-4">
|
||||||
{{ title }}
|
<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">
|
</div>
|
||||||
<!-- <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 }}
|
{{ content }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板B: 汉字听写-同音字 (大字) -->
|
|
||||||
<!-- 暂时未匹配到枚举,保持原样或删除 -->
|
|
||||||
<!-- <div v-else-if="template === 'TEMPLATE_DICTATION_HOMOPHONE'" class="text-center"> -->
|
|
||||||
|
|
||||||
<!-- 模板C: 汉字加一加 (提示+部件) -->
|
<!-- 模板C: 汉字加一加 (提示+部件) -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.CharacterRadicalAddition" class="text-center">
|
<div v-else-if="template === QuestionCategoryEnum.CharacterRadicalAddition" class="text-center">
|
||||||
<div class="text-[50px] font-bold">
|
<div class="mb-6 inline-block text-5xl font-bold leading-none">
|
||||||
<template v-if="parsedComponentAddTitle.type === 'quote_full'">
|
<div class="rich-content ml-3 mt-4 flex gap-1 text-5xl tracking-[0.1em]">
|
||||||
<span class="text-black">{{ parsedComponentAddTitle.prefix }}“</span>
|
请写出含有“ <span class="text-color-red !text-6xl">{{ content }}</span>”的汉字,书写时间为60秒。
|
||||||
<span class="text-red-600">{{ parsedComponentAddTitle.content }}</span>
|
</div>
|
||||||
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板D: 词语听写 (拼音+提示) -->
|
<!-- 模板D: 成语写一写1 (拼音+提示) -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.WordDictation" class="flex flex-col items-center">
|
<div v-else-if="template === QuestionCategoryEnum.IdiomWriting1" class="flex flex-col items-center">
|
||||||
<div class="mb-8 flex flex-wrap justify-center gap-6">
|
<div class="mb-1 text-gray-800 font-bold leading-relaxed">
|
||||||
<TianZiGe v-for="(char, index) in pinyinChars" :key="index" :char="char" />
|
<div class="rich-content ml-3 mt-4 flex gap-1 text-4xl">
|
||||||
|
{{ content }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板E: 成语-文字要求 -->
|
<!-- 模板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">
|
<div class="mb-8 text-4xl text-gray-800 font-bold">
|
||||||
<!-- {{ content }} -->
|
<NImage :src="ImageUrl" preview-disabled width="300" object-fit="contain" />
|
||||||
<div class="rich-content" v-html="content" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板G: 诗词理解-选择题 (通用选择题模板) -->
|
<!-- 模板G: 诗词理解-选择题 (通用选择题模板) -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.PoetryComprehension" class="w-full flex flex-col items-center">
|
<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="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||||
<div class="rich-content" v-html="content" />
|
<div class="rich-content" v-html="content" />
|
||||||
</div>
|
</div>
|
||||||
@ -146,57 +129,65 @@ watch(
|
|||||||
|
|
||||||
<!-- 模板ChangeWords: 换字组成语 -->
|
<!-- 模板ChangeWords: 换字组成语 -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.ChangeWords" class="w-full flex flex-col items-center">
|
<div v-else-if="template === QuestionCategoryEnum.ChangeWords" class="w-full flex flex-col items-center">
|
||||||
<div class="options-container text-2xl">
|
<div class="content-with-bg mb-1 mt-10 p-6 text-6xl text-gray-800 font-bold !px-16 !py-8">
|
||||||
{{ title }}
|
{{ content }}
|
||||||
</div>
|
|
||||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
|
||||||
<div class="rich-content" v-html="content" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板: 场景猜诗句 -->
|
<!-- 模板: 场景猜诗句 -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.SceneBasedPoemGuessing" class="w-full flex flex-col items-center">
|
<div v-else-if="template === QuestionCategoryEnum.SceneBasedPoemGuessing" class="w-full flex flex-col items-center">
|
||||||
<div class="options-container text-2xl">
|
<div class="mb-1 p-16 text-3xl text-gray-800 font-bold leading-relaxed line-height-20">
|
||||||
{{ title }}
|
|
||||||
</div>
|
|
||||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
|
||||||
<div class="rich-content" v-html="content" />
|
<div class="rich-content" v-html="content" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板: 联想对对碰 -->
|
<!-- 模板: 联想对对碰 -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.AssociationMatching" class="w-full flex flex-col items-center">
|
<div
|
||||||
<div class="options-container text-2xl">
|
v-else-if="template === QuestionCategoryEnum.AssociationMatching"
|
||||||
{{ title }}
|
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="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 class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
|
||||||
<div class="rich-content" v-html="content" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板: 字词飞花令 -->
|
<!-- 模板: 字词飞花令 -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.CharacterWordFlowerDrinkingGame" class="w-full flex flex-col items-center">
|
<div
|
||||||
<div class="options-container text-2xl">
|
v-else-if="template === QuestionCategoryEnum.CharacterWordFlowerDrinkingGame"
|
||||||
|
class="w-full flex flex-col items-center"
|
||||||
|
>
|
||||||
|
<div class="options-container text-5xl">
|
||||||
请回答带有“{{ content }}”的诗词。
|
请回答带有“{{ content }}”的诗词。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板: 诗词常识 -->
|
<!-- 模板: 诗词常识 -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.PoetryCommonKnowledge" class="w-full flex flex-col items-center">
|
<div v-else-if="template === QuestionCategoryEnum.PoetryCommonKnowledge" class="w-full flex flex-col items-center">
|
||||||
<div class="options-container text-2xl">
|
<div class="mb-1 p-16 text-3xl text-gray-800 font-bold leading-relaxed line-height-20">
|
||||||
{{ title }}
|
|
||||||
</div>
|
|
||||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
|
||||||
<div class="rich-content" v-html="content" />
|
<div class="rich-content" v-html="content" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 模板: 逆向接诗句 -->
|
<!-- 模板: 逆向接诗句 -->
|
||||||
<div v-else-if="template === QuestionCategoryEnum.ReversePoemMatching" class="w-full flex flex-col items-center">
|
<div v-else-if="template === QuestionCategoryEnum.ReversePoemMatching" class="w-full flex flex-col items-center">
|
||||||
<div class="options-container text-2xl">
|
<div class="mb-1 mt-20 text-5xl text-gray-800 font-bold leading-relaxed">
|
||||||
{{ title }}
|
|
||||||
</div>
|
|
||||||
<div class="mb-1 text-3xl text-gray-800 font-bold leading-relaxed">
|
|
||||||
<div class="rich-content" v-html="content" />
|
<div class="rich-content" v-html="content" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -206,7 +197,7 @@ watch(
|
|||||||
<div class="ptions-container1 mb-2 text-center text-2xl">
|
<div class="ptions-container1 mb-2 text-center text-2xl">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</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 }}
|
{{ content }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -413,5 +404,53 @@ watch(
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
vertical-align: middle;
|
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>
|
</style>
|
||||||
|
|||||||
@ -83,13 +83,13 @@ async function getUserRankList() {
|
|||||||
render(row: TeamData) {
|
render(row: TeamData) {
|
||||||
const rank = row.rank
|
const rank = row.rank
|
||||||
if (rank === 1) {
|
if (rank === 1) {
|
||||||
return <NTag type="warning" size="large" round>🏆</NTag>
|
return <NTag type="warning" size="large" class="!py-6 !text-3xl" round>🏆</NTag>
|
||||||
}
|
}
|
||||||
if (rank === 2) {
|
if (rank === 2) {
|
||||||
return <NTag type="info" size="large" round>🥈</NTag>
|
return <NTag type="info" size="large" class="!py-6 !text-3xl" round>🥈</NTag>
|
||||||
}
|
}
|
||||||
if (rank === 3) {
|
if (rank === 3) {
|
||||||
return <NTag type="success" size="large" round>🥉</NTag>
|
return <NTag type="success" size="large" class="!py-6 !text-3xl" round>🥉</NTag>
|
||||||
}
|
}
|
||||||
return <span>{rank}</span>
|
return <span>{rank}</span>
|
||||||
},
|
},
|
||||||
@ -140,14 +140,17 @@ function rowClassName(row: TeamData) {
|
|||||||
<div class="leaderboard-container">
|
<div class="leaderboard-container">
|
||||||
<div class="leaderboard-header">
|
<div class="leaderboard-header">
|
||||||
<NImage :src="title" alt="logo" preview-disabled class="mt--60px" object-fit="contain" />
|
<NImage :src="title" alt="logo" preview-disabled class="mt--60px" object-fit="contain" />
|
||||||
<p class="mt--20px text-center text-sm text-#6b778d">
|
<p class="mt--20px text-center text-lg text-#6b778d">
|
||||||
"勤学如春起之苗,不见其增,日有所长"
|
"勤学如春起之苗,不见其增,日有所长"
|
||||||
</p>
|
</p>
|
||||||
<ActionButton v-if="hasExtraTimeBtn" class="position-absolute bottom-20px right-20px" type="text" text="加时赛" @click="handleAddTime" />
|
<ActionButton
|
||||||
|
v-if="hasExtraTimeBtn" class="position-absolute bottom-20px right-20px" type="text" text="加时赛"
|
||||||
|
@click="handleAddTime"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="leaderboard-content">
|
<div class="leaderboard-content">
|
||||||
<NDataTable
|
<NDataTable
|
||||||
:columns="columns" :data="tableData" :bordered="false" :bottom-bordered="false"
|
:columns="columns" :data="tableData" :bordered="false" :bottom-bordered="false" size="large"
|
||||||
:row-class-name="rowClassName" class="rank-table"
|
:row-class-name="rowClassName" class="rank-table"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"question_bank": [
|
"question_bank": [
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>诗人袁枚写的与<strong>美食</strong>有关的书是( )。</p><p><br></p><p><strong> A.《食经》 B.《食珍录》 C.《红楼梦》 D.《随园食单》</strong></p>",
|
"Name": "<p>诗人袁枚写的与<strong>美食</strong>有关的书是( )。</p><p><strong> A.《食经》 B.《食珍录》 C.《红楼梦》 D.《随园食单》</strong></p>",
|
||||||
"Answer": "D",
|
"Answer": "D",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“我家洗砚池头树”引用了一位<strong>书法家</strong>的典故,这位书法家是( )。</p><p><br></p><p><strong> A.王献之 B.王羲之 C.王冕 D.柳公权</strong></p>",
|
"Name": "<p>“我家洗砚池头树”引用了一位<strong>书法家</strong>的典故,这位书法家是( )。</p><p><strong> A.王献之 B.王羲之 C.王冕 D.柳公权</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“诗中有画,画中有诗”评价的是( )。</p><p><br></p><p><strong> A.杜牧的诗画风格</strong></p><p><strong> B.刘禹锡的诗画风格</strong></p><p><strong> C.苏轼的诗画风格</strong></p><p><strong> D.王维的诗画风格</strong></p>",
|
"Name": "<p>“诗中有画,画中有诗”评价的是( )。</p><p><strong> A.杜牧的诗画风格</strong></p><p><strong> B.刘禹锡的诗画风格</strong></p><p><strong> C.苏轼的诗画风格</strong></p><p><strong> D.王维的诗画风格</strong></p>",
|
||||||
"Answer": "D",
|
"Answer": "D",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>被闻一多称为“<strong>诗中的诗</strong>,顶峰上的顶峰”的诗歌作品是( )。</p><p><br></p><p><strong> A.刘希夷的《代悲白头翁》</strong></p><p><strong> B.杨广的《春江花月夜》</strong></p><p><strong> C.张若虚的《春江花月夜》</strong></p><p><strong> D.李白的《蜀道难》</strong></p>",
|
"Name": "<p>被闻一多称为“<strong>诗中的诗</strong>,顶峰上的顶峰”的诗歌作品是( )。</p><p><strong> A.刘希夷的《代悲白头翁》</strong></p><p><strong> B.杨广的《春江花月夜》</strong></p><p><strong> C.张若虚的《春江花月夜》</strong></p><p><strong> D.李白的《蜀道难》</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -34,7 +34,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“<strong>梅妻鹤子</strong>”指的是( )。</p><p><br></p><p><strong> A.林逋 B.梅尧臣 C.苏舜钦 D.王安石</strong></p>",
|
"Name": "<p>“<strong>梅妻鹤子</strong>”指的是( )。</p><p><strong> A.林逋 B.梅尧臣 C.苏舜钦 D.王安石</strong></p>",
|
||||||
"Answer": "A",
|
"Answer": "A",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -42,7 +42,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“一门父子三词客,千古文章八大家。”这副对联中提到的“<strong>三父子</strong>”是( )。</p><p><br></p><p><strong> A.曹操、曹丕、曹植</strong></p><p><strong> B.苏洵、苏轼、苏辙</strong></p><p><strong> C.班彪、班固、班超</strong></p><p><strong> D.阮瑀、阮籍、阮咸</strong></p>",
|
"Name": "<p>“一门父子三词客,千古文章八大家。”这副对联中提到的“<strong>三父子</strong>”是( )。</p><p><strong> A.曹操、曹丕、曹植</strong></p><p><strong> B.苏洵、苏轼、苏辙</strong></p><p><strong> C.班彪、班固、班超</strong></p><p><strong> D.阮瑀、阮籍、阮咸</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -50,7 +50,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>诗人刘禹锡被<strong>称</strong>为( )。</p><p><br></p><p><strong> A.“诗鬼” B.“诗豪” C.“诗圣” D.“诗仙”</strong></p>",
|
"Name": "<p>诗人刘禹锡被<strong>称</strong>为( )。</p><p><strong> A.“诗鬼” B.“诗豪” C.“诗圣” D.“诗仙”</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -58,7 +58,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>有关诗人卢钺的信息,<strong>不正确</strong>的一项是( )。</p><p><br></p><p><strong> A.别号梅坡</strong></p><p><strong> B.代表作《雪梅》</strong></p><p><strong> C.与辛派词人陈亮是好友</strong></p><p><strong> D.宋朝人</strong></p>",
|
"Name": "<p>有关诗人卢钺的信息,<strong>不正确</strong>的一项是( )。</p><p><strong> A.别号梅坡</strong></p><p><strong> B.代表作《雪梅》</strong></p><p><strong> C.与辛派词人陈亮是好友</strong></p><p><strong> D.宋朝人</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -66,7 +66,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>诗人王昌龄被<strong>称</strong>为( )。</p><p><br></p><p><strong> A.“五言圣手” B.“七绝圣手” C.“七言圣手” D.“七绝诗人”</strong></p>",
|
"Name": "<p>诗人王昌龄被<strong>称</strong>为( )。</p><p><strong> A.“五言圣手” B.“七绝圣手” C.“七言圣手” D.“七绝诗人”</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -74,7 +74,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>李商隐与杜牧<strong>合称</strong>( )。</p><p><br></p><p><strong> A.“李杜” B.“杜李” C.“小李杜” D.“唐诗双杰”</strong></p>",
|
"Name": "<p>李商隐与杜牧<strong>合称</strong>( )。</p><p><strong> A.“李杜” B.“杜李” C.“小李杜” D.“唐诗双杰”</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -82,7 +82,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“南朝四百八十寺”中,“<strong>南朝</strong>”指的是( )。</p><p><br></p><p><strong> A.在南方建都的王朝</strong></p><p><strong> B.宋、齐、魏、陈四个朝代的总称</strong></p><p><strong> C.宋、齐、梁、陈四个朝代的总称</strong></p><p><strong> D.在南京建都的王朝</strong></p>",
|
"Name": "<p>“南朝四百八十寺”中,“<strong>南朝</strong>”指的是( )。</p><p><strong> A.在南方建都的王朝</strong></p><p><strong> B.宋、齐、魏、陈四个朝代的总称</strong></p><p><strong> C.宋、齐、梁、陈四个朝代的总称</strong></p><p><strong> D.在南京建都的王朝</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -90,7 +90,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“<strong>初唐四杰</strong>”是指( )。</p><p><br></p><p><strong> A.张若虚、张旭、孔融和贺知章</strong></p><p><strong> B.王勃、杨炯、卢照邻和骆宾王</strong></p><p><strong> C.高适、王昌龄、岑参和王之涣</strong></p><p><strong> D.贺知章、张若虚、张旭和包融</strong></p>",
|
"Name": "<p>“<strong>初唐四杰</strong>”是指( )。</p><p><strong> A.张若虚、张旭、孔融和贺知章</strong></p><p><strong> B.王勃、杨炯、卢照邻和骆宾王</strong></p><p><strong> C.高适、王昌龄、岑参和王之涣</strong></p><p><strong> D.贺知章、张若虚、张旭和包融</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"question_bank": [
|
"question_bank": [
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>诗人袁枚写的与<strong>美食</strong>有关的书是( )。</p><p><br></p><p><strong> A.《食经》 B.《食珍录》 C.《红楼梦》 D.《随园食单》</strong></p>",
|
"Name": "<p>诗人袁枚写的与<strong>美食</strong>有关的书是( )。</p><p><strong> A.《食经》 B.《食珍录》 C.《红楼梦》 D.《随园食单》</strong></p>",
|
||||||
"Answer": "D",
|
"Answer": "D",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“我家洗砚池头树”引用了一位<strong>书法家</strong>的典故,这位书法家是( )。</p><p><br></p><p><strong> A.王献之 B.王羲之 C.王冕 D.柳公权</strong></p>",
|
"Name": "<p>“我家洗砚池头树”引用了一位<strong>书法家</strong>的典故,这位书法家是( )。</p><p><strong> A.王献之 B.王羲之 C.王冕 D.柳公权</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“诗中有画,画中有诗”评价的是( )。</p><p><br></p><p><strong> A.杜牧的诗画风格</strong></p><p><strong> B.刘禹锡的诗画风格</strong></p><p><strong> C.苏轼的诗画风格</strong></p><p><strong> D.王维的诗画风格</strong></p>",
|
"Name": "<p>“诗中有画,画中有诗”评价的是( )。</p><p><strong> A.杜牧的诗画风格</strong></p><p><strong> B.刘禹锡的诗画风格</strong></p><p><strong> C.苏轼的诗画风格</strong></p><p><strong> D.王维的诗画风格</strong></p>",
|
||||||
"Answer": "D",
|
"Answer": "D",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>被闻一多称为“<strong>诗中的诗</strong>,顶峰上的顶峰”的诗歌作品是( )。</p><p><br></p><p><strong> A.刘希夷的《代悲白头翁》</strong></p><p><strong> B.杨广的《春江花月夜》</strong></p><p><strong> C.张若虚的《春江花月夜》</strong></p><p><strong> D.李白的《蜀道难》</strong></p>",
|
"Name": "<p>被闻一多称为“<strong>诗中的诗</strong>,顶峰上的顶峰”的诗歌作品是( )。</p><p><strong> A.刘希夷的《代悲白头翁》</strong></p><p><strong> B.杨广的《春江花月夜》</strong></p><p><strong> C.张若虚的《春江花月夜》</strong></p><p><strong> D.李白的《蜀道难》</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -34,7 +34,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“<strong>梅妻鹤子</strong>”指的是( )。</p><p><br></p><p><strong> A.林逋 B.梅尧臣 C.苏舜钦 D.王安石</strong></p>",
|
"Name": "<p>“<strong>梅妻鹤子</strong>”指的是( )。</p><p><strong> A.林逋 B.梅尧臣 C.苏舜钦 D.王安石</strong></p>",
|
||||||
"Answer": "A",
|
"Answer": "A",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -42,7 +42,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“一门父子三词客,千古文章八大家。”这副对联中提到的“<strong>三父子</strong>”是( )。</p><p><br></p><p><strong> A.曹操、曹丕、曹植</strong></p><p><strong> B.苏洵、苏轼、苏辙</strong></p><p><strong> C.班彪、班固、班超</strong></p><p><strong> D.阮瑀、阮籍、阮咸</strong></p>",
|
"Name": "<p>“一门父子三词客,千古文章八大家。”这副对联中提到的“<strong>三父子</strong>”是( )。</p><p><strong> A.曹操、曹丕、曹植</strong></p><p><strong> B.苏洵、苏轼、苏辙</strong></p><p><strong> C.班彪、班固、班超</strong></p><p><strong> D.阮瑀、阮籍、阮咸</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -50,7 +50,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>诗人刘禹锡被<strong>称</strong>为( )。</p><p><br></p><p><strong> A.“诗鬼” B.“诗豪” C.“诗圣” D.“诗仙”</strong></p>",
|
"Name": "<p>诗人刘禹锡被<strong>称</strong>为( )。</p><p><strong> A.“诗鬼” B.“诗豪” C.“诗圣” D.“诗仙”</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -58,7 +58,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>有关诗人卢钺的信息,<strong>不正确</strong>的一项是( )。</p><p><br></p><p><strong> A.别号梅坡</strong></p><p><strong> B.代表作《雪梅》</strong></p><p><strong> C.与辛派词人陈亮是好友</strong></p><p><strong> D.宋朝人</strong></p>",
|
"Name": "<p>有关诗人卢钺的信息,<strong>不正确</strong>的一项是( )。</p><p><strong> A.别号梅坡</strong></p><p><strong> B.代表作《雪梅》</strong></p><p><strong> C.与辛派词人陈亮是好友</strong></p><p><strong> D.宋朝人</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -66,7 +66,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>诗人王昌龄被<strong>称</strong>为( )。</p><p><br></p><p><strong> A.“五言圣手” B.“七绝圣手” C.“七言圣手” D.“七绝诗人”</strong></p>",
|
"Name": "<p>诗人王昌龄被<strong>称</strong>为( )。</p><p><strong> A.“五言圣手” B.“七绝圣手” C.“七言圣手” D.“七绝诗人”</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -74,7 +74,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>李商隐与杜牧<strong>合称</strong>( )。</p><p><br></p><p><strong> A.“李杜” B.“杜李” C.“小李杜” D.“唐诗双杰”</strong></p>",
|
"Name": "<p>李商隐与杜牧<strong>合称</strong>( )。</p><p><strong> A.“李杜” B.“杜李” C.“小李杜” D.“唐诗双杰”</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -82,7 +82,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“南朝四百八十寺”中,“<strong>南朝</strong>”指的是( )。</p><p><br></p><p><strong> A.在南方建都的王朝</strong></p><p><strong> B.宋、齐、魏、陈四个朝代的总称</strong></p><p><strong> C.宋、齐、梁、陈四个朝代的总称</strong></p><p><strong> D.在南京建都的王朝</strong></p>",
|
"Name": "<p>“南朝四百八十寺”中,“<strong>南朝</strong>”指的是( )。</p><p><strong> A.在南方建都的王朝</strong></p><p><strong> B.宋、齐、魏、陈四个朝代的总称</strong></p><p><strong> C.宋、齐、梁、陈四个朝代的总称</strong></p><p><strong> D.在南京建都的王朝</strong></p>",
|
||||||
"Answer": "C",
|
"Answer": "C",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
@ -90,7 +90,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"QuestionId": 34,
|
"QuestionId": 34,
|
||||||
"Name": "<p>“<strong>初唐四杰</strong>”是指( )。</p><p><br></p><p><strong> A.张若虚、张旭、孔融和贺知章</strong></p><p><strong> B.王勃、杨炯、卢照邻和骆宾王</strong></p><p><strong> C.高适、王昌龄、岑参和王之涣</strong></p><p><strong> D.贺知章、张若虚、张旭和包融</strong></p>",
|
"Name": "<p>“<strong>初唐四杰</strong>”是指( )。</p><p><strong> A.张若虚、张旭、孔融和贺知章</strong></p><p><strong> B.王勃、杨炯、卢照邻和骆宾王</strong></p><p><strong> C.高适、王昌龄、岑参和王之涣</strong></p><p><strong> D.贺知章、张若虚、张旭和包融</strong></p>",
|
||||||
"Answer": "B",
|
"Answer": "B",
|
||||||
"Type": "text",
|
"Type": "text",
|
||||||
"IsGood": 0,
|
"IsGood": 0,
|
||||||
|
|||||||