chore: 清理废弃的用户端答题流程代码并优化SCSS导入
移除废弃的`user copy`目录及其所有相关文件,包括组件、类型定义、模拟数据和图片 在vite配置中全局导入SCSS变量,移除各组件中冗余的`@import`语句 更新TypeScript配置以包含build目录,并优化SCSS颜色函数的使用
This commit is contained in:
@ -140,8 +140,6 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/scss/variables.scss';
|
||||
|
||||
.title-section {
|
||||
margin: 10px auto;
|
||||
width: 405px;
|
||||
|
||||
@ -1,179 +0,0 @@
|
||||
import type { CompetitionData } from '../types'
|
||||
import img from '@/assets/imgs/q5-img.png'
|
||||
|
||||
/**
|
||||
* 模拟数据
|
||||
* 真实后端数据可能是:
|
||||
* 活动详情接口,传活动id 获取 流程nodes
|
||||
* 每次可能只返回一个n1,前端先展示n1,用户点击“抽题”后,再请求n2。其中questions 可能不是在n1就返回,而是点击抽提时候 传nodeId 去随机获取后前端保存
|
||||
* 1. 包含 3 个节点(N1, N2, N3)
|
||||
* 2. 每个节点包含 2 个批次(汉字听一听, 汉字加一加)
|
||||
* 3. 每个批次包含 2 个问题(Q1, Q2, Q3, Q4, Q5)
|
||||
*/
|
||||
export const mockData: CompetitionData = {
|
||||
activityInfo: {
|
||||
name: '星·辞海遨游',
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
nodeId: 'N1',
|
||||
roundTitle: '第一轮',
|
||||
moduleName: '汉字听一听',
|
||||
batchName: '根据提示写汉字',
|
||||
description: '请根据汉语拼音提示书写正确的汉字,时间为15秒。',
|
||||
uiTemplate: 'TEMPLATE_DICTATION_HINT',
|
||||
config: { timeLimit: 5, questionCount: 2, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q1',
|
||||
content: { pinyin: 'jiū,表示小鸟的叫声', hint: '表示小鸟的叫声' },
|
||||
answer: ['啾'],
|
||||
},
|
||||
{
|
||||
id: 'Q2',
|
||||
content: { pinyin: 'yāo', hint: '形容草木茂盛美丽' },
|
||||
answer: ['夭'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N2',
|
||||
roundTitle: '第二轮',
|
||||
moduleName: '汉字听一听',
|
||||
batchName: '同音字',
|
||||
description: '诗词理解',
|
||||
uiTemplate: 'TEMPLATE_DICTATION_HOMOPHONE',
|
||||
config: { timeLimit: 5, questionCount: 2, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q3',
|
||||
content: { mainText: 'táng' },
|
||||
answer: ['唐', '塘', '糖', '搪', '溏', '瑭', '鄌', '螗', '糖', '堂', '膛', '螳', '鄳', '樘', '镗', '棠', '饧'],
|
||||
},
|
||||
{
|
||||
id: 'Q4',
|
||||
content: { mainText: 'jù' },
|
||||
answer: ['剧', '据', '巨', '拒', '聚', '炬', '距', '惧', '具', '俱', '沮', '咀', '矩', '锯'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N3',
|
||||
roundTitle: '第二轮',
|
||||
moduleName: '诗词理解',
|
||||
batchName: '选择题',
|
||||
description: '请选择正确的选项,时间为30秒。',
|
||||
uiTemplate: 'TEMPLATE_POETRY_MULTIPLE_CHOICE',
|
||||
config: { timeLimit: 30, questionCount: 2, scorePerQuestion: 2 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q3',
|
||||
content: {
|
||||
questionText: '《闻王昌龄左迁龙标遥有此寄》中,“左迁”的意思是()',
|
||||
options: [
|
||||
{ label: 'A', text: '贬官,降职', image: img },
|
||||
{ label: 'B', text: '搬家', image: img },
|
||||
{ label: 'C', text: '一路向西游玩', image: img },
|
||||
],
|
||||
},
|
||||
answer: ['A'],
|
||||
},
|
||||
{
|
||||
id: 'Q4',
|
||||
content: {
|
||||
questionText: '《静夜思》中,“举头望明月”的下一句是()',
|
||||
options: [
|
||||
{ label: 'A', text: '低头思故乡', image: img },
|
||||
{ label: 'B', text: '疑是地上霜', image: img },
|
||||
],
|
||||
},
|
||||
answer: ['A'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N4',
|
||||
roundTitle: '第三轮',
|
||||
moduleName: '汉字加一加',
|
||||
batchName: '部件组合',
|
||||
description: '请写出含有指定部件的汉字,时间为60秒。',
|
||||
uiTemplate: 'TEMPLATE_COMPONENT_ADD',
|
||||
config: { timeLimit: 5, questionCount: 1, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q5',
|
||||
content: { component: '车' },
|
||||
answer: ['辆', '轿', '转', '软', '轮', '辐', '输', '轨', '轩', '轻', '轶', '辄', '轴', '轧', '轼', '辊', '辕', '辙', '辍', '辗', '轸', '轭', '辚', '辖', '较', '辘', '轫', '轵', '辋', '轲', '轺', '臻', '软', '辌', '轷', '轻', '辁', '辒', '蚺', '韫', '轱', '辂', '轻', '轹', '辅', '舻', '辐', '斩', '连', '阵', '军', '轰', '库', '辈', '载', '辈', '晕', '辔'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N5',
|
||||
roundTitle: '第四轮',
|
||||
moduleName: '词语听写',
|
||||
batchName: '拼音写词',
|
||||
description: '请根据汉语拼音提示书写正确的词语,时间为30秒。',
|
||||
uiTemplate: 'TEMPLATE_WORD_DICTATION',
|
||||
config: { timeLimit: 5, questionCount: 2, scorePerQuestion: 2 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q6',
|
||||
content: { pinyin: 'zhì rè', hint: '形容温度极高' },
|
||||
answer: ['炙热'],
|
||||
},
|
||||
{
|
||||
id: 'Q7',
|
||||
content: { pinyin: 'hào hàn', hint: '形容广大繁多' },
|
||||
answer: ['浩瀚'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N6',
|
||||
roundTitle: '第五轮',
|
||||
moduleName: '成语写一写',
|
||||
batchName: '文字要求',
|
||||
description: '请根据要求书写正确的成语,时间为60秒。',
|
||||
uiTemplate: 'TEMPLATE_IDIOM_TEXT_REQ',
|
||||
config: { timeLimit: 5, questionCount: 1, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q8',
|
||||
content: { requirement: '请写出含有反义字的四字成语。' },
|
||||
answer: ['七上八下', '前因后果', '大同小异', '东张西望', '左顾右盼', '南辕北辙', '深入浅出', '出生入死', '死去活来', '天翻地覆', '黑白分明'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N7',
|
||||
roundTitle: '第六轮',
|
||||
moduleName: '成语写一写',
|
||||
batchName: '看图写成语',
|
||||
description: '请根据图片书写正确的成语,时间为30秒。',
|
||||
uiTemplate: 'TEMPLATE_IDIOM_IMAGE',
|
||||
config: { timeLimit: 30, questionCount: 2, scorePerQuestion: 2 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q9',
|
||||
content: { hint: '比喻事情已定', image: img },
|
||||
answer: ['板上钉钉'],
|
||||
},
|
||||
{
|
||||
id: 'Q10',
|
||||
content: { hint: '比喻事情已定', image: img },
|
||||
answer: ['板上钉钉'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const uiTemplatesMapping = {
|
||||
TEMPLATE_DICTATION_HINT: '汉字听写-提示',
|
||||
TEMPLATE_DICTATION_HOMOPHONE: '汉字听写-同音',
|
||||
TEMPLATE_COMPONENT_ADD: '汉字加一加',
|
||||
TEMPLATE_WORD_DICTATION: '词语听写',
|
||||
TEMPLATE_IDIOM_TEXT_REQ: '成语-文字要求',
|
||||
TEMPLATE_IDIOM_IMAGE: '成语-看图',
|
||||
TEMPLATE_POETRY_MULTIPLE_CHOICE: '诗词理解-选择题',
|
||||
}
|
||||
@ -1,223 +0,0 @@
|
||||
import type { CompetitionData } from '../types'
|
||||
import img from '@/assets/imgs/q5-img.png'
|
||||
|
||||
/**
|
||||
* 模拟数据
|
||||
* 真实后端数据可能是:
|
||||
* 活动详情接口,传活动id 获取 流程nodes
|
||||
* 每次可能只返回一个n1,前端先展示n1,用户点击“抽题”后,再请求n2。其中questions 可能不是在n1就返回,而是点击抽提时候 传nodeId 去随机获取后前端保存
|
||||
* 1. 包含 3 个节点(N1, N2, N3)
|
||||
* 2. 每个节点包含 2 个批次(汉字听一听, 汉字加一加)
|
||||
* 3. 每个批次包含 2 个问题(Q1, Q2, Q3, Q4, Q5)
|
||||
*/
|
||||
export const mockData: CompetitionData = {
|
||||
activityInfo: {
|
||||
name: '星·辞海遨游',
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
nodeId: 'N3',
|
||||
roundTitle: '第二轮',
|
||||
moduleName: '诗词理解',
|
||||
batchName: '选择题',
|
||||
description: '请选择正确的选项,时间为30秒。',
|
||||
uiTemplate: 'TEMPLATE_POETRY_MULTIPLE_CHOICE',
|
||||
config: { timeLimit: 300, questionCount: 2, scorePerQuestion: 2 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q3',
|
||||
content: {
|
||||
title: '《闻王昌龄左迁龙标遥有此寄》中,“左迁”的意思是()',
|
||||
options: [
|
||||
{ label: 'A', text: '贬官,降职', image: img },
|
||||
{ label: 'B', text: '搬家', image: img },
|
||||
{ label: 'C', text: '一路向西游玩', image: img },
|
||||
],
|
||||
},
|
||||
answer: ['A'],
|
||||
},
|
||||
{
|
||||
id: 'Q4',
|
||||
content: {
|
||||
title: '《静夜思》中,“举头望明月”的下一句是()',
|
||||
options: [
|
||||
{ label: 'A', text: '低头思故乡', image: img },
|
||||
{ label: 'B', text: '疑是地上霜', image: img },
|
||||
],
|
||||
},
|
||||
answer: ['A'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N1',
|
||||
roundTitle: '第一轮',
|
||||
moduleName: '汉字听一听',
|
||||
batchName: '根据提示写汉字',
|
||||
description: '请根据汉语拼音提示书写正确的汉字,时间为15秒。',
|
||||
uiTemplate: 'TEMPLATE_DICTATION_HINT',
|
||||
config: { timeLimit: 5, questionCount: 2, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q1',
|
||||
content: {
|
||||
title: 'jiū,表示小鸟的叫声',
|
||||
meta: { hint: '表示小鸟的叫声' },
|
||||
},
|
||||
answer: ['啾'],
|
||||
},
|
||||
{
|
||||
id: 'Q2',
|
||||
content: {
|
||||
title: 'yāo',
|
||||
meta: { hint: '形容草木茂盛美丽' },
|
||||
},
|
||||
answer: ['夭'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N2',
|
||||
roundTitle: '第二轮',
|
||||
moduleName: '汉字听一听',
|
||||
batchName: '同音字',
|
||||
description: '诗词理解',
|
||||
uiTemplate: 'TEMPLATE_DICTATION_HOMOPHONE',
|
||||
config: { timeLimit: 5, questionCount: 2, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q3',
|
||||
content: { title: 'táng' },
|
||||
answer: ['唐', '塘', '糖', '搪', '溏', '瑭', '鄌', '螗', '糖', '堂', '膛', '螳', '鄳', '樘', '镗', '棠', '饧'],
|
||||
},
|
||||
{
|
||||
id: 'Q4',
|
||||
content: { title: 'jù' },
|
||||
answer: ['剧', '据', '巨', '拒', '聚', '炬', '距', '惧', '具', '俱', '沮', '咀', '矩', '锯'],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
nodeId: 'N4',
|
||||
roundTitle: '第三轮',
|
||||
moduleName: '汉字加一加',
|
||||
batchName: '部件组合',
|
||||
description: '请写出含有指定部件的汉字,时间为60秒。',
|
||||
uiTemplate: 'TEMPLATE_COMPONENT_ADD',
|
||||
config: { timeLimit: 5, questionCount: 1, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q5',
|
||||
content: { title: '车' },
|
||||
answer: ['辆', '轿', '转', '软', '轮', '辐', '输', '轨', '轩', '轻', '轶', '辄', '轴', '轧', '轼', '辊', '辕', '辙', '辍', '辗', '轸', '轭', '辚', '辖', '较', '辘', '轫', '轵', '辋', '轲', '轺', '臻', '软', '辌', '轷', '轻', '辁', '辒', '蚺', '韫', '轱', '辂', '轻', '轹', '辅', '舻', '辐', '斩', '连', '阵', '军', '轰', '库', '辈', '载', '辈', '晕', '辔'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N5',
|
||||
roundTitle: '第四轮',
|
||||
moduleName: '词语听写',
|
||||
batchName: '拼音写词',
|
||||
description: '请根据汉语拼音提示书写正确的词语,时间为30秒。',
|
||||
uiTemplate: 'TEMPLATE_WORD_DICTATION',
|
||||
config: { timeLimit: 5, questionCount: 2, scorePerQuestion: 2 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q6',
|
||||
content: {
|
||||
title: 'zhì rè',
|
||||
meta: { hint: '形容温度极高' },
|
||||
},
|
||||
answer: ['炙热'],
|
||||
},
|
||||
{
|
||||
id: 'Q7',
|
||||
content: {
|
||||
title: 'hào hàn',
|
||||
meta: { hint: '形容广大繁多' },
|
||||
},
|
||||
answer: ['浩瀚'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N6',
|
||||
roundTitle: '第五轮',
|
||||
moduleName: '成语写一写',
|
||||
batchName: '文字要求',
|
||||
description: '请根据要求书写正确的成语,时间为60秒。',
|
||||
uiTemplate: 'TEMPLATE_IDIOM_TEXT_REQ',
|
||||
config: { timeLimit: 5, questionCount: 1, scorePerQuestion: 1 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q8',
|
||||
content: { title: '请写出含有反义字的四字成语。' },
|
||||
answer: ['七上八下', '前因后果', '大同小异', '东张西望', '左顾右盼', '南辕北辙', '深入浅出', '出生入死', '死去活来', '天翻地覆', '黑白分明'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N7',
|
||||
roundTitle: '第六轮',
|
||||
moduleName: '成语写一写',
|
||||
batchName: '看图写成语',
|
||||
description: '请根据图片书写正确的成语,时间为30秒。',
|
||||
uiTemplate: 'TEMPLATE_IDIOM_IMAGE',
|
||||
config: { timeLimit: 30, questionCount: 2, scorePerQuestion: 2 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q9',
|
||||
content: {
|
||||
title: '',
|
||||
titleImage: img,
|
||||
meta: { hint: '比喻事情已定' },
|
||||
},
|
||||
answer: ['板上钉钉'],
|
||||
},
|
||||
{
|
||||
id: 'Q10',
|
||||
content: {
|
||||
title: '',
|
||||
titleImage: img,
|
||||
meta: { hint: '比喻事情已定' },
|
||||
},
|
||||
answer: ['板上钉钉'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
nodeId: 'N8',
|
||||
roundTitle: '第七轮',
|
||||
moduleName: '汉字辨析',
|
||||
batchName: '选字填空',
|
||||
description: '请选择正确的汉字填入括号中。',
|
||||
uiTemplate: 'TEMPLATE_POETRY_MULTIPLE_CHOICE',
|
||||
config: { timeLimit: 20, questionCount: 1, scorePerQuestion: 2 },
|
||||
questions: [
|
||||
{
|
||||
id: 'Q11',
|
||||
content: {
|
||||
title: '下列哪个字是“没”的繁体字?',
|
||||
options: [
|
||||
{ label: 'A', text: '没', renderType: 'tianzige' },
|
||||
{ label: 'B', text: '沒', renderType: 'tianzige' },
|
||||
{ label: 'C', text: '殁', renderType: 'tianzige' },
|
||||
],
|
||||
},
|
||||
answer: ['B'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const uiTemplatesMapping = {
|
||||
TEMPLATE_DICTATION_HINT: '汉字听写-提示',
|
||||
TEMPLATE_DICTATION_HOMOPHONE: '汉字听写-同音',
|
||||
TEMPLATE_COMPONENT_ADD: '汉字加一加',
|
||||
TEMPLATE_WORD_DICTATION: '词语听写',
|
||||
TEMPLATE_IDIOM_TEXT_REQ: '成语-文字要求',
|
||||
TEMPLATE_IDIOM_IMAGE: '成语-看图',
|
||||
TEMPLATE_POETRY_MULTIPLE_CHOICE: '诗词理解-选择题',
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB |
@ -1,168 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onUnmounted, ref } from 'vue'
|
||||
import { mockData } from './data/mock' // 引入模拟数据
|
||||
import AnswerAnalysisComp from './modules/AnswerAnalysisComp.vue'
|
||||
import CoverComp from './modules/CoverComp.vue' // 封面组件
|
||||
import GameComp from './modules/GameComp.vue'
|
||||
import IntroComp from './modules/IntroComp.vue'
|
||||
|
||||
// 状态定义
|
||||
type Status = 'COVER' | 'INTRO' | 'GAME' | 'ANSWER_ANALYSIS'
|
||||
|
||||
const status = ref<Status>('COVER')
|
||||
const data = ref(mockData)
|
||||
|
||||
// 索引控制
|
||||
const currentStep = ref(0) // Node 索引
|
||||
const subStep = ref(0) // Question 索引
|
||||
|
||||
// 定时器控制
|
||||
const timeLeft = ref(0)
|
||||
let timerInterval: number | null = null
|
||||
|
||||
// --- 计算属性 ---
|
||||
const currentNode = computed(() => data.value.nodes[currentStep.value])
|
||||
const currentQuestion = computed(() => {
|
||||
// 保护性代码:防止越界
|
||||
const questions = currentNode.value.questions
|
||||
return questions[subStep.value] || questions[0]
|
||||
})
|
||||
|
||||
// --- 动作处理 ---
|
||||
|
||||
// 1. 开始比赛 -> 去第一个环节的介绍页
|
||||
function handleStart() {
|
||||
currentStep.value = 0
|
||||
subStep.value = 0
|
||||
status.value = 'INTRO'
|
||||
}
|
||||
|
||||
// 2. 抽题 -> 去答题页,重置时间
|
||||
function handleDraw() {
|
||||
status.value = 'GAME'
|
||||
timeLeft.value = currentNode.value.config.timeLimit
|
||||
startTimer()
|
||||
}
|
||||
|
||||
// 3. 定时器逻辑
|
||||
function startTimer() {
|
||||
if (timerInterval)
|
||||
clearInterval(timerInterval)
|
||||
timerInterval = window.setInterval(() => {
|
||||
if (timeLeft.value > 0) {
|
||||
timeLeft.value--
|
||||
}
|
||||
else {
|
||||
// 时间到,清除定时器,进入答题图解页面
|
||||
if (timerInterval)
|
||||
clearInterval(timerInterval)
|
||||
status.value = 'ANSWER_ANALYSIS'
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 4. 下一题逻辑 (核心流程)
|
||||
function handleToAnalysis() {
|
||||
if (timerInterval)
|
||||
clearInterval(timerInterval)
|
||||
status.value = 'ANSWER_ANALYSIS'
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
if (timerInterval)
|
||||
clearInterval(timerInterval)
|
||||
|
||||
const totalQuestionsInNode = currentNode.value.config.questionCount
|
||||
|
||||
// A. 如果当前环节还有题
|
||||
if (subStep.value < totalQuestionsInNode - 1 && subStep.value < currentNode.value.questions.length - 1) {
|
||||
subStep.value++
|
||||
// 回到介绍页(抽题页),等待用户点击“抽题”再次开始
|
||||
status.value = 'INTRO'
|
||||
}
|
||||
// B. 当前环节结束,去下一个环节
|
||||
else {
|
||||
if (currentStep.value < data.value.nodes.length - 1) {
|
||||
currentStep.value++
|
||||
subStep.value = 0
|
||||
status.value = 'INTRO' // 回到介绍页
|
||||
}
|
||||
else {
|
||||
// 全部结束
|
||||
window.$message?.success('全场比赛结束!')
|
||||
status.value = 'COVER'
|
||||
currentStep.value = 0
|
||||
subStep.value = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timerInterval)
|
||||
clearInterval(timerInterval)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-app-container relative h-screen w-full overflow-hidden font-sans">
|
||||
<!-- 背景图占位 (实际项目中应为 img 或 background-image) -->
|
||||
<div class="absolute inset-0 z-0 bg-blue-100/50">
|
||||
<!-- 模拟云纹/山水背景 -->
|
||||
<div class="absolute bottom-0 h-1/3 w-full from-teal-200/50 to-transparent bg-gradient-to-t" />
|
||||
<div class="absolute top-0 h-1/4 w-full from-blue-200/50 to-transparent bg-gradient-to-b" />
|
||||
</div>
|
||||
|
||||
<!-- 顶部左右信息 (固定) -->
|
||||
<div class="absolute left-6 top-4 z-20 text-lg text-gray-700 font-medium tracking-wide">
|
||||
教育学会
|
||||
</div>
|
||||
<div class="absolute right-6 top-4 z-20 text-lg text-gray-700 font-medium tracking-wide">
|
||||
树人研究院
|
||||
</div>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<div class="relative z-10 h-full w-full">
|
||||
<!-- 状态 1: 封面 -->
|
||||
<CoverComp
|
||||
v-if="status === 'COVER'"
|
||||
:title="data.activityInfo.name"
|
||||
:nodes="data.nodes"
|
||||
@start="handleStart"
|
||||
/>
|
||||
|
||||
<!-- 状态 2: 介绍页 -->
|
||||
<IntroComp
|
||||
v-else-if="status === 'INTRO'"
|
||||
:node="currentNode"
|
||||
@back="status = 'COVER'"
|
||||
@draw="handleDraw"
|
||||
/>
|
||||
|
||||
<!-- 状态 3: 答题页 -->
|
||||
<GameComp
|
||||
v-else-if="status === 'GAME'"
|
||||
:node="currentNode"
|
||||
:question="currentQuestion"
|
||||
:sub-step="subStep"
|
||||
:time-left="timeLeft"
|
||||
@back="status = 'INTRO'"
|
||||
@next="handleToAnalysis"
|
||||
/>
|
||||
|
||||
<!-- 状态 4: 答题图解页 -->
|
||||
<AnswerAnalysisComp
|
||||
v-else-if="status === 'ANSWER_ANALYSIS'"
|
||||
:question-id="currentQuestion.id"
|
||||
@back="status = 'GAME'"
|
||||
@next="handleNext"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-app-container {
|
||||
/* 基础背景色,防止图片加载失败时太突兀 */
|
||||
background-color: #eef7ff;
|
||||
}
|
||||
</style>
|
||||
@ -1,166 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
questionId?: string
|
||||
}>()
|
||||
|
||||
defineEmits(['back', 'next'])
|
||||
|
||||
const zoomedImage = ref<string | null>(null)
|
||||
|
||||
// Mock team data
|
||||
const teams = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: '第一队',
|
||||
writtenCount: 16,
|
||||
correctCount: 13,
|
||||
score: 13,
|
||||
manualScore: null as number | null,
|
||||
image: 'https://via.placeholder.com/300x400?text=Team+1+Answer', // Placeholder for now
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '第二队',
|
||||
writtenCount: 15,
|
||||
correctCount: 12,
|
||||
score: 12,
|
||||
manualScore: null as number | null,
|
||||
image: 'https://via.placeholder.com/300x400?text=Team+2+Answer',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '第三队',
|
||||
writtenCount: 18,
|
||||
correctCount: 15,
|
||||
score: 15,
|
||||
manualScore: null as number | null,
|
||||
image: 'https://via.placeholder.com/300x400?text=Team+3+Answer',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '第四队',
|
||||
writtenCount: 14,
|
||||
correctCount: 10,
|
||||
score: 10,
|
||||
manualScore: null as number | null,
|
||||
image: 'https://via.placeholder.com/300x400?text=Team+4+Answer',
|
||||
},
|
||||
])
|
||||
|
||||
function handleZoom(img: string) {
|
||||
zoomedImage.value = img
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative h-full w-full flex flex-col items-center px-12 pt-28">
|
||||
<!-- Top Bar -->
|
||||
<div class="relative z-10 mb-6 w-full flex items-center justify-between">
|
||||
<!-- Back Button -->
|
||||
<button
|
||||
class="border-2 border-red-400 rounded-full bg-white px-8 py-2 text-lg text-red-500 font-bold shadow-md transition hover:bg-red-50"
|
||||
@click="$emit('back')"
|
||||
>
|
||||
返回
|
||||
</button>
|
||||
|
||||
<!-- Title Scroll -->
|
||||
<div class="absolute left-1/2 top-0 -translate-x-1/2">
|
||||
<div class="relative h-20 min-w-[300px] flex items-center justify-center border-2 border-orange-200 rounded-lg from-orange-100 to-orange-50 bg-gradient-to-b px-12 shadow-lg">
|
||||
<div class="absolute top-1/2 h-24 w-6 border-r-4 border-yellow-600 rounded-l-md bg-teal-700 shadow-md -left-3 -translate-y-1/2">
|
||||
<div class="absolute left-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 left-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
<div class="absolute top-1/2 h-24 w-6 border-l-4 border-yellow-600 rounded-r-md bg-teal-700 shadow-md -right-3 -translate-y-1/2">
|
||||
<div class="absolute right-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 right-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
<h1 class="text-3xl text-gray-800 font-bold tracking-widest font-serif">
|
||||
答题图解
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Next Button -->
|
||||
<button
|
||||
class="border-2 border-red-400 rounded-full bg-white px-8 py-2 text-lg text-red-500 font-bold shadow-md transition hover:bg-red-50"
|
||||
@click="$emit('next')"
|
||||
>
|
||||
下一题
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="w-full flex flex-col flex-1 overflow-hidden">
|
||||
<div class="mb-2 text-xl text-red-600 font-bold">
|
||||
备注:由AI模型评判
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 h-full gap-6 pb-8">
|
||||
<div v-for="team in teams" :key="team.id" class="flex flex-col border-2 border-gray-200 rounded-xl bg-white/90 p-4 shadow-sm">
|
||||
<div class="mb-2 text-xl text-gray-800 font-bold">
|
||||
{{ team.name }}
|
||||
</div>
|
||||
|
||||
<!-- Answer Image Area -->
|
||||
<div class="relative mb-4 flex-1 cursor-zoom-in overflow-hidden border border-gray-300 rounded bg-gray-50" @click="handleZoom(team.image)">
|
||||
<!-- Grid Background Simulation -->
|
||||
<div class="pointer-events-none absolute inset-0 grid grid-cols-8 gap-px bg-gray-200 opacity-20">
|
||||
<div v-for="n in 64" :key="n" class="bg-white" />
|
||||
</div>
|
||||
<!-- Simulated Handwriting/Content -->
|
||||
<div class="absolute inset-0 flex items-center justify-center text-gray-400">
|
||||
(点击放大查看详情)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats & Score -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="text-sm text-gray-700 font-medium">
|
||||
写了数量{{ team.writtenCount }},正确{{ team.correctCount }}个,积分{{ team.score }}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-red-500 font-bold">评委当场评</span>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<input
|
||||
v-model="team.manualScore"
|
||||
type="number"
|
||||
class="w-full border border-gray-300 rounded px-3 py-2 text-sm focus:border-blue-500 focus:outline-none"
|
||||
placeholder="留个输入框,修改正确积分"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zoom Modal -->
|
||||
<div v-if="zoomedImage" class="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm" @click="zoomedImage = null">
|
||||
<div class="relative max-h-[90vh] max-w-[90vw] p-4">
|
||||
<img :src="zoomedImage" class="max-h-full max-w-full rounded bg-white shadow-2xl" alt="Zoomed Answer">
|
||||
<div class="absolute bottom-4 left-1/2 text-sm text-white/80 -translate-x-1/2">
|
||||
点击任意处关闭
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Custom Scrollbar for content if needed */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
@ -1,81 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { ActivityNode } from '../types'
|
||||
|
||||
defineProps<{
|
||||
title: string
|
||||
nodes: ActivityNode[]
|
||||
}>()
|
||||
|
||||
defineEmits(['start'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full w-full flex flex-col items-center pt-24">
|
||||
<!-- 标题卷轴 -->
|
||||
<div class="relative mb-20">
|
||||
<!-- 卷轴主体 -->
|
||||
<div class="relative z-10 h-24 min-w-[400px] flex items-center justify-center border-2 border-orange-200 rounded-lg from-orange-100 to-orange-50 bg-gradient-to-b px-12 shadow-lg">
|
||||
<div class="absolute top-1/2 h-28 w-8 border-r-4 border-yellow-600 rounded-l-md bg-teal-700 shadow-md -left-4 -translate-y-1/2">
|
||||
<!-- 卷轴轴头 -->
|
||||
<div class="absolute left-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 left-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
<div class="absolute top-1/2 h-28 w-8 border-l-4 border-yellow-600 rounded-r-md bg-teal-700 shadow-md -right-4 -translate-y-1/2">
|
||||
<!-- 卷轴轴头 -->
|
||||
<div class="absolute right-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 right-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
|
||||
<!-- 飘带装饰 -->
|
||||
<div class="absolute h-12 w-24 rotate-12 transform rounded-full bg-green-200/50 blur-xl -right-12 -top-6 -z-10" />
|
||||
<div class="absolute h-12 w-24 transform rounded-full bg-green-200/50 blur-xl -bottom-6 -left-12 -z-10 -rotate-12" />
|
||||
|
||||
<h1 class="text-4xl text-gray-800 font-bold tracking-widest font-serif">
|
||||
{{ title }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 卡片列表 -->
|
||||
<div class="grid grid-cols-4 max-w-7xl w-full gap-8 px-12">
|
||||
<div
|
||||
v-for="(node) in nodes.slice(0, 4)"
|
||||
:key="node.nodeId"
|
||||
class="group relative cursor-default"
|
||||
>
|
||||
<!-- 卡片背景 (仿古风) -->
|
||||
<div class="relative aspect-[3/4] w-full flex flex-col items-center justify-center overflow-hidden border-4 border-orange-200 rounded-2xl bg-orange-50/80 shadow-lg transition-transform hover:-translate-y-2">
|
||||
<!-- 内部装饰圈 -->
|
||||
<div class="absolute inset-4 flex items-center justify-center border-2 border-orange-300/50 rounded-xl border-dashed">
|
||||
<!-- 云纹装饰 (CSS模拟) -->
|
||||
<div class="absolute h-12 w-12 rounded-full bg-teal-100/30 blur-md -left-4 -top-4" />
|
||||
<div class="absolute h-12 w-12 rounded-full bg-teal-100/30 blur-md -bottom-4 -right-4" />
|
||||
</div>
|
||||
|
||||
<!-- 文字内容 -->
|
||||
<div class="relative z-10 transform text-center -rotate-2">
|
||||
<div class="text-3xl text-gray-800 font-bold leading-tight font-serif drop-shadow-sm">
|
||||
<!-- 强制换行处理,每两个字换行或根据长度 -->
|
||||
<span class="block">{{ node.moduleName.slice(0, 2) }}</span>
|
||||
<span class="block">{{ node.moduleName.slice(2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 准备开始按钮 -->
|
||||
<div class="fixed bottom-12 right-12">
|
||||
<button
|
||||
class="border-2 border-red-200 rounded-full from-red-400 to-red-500 bg-gradient-to-r px-10 py-3 text-xl text-white font-bold shadow-lg transition active:scale-95 hover:from-red-500 hover:to-red-600"
|
||||
@click="$emit('start')"
|
||||
>
|
||||
准备开始
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 可以添加一些古风字体或特定样式 */
|
||||
</style>
|
||||
@ -1,148 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { ActivityNode, Question } from '../types'
|
||||
import { computed } from 'vue'
|
||||
import { uiTemplatesMapping } from '../data/mock'
|
||||
import QuestionRenderer from './QuestionRenderer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
node: ActivityNode
|
||||
question: Question
|
||||
subStep: number
|
||||
timeLeft: number
|
||||
}>()
|
||||
|
||||
defineEmits(['back', 'next'])
|
||||
|
||||
const formattedTime = computed(() => {
|
||||
const m = Math.floor(props.timeLeft / 60)
|
||||
const s = props.timeLeft % 60
|
||||
return `${m}:${s < 10 ? `0${s}` : s}`
|
||||
})
|
||||
|
||||
// Mock chart data
|
||||
const chartData = [
|
||||
{ group: '第一组', total: 42, correct: 36 },
|
||||
{ group: '第二组', total: 20, correct: 16 },
|
||||
{ group: '第三组', total: 19, correct: 19 },
|
||||
{ group: '第四组', total: 17, correct: 14 },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative h-full w-full flex flex-col items-center px-12 pt-28">
|
||||
<!-- 顶部栏 -->
|
||||
<div class="relative z-10 mb-8 w-full flex items-center justify-between">
|
||||
<!-- 返回按钮 -->
|
||||
<button
|
||||
class="border-2 border-red-400 rounded-full bg-white px-8 py-2 text-lg text-red-500 font-bold shadow-md transition hover:bg-red-50"
|
||||
@click="$emit('back')"
|
||||
>
|
||||
返回
|
||||
</button>
|
||||
|
||||
<!-- 标题卷轴 -->
|
||||
<div class="absolute left-1/2 top-0 -translate-x-1/2">
|
||||
<div
|
||||
class="relative h-20 min-w-[300px] flex items-center justify-center border-2 border-orange-200 rounded-lg from-orange-100 to-orange-50 bg-gradient-to-b px-12 shadow-lg"
|
||||
>
|
||||
<div
|
||||
class="absolute top-1/2 h-24 w-6 border-r-4 border-yellow-600 rounded-l-md bg-teal-700 shadow-md -left-3 -translate-y-1/2"
|
||||
>
|
||||
<div class="absolute left-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 left-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
<div
|
||||
class="absolute top-1/2 h-24 w-6 border-l-4 border-yellow-600 rounded-r-md bg-teal-700 shadow-md -right-3 -translate-y-1/2"
|
||||
>
|
||||
<div class="absolute right-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 right-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
<h1 class="text-3xl text-gray-800 font-bold tracking-widest font-serif">
|
||||
{{ node.moduleName }}
|
||||
<span class="text-sm text-red-500 font-bold">({{ uiTemplatesMapping[node.uiTemplate] }})</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 倒计时 -->
|
||||
<div class="border-2 border-red-400 rounded-full bg-white px-6 py-2 shadow-md">
|
||||
<span class="text-xl text-red-500 font-bold">倒计时 {{ formattedTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 题目说明 -->
|
||||
<div class="m-14 text-2xl text-gray-800 font-medium">
|
||||
{{ node.description }}
|
||||
</div>
|
||||
|
||||
<!-- 题目内容区域 -->
|
||||
<div class="flex-2 mb-4 w-full flex items-center justify-center">
|
||||
<QuestionRenderer
|
||||
:template="node.uiTemplate" :content="question.content"
|
||||
class="origin-center scale-150 transform"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 隐藏的 Next 按钮 (点击题目区域或键盘操作,这里为了演示保留一个透明层或仅通过逻辑触发,或者暂时放一个不易察觉的按钮用于测试) -->
|
||||
<div class="absolute inset-0 z-0" @click="$emit('next')" /> <!-- 点击背景切换下一题,方便演示 -->
|
||||
|
||||
<!-- 底部图表区域 -->
|
||||
<div
|
||||
class="relative z-20 mb-8 h-64 max-w-5xl w-full flex flex-col border-2 border-blue-300 rounded-xl bg-white/90 p-4 shadow-lg backdrop-blur"
|
||||
>
|
||||
<!-- 图表标题栏 -->
|
||||
<div class="mb-4 flex items-center justify-between px-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="h-3 w-3 rotate-45 bg-orange-400" />
|
||||
<span class="text-lg text-blue-800 font-bold">答题进度</span>
|
||||
</div>
|
||||
<div class="flex gap-6 text-sm">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="h-3 w-3 rounded-full bg-blue-400" />
|
||||
<span class="text-gray-600">答题数量</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="h-3 w-3 rounded-full bg-orange-300" />
|
||||
<span class="text-gray-600">正确数量</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 柱状图 -->
|
||||
<div class="flex flex-1 items-end justify-around px-8 pb-2">
|
||||
<div v-for="item in chartData" :key="item.group" class="w-16 flex flex-col items-center gap-2">
|
||||
<div class="h-32 flex items-end gap-2">
|
||||
<!-- Blue Bar -->
|
||||
<div
|
||||
class="relative w-6 rounded-t-md from-blue-500 to-blue-300 bg-gradient-to-t transition-all duration-1000"
|
||||
:style="{ height: `${item.total * 2}px` }"
|
||||
>
|
||||
<span class="absolute left-1/2 text-blue-800 font-bold -top-6 -translate-x-1/2">{{ item.total }}</span>
|
||||
</div>
|
||||
<!-- Orange Bar -->
|
||||
<div
|
||||
class="relative w-6 rounded-t-md from-orange-400 to-orange-200 bg-gradient-to-t transition-all duration-1000"
|
||||
:style="{ height: `${item.correct * 2}px` }"
|
||||
>
|
||||
<span class="absolute left-1/2 text-orange-600 font-bold -top-6 -translate-x-1/2">{{ item.correct
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-blue-800 font-bold">
|
||||
{{ item.group }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Question Renderer Override if needed */
|
||||
:deep(.question-content) {
|
||||
font-size: 4rem;
|
||||
color: #ef4444;
|
||||
/* red-500 */
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
@ -1,63 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { ActivityNode } from '../types'
|
||||
|
||||
defineProps<{ node: ActivityNode }>()
|
||||
defineEmits(['back', 'draw'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full w-full flex flex-col items-center pt-44">
|
||||
<!-- 标题卷轴 -->
|
||||
<div class="relative mb-16">
|
||||
<div class="relative z-10 h-20 min-w-[300px] flex items-center justify-center border-2 border-orange-200 rounded-lg from-orange-100 to-orange-50 bg-gradient-to-b px-12 shadow-lg">
|
||||
<div class="absolute top-1/2 h-24 w-6 border-r-4 border-yellow-600 rounded-l-md bg-teal-700 shadow-md -left-3 -translate-y-1/2">
|
||||
<div class="absolute left-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 left-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
<div class="absolute top-1/2 h-24 w-6 border-l-4 border-yellow-600 rounded-r-md bg-teal-700 shadow-md -right-3 -translate-y-1/2">
|
||||
<div class="absolute right-1 top-2 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
<div class="absolute bottom-2 right-1 h-2 w-full rounded-full bg-teal-600/50" />
|
||||
</div>
|
||||
<h1 class="text-3xl text-gray-800 font-bold tracking-widest font-serif">
|
||||
{{ node.moduleName }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 规则描述 -->
|
||||
<div class="mb-20 max-w-4xl text-center">
|
||||
<div class="text-2xl text-gray-800 font-medium leading-relaxed tracking-wide">
|
||||
{{ node.description }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 抽题按钮 (大圆形) -->
|
||||
<div class="group relative">
|
||||
<button
|
||||
class="h-64 w-64 flex flex-col items-center justify-center border-4 border-blue-400 rounded-full bg-gray-200/80 text-3xl text-gray-700 font-bold shadow-xl transition-all active:scale-95 hover:scale-105"
|
||||
@click="$emit('draw')"
|
||||
>
|
||||
<span>抽题</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="fixed bottom-12 left-12">
|
||||
<button
|
||||
class="border-2 border-red-400 rounded-full bg-white px-10 py-2 text-xl text-red-500 font-bold shadow-md transition hover:bg-red-50"
|
||||
@click="$emit('back')"
|
||||
>
|
||||
返回
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="fixed bottom-12 right-12">
|
||||
<button
|
||||
class="rounded-full from-red-400 to-red-500 bg-gradient-to-r px-10 py-2 text-xl text-white font-bold shadow-lg transition hover:from-red-500 hover:to-red-600"
|
||||
@click="$emit('draw')"
|
||||
>
|
||||
开始答题
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,120 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { QuestionContent, UiTemplateType } from '../types'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
template: UiTemplateType
|
||||
content: QuestionContent
|
||||
}>()
|
||||
|
||||
const pinyinChars = computed(() => {
|
||||
if (props.template === 'TEMPLATE_WORD_DICTATION' && props.content.pinyin) {
|
||||
return props.content.pinyin.split(' ')
|
||||
}
|
||||
return []
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-[400px] w-full flex items-center justify-center p-10">
|
||||
<!-- 模板A: 汉字听写-提示 (拼音+提示) -->
|
||||
<div v-if="template === 'TEMPLATE_DICTATION_HINT'" class="text-center">
|
||||
<div class="mb-6 inline-block text-[120px] text-red-500 font-bold leading-none" style="text-shadow: 2px 2px 4px rgba(0,0,0,0.1);">
|
||||
“{{ content.pinyin }}”
|
||||
</div>
|
||||
<!-- <div class="text-4xl text-gray-800 font-bold">
|
||||
{{ content.hint }}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 模板B: 汉字听写-同音字 (大字) -->
|
||||
<div v-else-if="template === 'TEMPLATE_DICTATION_HOMOPHONE'" class="text-center">
|
||||
<div class="text-[100px] text-red-600 font-bold">
|
||||
“{{ content.mainText }}”
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板C: 汉字加一加 (提示+部件) -->
|
||||
<div v-else-if="template === 'TEMPLATE_COMPONENT_ADD'" class="text-center">
|
||||
<div class="text-[100px] text-red-600 font-bold">
|
||||
{{ content.component }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板D: 词语听写 (拼音+提示) -->
|
||||
<div v-else-if="template === 'TEMPLATE_WORD_DICTATION'" class="flex flex-col items-center">
|
||||
<div class="mb-8 flex flex-wrap justify-center gap-6">
|
||||
<div
|
||||
v-for="(char, index) in pinyinChars"
|
||||
:key="index"
|
||||
class="relative h-32 w-32 flex select-none items-center justify-center border-2 border-red-500 bg-white"
|
||||
>
|
||||
<!-- 米字格背景 -->
|
||||
<div class="pointer-events-none absolute inset-0 z-0 h-full w-full">
|
||||
<!-- 横虚线 -->
|
||||
<div class="absolute left-0 top-1/2 h-[1px] w-full border-t border-red-400 border-dashed opacity-60" />
|
||||
<!-- 竖虚线 -->
|
||||
<div class="absolute left-1/2 top-0 h-full w-[1px] border-l border-red-400 border-dashed opacity-60" />
|
||||
<!-- 斜虚线 (SVG) -->
|
||||
<svg width="100%" height="100%" class="absolute inset-0 opacity-60">
|
||||
<line x1="0" y1="0" x2="100%" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
|
||||
<line x1="100%" y1="0" x2="0" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 文字 -->
|
||||
<span class="z-10 text-5xl text-gray-800 font-bold font-sans">{{ char }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板E: 成语-文字要求 -->
|
||||
<div v-else-if="template === 'TEMPLATE_IDIOM_TEXT_REQ'" class="text-center">
|
||||
<div class="mb-8 text-4xl text-gray-800 font-bold">
|
||||
{{ content.requirement }}
|
||||
</div>
|
||||
<!-- <div class="rounded bg-gray-100 px-4 py-2 text-xl text-gray-500">
|
||||
示例:{{ content.example }}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 模板F: 成语-看图 (使用Div占位) -->
|
||||
<div v-else-if="template === 'TEMPLATE_IDIOM_IMAGE'" class="flex flex-col items-center text-center">
|
||||
<div class="mb-6 h-60 w-80 flex items-center justify-center">
|
||||
<!-- <span class="text-gray-400">图片展示区域<br></span> -->
|
||||
<img :src="content.image" alt="idiom image" class="h-full w-full object-contain">
|
||||
</div>
|
||||
<!-- <div class="text-xl text-gray-600 font-bold">
|
||||
提示:{{ content.hint }}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 模板G: 诗词理解-选择题 -->
|
||||
<div v-else-if="template === 'TEMPLATE_POETRY_MULTIPLE_CHOICE'" class="w-full flex flex-col items-center">
|
||||
<div class="mb-8 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
{{ content.questionText }}
|
||||
</div>
|
||||
<div class="grid grid-cols-1 w-full gap-6 lg:grid-cols-3 md:grid-cols-2">
|
||||
<div
|
||||
v-for="(option, index) in content.options"
|
||||
:key="index"
|
||||
class="group flex flex-col cursor-pointer items-center border-2 border-transparent rounded-xl bg-gray-50 p-4 transition-all hover:border-red-400 hover:bg-red-50 hover:shadow-lg"
|
||||
>
|
||||
<div v-if="option.image" class="mb-3 h-40 w-full flex items-center justify-center overflow-hidden rounded-lg bg-white p-2">
|
||||
<img :src="option.image" :alt="option.label" class="h-full w-full object-contain transition-transform group-hover:scale-105">
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="h-8 w-8 flex items-center justify-center rounded-full bg-red-100 text-red-600 font-bold group-hover:bg-red-500 group-hover:text-white">
|
||||
{{ option.label }}
|
||||
</div>
|
||||
<span class="text-xl text-gray-700 font-medium group-hover:text-red-700">{{ option.text }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="text-red-500">
|
||||
未知的题目模板: {{ template }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,301 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { QuestionContent, UiTemplateType } from '../types'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
template: UiTemplateType
|
||||
content: QuestionContent
|
||||
}>()
|
||||
|
||||
const pinyinChars = computed(() => {
|
||||
if (props.template === 'TEMPLATE_WORD_DICTATION' && props.content.title) {
|
||||
return props.content.title.split(' ')
|
||||
}
|
||||
return []
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-[400px] w-full flex items-center justify-center p-10">
|
||||
<!-- 模板A: 汉字听写-提示 (拼音+提示) -->
|
||||
<div v-if="template === 'TEMPLATE_DICTATION_HINT'" class="text-center">
|
||||
<div class="mb-6 inline-block text-[120px] text-red-500 font-bold leading-none" style="text-shadow: 2px 2px 4px rgba(0,0,0,0.1);">
|
||||
“{{ content.title }}”
|
||||
</div>
|
||||
<!-- <div class="text-4xl text-gray-800 font-bold">
|
||||
{{ content.meta?.hint }}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 模板B: 汉字听写-同音字 (大字) -->
|
||||
<div v-else-if="template === 'TEMPLATE_DICTATION_HOMOPHONE'" class="text-center">
|
||||
<div class="text-[100px] text-red-600 font-bold">
|
||||
“{{ content.title }}”
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板C: 汉字加一加 (提示+部件) -->
|
||||
<div v-else-if="template === 'TEMPLATE_COMPONENT_ADD'" class="text-center">
|
||||
<div class="text-[100px] text-red-600 font-bold">
|
||||
{{ content.title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板D: 词语听写 (拼音+提示) -->
|
||||
<div v-else-if="template === 'TEMPLATE_WORD_DICTATION'" class="flex flex-col items-center">
|
||||
<div class="mb-8 flex flex-wrap justify-center gap-6">
|
||||
<div
|
||||
v-for="(char, index) in pinyinChars"
|
||||
:key="index"
|
||||
class="relative h-32 w-32 flex select-none items-center justify-center border-2 border-red-500 bg-white"
|
||||
>
|
||||
<!-- 米字格背景 -->
|
||||
<div class="pointer-events-none absolute inset-0 z-0 h-full w-full">
|
||||
<!-- 横虚线 -->
|
||||
<div class="absolute left-0 top-1/2 h-[1px] w-full border-t border-red-400 border-dashed opacity-60" />
|
||||
<!-- 竖虚线 -->
|
||||
<div class="absolute left-1/2 top-0 h-full w-[1px] border-l border-red-400 border-dashed opacity-60" />
|
||||
<!-- 斜虚线 (SVG) -->
|
||||
<svg width="100%" height="100%" class="absolute inset-0 opacity-60">
|
||||
<line x1="0" y1="0" x2="100%" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
|
||||
<line x1="100%" y1="0" x2="0" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 文字 -->
|
||||
<span class="z-10 text-5xl text-gray-800 font-bold font-sans">{{ char }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模板E: 成语-文字要求 -->
|
||||
<div v-else-if="template === 'TEMPLATE_IDIOM_TEXT_REQ'" class="text-center">
|
||||
<div class="mb-8 text-4xl text-gray-800 font-bold">
|
||||
{{ content.title }}
|
||||
</div>
|
||||
<!-- <div class="rounded bg-gray-100 px-4 py-2 text-xl text-gray-500">
|
||||
示例:{{ content.meta?.example }}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 模板F: 成语-看图 (使用Div占位) -->
|
||||
<div v-else-if="template === 'TEMPLATE_IDIOM_IMAGE'" class="flex flex-col items-center text-center">
|
||||
<div class="mb-6 h-60 w-80 flex items-center justify-center">
|
||||
<!-- <span class="text-gray-400">图片展示区域<br></span> -->
|
||||
<img :src="content.titleImage" alt="idiom image" class="h-full w-full object-contain">
|
||||
</div>
|
||||
<!-- <div class="text-xl text-gray-600 font-bold">
|
||||
提示:{{ content.meta?.hint }}
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- 模板G: 诗词理解-选择题 (通用选择题模板) -->
|
||||
<div v-else-if="template === 'TEMPLATE_POETRY_MULTIPLE_CHOICE'" class="w-full flex flex-col items-center">
|
||||
<div class="mb-8 text-3xl text-gray-800 font-bold leading-relaxed">
|
||||
{{ content.title }}
|
||||
</div>
|
||||
<div class="options-container">
|
||||
<div
|
||||
v-for="(option, index) in content.options"
|
||||
:key="index"
|
||||
class="option-card group"
|
||||
:class="{
|
||||
'is-mixed': !option.renderType || option.renderType === 'mixed' || option.renderType === 'image',
|
||||
'is-text': option.renderType === 'text',
|
||||
}"
|
||||
>
|
||||
<!-- 1. 图片渲染模式 -->
|
||||
<div v-if="option.image" class="option-image-wrapper">
|
||||
<img :src="option.image" :alt="option.label" class="option-image">
|
||||
</div>
|
||||
|
||||
<!-- 2. 田字格渲染模式 -->
|
||||
<div v-if="option.renderType === 'tianzige'" class="tianzige-wrapper">
|
||||
<!-- 米字格背景 -->
|
||||
<div class="tianzige-bg">
|
||||
<div class="line-horizontal" />
|
||||
<div class="line-vertical" />
|
||||
<svg width="100%" height="100%" class="line-diagonal">
|
||||
<line x1="0" y1="0" x2="100%" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
|
||||
<line x1="100%" y1="0" x2="0" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="tianzige-text">{{ option.text }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 选项标签和文字 -->
|
||||
<div class="option-content">
|
||||
<div class="option-label">
|
||||
{{ option.label }}
|
||||
</div>
|
||||
<!-- 如果不是田字格模式,显示普通文本 -->
|
||||
<span v-if="option.renderType !== 'tianzige'" class="option-text">
|
||||
{{ option.text }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="text-red-500">
|
||||
未知的题目模板: {{ template }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.options-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 2rem;
|
||||
margin-bottom: 3rem;
|
||||
|
||||
.option-card {
|
||||
width: 320px;
|
||||
height: 260px;
|
||||
}
|
||||
}
|
||||
|
||||
.option-card {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 0.75rem; /* rounded-xl */
|
||||
background-color: #f9fafb; /* bg-gray-50 */
|
||||
padding: 1rem; /* p-4 */
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: #f87171; /* border-red-400 */
|
||||
background-color: #fef2f2; /* bg-red-50 */
|
||||
box-shadow:
|
||||
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
||||
0 4px 6px -2px rgba(0, 0, 0, 0.05); /* shadow-lg */
|
||||
}
|
||||
|
||||
&.is-mixed {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.is-text {
|
||||
flex-direction: row;
|
||||
gap: 1rem; /* gap-4 */
|
||||
}
|
||||
}
|
||||
|
||||
.option-image-wrapper {
|
||||
margin-bottom: 1rem;
|
||||
height: 9rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border-radius: 0.5rem; /* rounded-lg */
|
||||
padding: 0.5rem; /* p-2 */
|
||||
}
|
||||
|
||||
.option-image {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
transition: transform 0.3s;
|
||||
|
||||
.group:hover & {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.tianzige-wrapper {
|
||||
position: relative;
|
||||
margin-bottom: 0.75rem; /* mb-3 */
|
||||
height: 8rem; /* h-32 */
|
||||
width: 8rem; /* w-32 */
|
||||
display: flex;
|
||||
user-select: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2px solid #ef4444; /* border-red-500 */
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.tianzige-bg {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.line-horizontal {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border-top: 1px dashed #f87171; /* border-red-400 */
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.line-vertical {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 1px;
|
||||
border-left: 1px dashed #f87171; /* border-red-400 */
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.line-diagonal {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.tianzige-text {
|
||||
font-family: 'KaiTi', 'STKaiti', serif; /* font-kaaiti */
|
||||
z-index: 10;
|
||||
font-size: 3.75rem; /* text-6xl */
|
||||
font-weight: 700;
|
||||
color: #1f2937; /* text-gray-800 */
|
||||
}
|
||||
|
||||
.option-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem; /* gap-3 */
|
||||
}
|
||||
|
||||
.option-label {
|
||||
height: 2rem; /* h-8 */
|
||||
width: 2rem; /* w-8 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 9999px; /* rounded-full */
|
||||
background-color: #fee2e2; /* bg-red-100 */
|
||||
color: #dc2626; /* text-red-600 */
|
||||
font-weight: 700;
|
||||
|
||||
.group:hover & {
|
||||
background-color: #ef4444; /* bg-red-500 */
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.option-text {
|
||||
font-size: 1.25rem; /* text-xl */
|
||||
color: #374151; /* text-gray-700 */
|
||||
font-weight: 500;
|
||||
|
||||
.group:hover & {
|
||||
color: #b91c1c; /* text-red-700 */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,41 +0,0 @@
|
||||
### 一、 文字版流程说明
|
||||
|
||||
1. 封面 (COVER)
|
||||
- 动作 :点击“开始比赛”按钮。
|
||||
- 跳转 :进入第一轮的【抽题/介绍页面】。
|
||||
|
||||
2. 抽题/介绍页面 (INTRO)
|
||||
- 展示 :当前环节名称(如“汉字听一听”)、规则说明、大圆形的“抽题”按钮。
|
||||
- 动作 :点击“抽题”或“开始答题”按钮。
|
||||
- 跳转 :进入当前题目的【答题页面】,同时开始倒计时。
|
||||
|
||||
3. 答题页面 (GAME)
|
||||
- 展示 :题目内容(如拼音、图片)、倒计时、实时答题进度图表。
|
||||
- 触发条件 A :倒计时归零。
|
||||
- 触发条件 B :点击隐藏的“下一题”区域(手动结束)。
|
||||
- 跳转 :停止计时,进入当前题目的【答题图解页面】。
|
||||
|
||||
4. 答题图解页面 (ANSWER_ANALYSIS)
|
||||
- 展示 :4个战队的答题原笔迹(支持点击放大)、AI评分结果、人工改分输入框。
|
||||
- 动作 :点击右上角“下一题”按钮。
|
||||
- 逻辑判断 :
|
||||
- 情况 A(本轮还有题) :索引指向下一题 -> 回到【抽题/介绍页面】 (准备抽取下一题)。
|
||||
- 情况 B(本轮已结束,还有下一轮) :索引指向下一轮第一题 -> 回到【抽题/介绍页面】 (展示新环节介绍)。
|
||||
- 情况 C(全场结束) :提示“全场比赛结束” -> 回到【封面】 。
|
||||
|
||||
阅读之星
|
||||
feat(user): 新增用户端答题流程页面与相关功能
|
||||
|
||||
- 新增用户端答题流程主页面,包含封面、介绍、答题、答题图解四个状态
|
||||
|
||||
- 新增用户端组件:封面、介绍页、答题页、答题图解页、题目渲染器
|
||||
|
||||
- 新增用户端类型定义、模拟数据及业务常量
|
||||
|
||||
- 新增用户路由及类型声明
|
||||
|
||||
- 优化题库分类树,改为扁平化列表结构
|
||||
|
||||
- 完善比赛创建功能,增加轮次类型、题目分数类型及关联AP字段
|
||||
|
||||
- 修复模板删除函数调用参数错误
|
||||
@ -1,64 +0,0 @@
|
||||
export type UiTemplateType =
|
||||
| 'TEMPLATE_DICTATION_HINT' // 汉字听写-提示 (jiu)
|
||||
| 'TEMPLATE_DICTATION_HOMOPHONE' // 汉字听写-同音 (tang)
|
||||
| 'TEMPLATE_COMPONENT_ADD' // 汉字加一加 (车)
|
||||
| 'TEMPLATE_WORD_DICTATION' // 词语听写 (zhi re)
|
||||
| 'TEMPLATE_IDIOM_TEXT_REQ' // 成语-文字要求 (反义字)
|
||||
| 'TEMPLATE_IDIOM_IMAGE' // 成语-看图
|
||||
| 'TEMPLATE_POETRY_MULTIPLE_CHOICE' // 诗词理解-选择题
|
||||
|
||||
export interface QuestionOption {
|
||||
label: string // A, B, C
|
||||
text: string // 选项文本/值
|
||||
image?: string // 选项图片
|
||||
renderType?: 'text' | 'image' | 'tianzige' | 'mixed' // 关键字段:控制选项渲染样式
|
||||
}
|
||||
|
||||
export interface QuestionContent {
|
||||
// 核心标准字段 (对应数据库列)
|
||||
title: string // 题干/主要内容 (原 word, questionText, mainText, pinyin, requirement, component)
|
||||
titleImage?: string // 题干图片 (原 image)
|
||||
titleAudio?: string // 题干音频 (原 soundUrl)
|
||||
options?: QuestionOption[] // 选项列表
|
||||
|
||||
// 扩展元数据 (对应数据库 JSON 字段)
|
||||
meta?: {
|
||||
hint?: string // 提示
|
||||
example?: string // 示例
|
||||
pinyin?: string // 如果 title 是汉字,这里存拼音;反之亦然
|
||||
definition?: string // 释义
|
||||
strokeCount?: number // 笔画数
|
||||
radicals?: string // 部首
|
||||
[key: string]: any
|
||||
}
|
||||
}
|
||||
|
||||
export interface Question {
|
||||
id: string
|
||||
content: QuestionContent
|
||||
answer: string[]
|
||||
}
|
||||
|
||||
export interface NodeConfig {
|
||||
timeLimit: number
|
||||
questionCount: number
|
||||
scorePerQuestion: number
|
||||
}
|
||||
|
||||
export interface ActivityNode {
|
||||
nodeId: string
|
||||
roundTitle: string
|
||||
moduleName: string
|
||||
batchName: string
|
||||
description: string
|
||||
uiTemplate: UiTemplateType
|
||||
config: NodeConfig
|
||||
questions: Question[]
|
||||
}
|
||||
|
||||
export interface CompetitionData {
|
||||
activityInfo: {
|
||||
name: string
|
||||
}
|
||||
nodes: ActivityNode[]
|
||||
}
|
||||
@ -101,8 +101,6 @@ function toggleFlip(index: number) {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/styles/scss/variables.scss';
|
||||
|
||||
.perspective-container {
|
||||
perspective: 1000px; // [3D透视] 设置观察者距离,数值越小透视感越强,产生近大远小的3D效果
|
||||
}
|
||||
|
||||
@ -82,8 +82,6 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/scss/variables.scss';
|
||||
|
||||
.groups-container {
|
||||
width: 100%;
|
||||
padding: 0 60px;
|
||||
|
||||
@ -81,7 +81,7 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/scss/variables.scss';
|
||||
@use 'sass:color';
|
||||
|
||||
.cards-container {
|
||||
width: 100%;
|
||||
@ -146,7 +146,7 @@ onMounted(() => {
|
||||
|
||||
.event-subtitle {
|
||||
font-size: 1.1rem;
|
||||
color: lighten($text-color, 15%);
|
||||
color: color.adjust($text-color, $lightness: 15%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"src/**/*.d.ts",
|
||||
"vite.config.ts"
|
||||
"vite.config.ts",
|
||||
"build/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules", "dist", "src/typings/components.d.ts"]
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ export default defineConfig((configEnv) => {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
api: 'modern-compiler',
|
||||
additionalData: `@use "@/styles/scss/global.scss" as *;`,
|
||||
additionalData: `@use "@/styles/scss/variables.scss" as *; @use "@/styles/scss/global.scss" as *;`,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user