feat(competition): 新增比赛管理功能并优化UI交互
- 添加比赛创建向导,支持分步配置基础信息、分组管理、硬件绑定和题目配置 - 实现比赛卡片组件,支持复制和删除操作 - 优化比赛详情页的表单交互和样式 - 新增全局组件类型定义和图标 - 添加比赛海报上传功能 - 完善比赛状态管理,新增"已结束"状态
This commit is contained in:
@ -1,6 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { NGrid, NGridItem, NSelect } from 'naive-ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: {
|
||||
questions: {
|
||||
regular: Array<{ value: string, score: number, time: number }>
|
||||
pk: Array<{ value: string, score: number, time: number }>
|
||||
}
|
||||
}
|
||||
}>()
|
||||
|
||||
const questionOptions = [
|
||||
{ label: '汉字听写 - 根据提示书写汉字', value: 'hanzi' },
|
||||
@ -36,50 +45,54 @@ const timeOptions = [
|
||||
{ label: '90s', value: 90 },
|
||||
]
|
||||
|
||||
const regularQuestions = ref([
|
||||
{ value: 'hanzi', score: 1, time: 15 },
|
||||
{ value: 'tongyin', score: 1, time: 15 },
|
||||
{ value: 'pianpang', score: 1, time: 30 },
|
||||
{ value: 'ciyu', score: 1, time: 30 },
|
||||
{ value: 'chengyu', score: 1, time: 30 },
|
||||
{ value: 'fanyi', score: 1, time: 60 },
|
||||
{ value: 'jinyi', score: 1, time: 30 },
|
||||
{ value: 'kantu', score: 1, time: 30 },
|
||||
{ value: 'gushi', score: 1, time: 60 },
|
||||
{ value: 'mingju', score: 1, time: 60 },
|
||||
])
|
||||
const regularTotalScore = computed(() => {
|
||||
return props.modelValue?.questions?.regular?.reduce((acc, cur) => acc + cur.score, 0) || 0
|
||||
})
|
||||
|
||||
const pkQuestions = ref([
|
||||
{ value: 'speed10', score: 1, time: 60 },
|
||||
{ value: 'speed10', score: 1, time: 60 },
|
||||
{ value: 'speed10', score: 1, time: 60 },
|
||||
{ value: 'speed10', score: 1, time: 60 },
|
||||
{ value: 'speed10', score: 3, time: 60 },
|
||||
])
|
||||
const pkTotalScore = computed(() => {
|
||||
return props.modelValue?.questions?.pk?.reduce((acc, cur) => acc + cur.score, 0) || 0
|
||||
})
|
||||
|
||||
const regularTotalScore = computed(() => regularQuestions.value.reduce((acc, cur) => acc + cur.score, 0))
|
||||
const pkTotalScore = computed(() => pkQuestions.value.reduce((acc, cur) => acc + cur.score, 0))
|
||||
function validate() {
|
||||
// 简单校验:主赛环节是否有题目
|
||||
if (!props.modelValue?.questions?.regular?.length) {
|
||||
window.$message?.error('请至少配置一道主赛题目')
|
||||
return false
|
||||
}
|
||||
// 检查是否所有题目都选了题型
|
||||
const invalidRegular = props.modelValue.questions.regular.some(q => !q.value)
|
||||
if (invalidRegular) {
|
||||
window.$message?.error('请完善主赛环节的题型配置')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
defineExpose({ validate })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="py-4">
|
||||
<div class="mb-8 text-xl text-gray-800 font-bold">
|
||||
比赛赛题包配置
|
||||
</div>
|
||||
<NGrid :x-gap="48" :y-gap="24" cols="1 l:2" responsive="screen">
|
||||
<!-- 左侧:常规赛题包 -->
|
||||
<!-- 左侧:主赛环节 -->
|
||||
<NGridItem>
|
||||
<div class="h-full rounded-2xl bg-[#F5F9FF] p-6">
|
||||
<div class="mb-6 flex items-center justify-between border-b border-blue-100 pb-4">
|
||||
<div class="flex items-center gap-2 text-gray-800 font-bold">
|
||||
<icon-ic-outline-archive class="text-xl text-blue-500" />
|
||||
<span class="text-lg">常规赛题包</span>
|
||||
<span class="text-lg">主赛环节</span>
|
||||
</div>
|
||||
<div class="text-sm text-[#8DA5C3] font-medium">
|
||||
共 {{ regularQuestions.length }} 题 / 总计 {{ regularTotalScore }} 分
|
||||
共 {{ props.modelValue?.questions?.regular?.length || 0 }} 题 / 总计 {{ regularTotalScore }} 分
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-5">
|
||||
<div
|
||||
v-for="(item, idx) in regularQuestions"
|
||||
v-for="(item, idx) in props.modelValue?.questions?.regular"
|
||||
:key="idx"
|
||||
class="flex items-center gap-3"
|
||||
>
|
||||
@ -141,22 +154,22 @@ const pkTotalScore = computed(() => pkQuestions.value.reduce((acc, cur) => acc +
|
||||
</div>
|
||||
</NGridItem>
|
||||
|
||||
<!-- 右侧:加时赛 (PK环节) -->
|
||||
<!-- 右侧:加时PK环节 -->
|
||||
<NGridItem>
|
||||
<div class="h-full border border-[#FFF0E0] rounded-2xl bg-[#FFF9F5] p-6">
|
||||
<div class="mb-6 flex items-center justify-between border-b border-orange-100 pb-4">
|
||||
<div class="flex items-center gap-2 text-[#5E3218] font-bold">
|
||||
<icon-ic-outline-timer class="text-xl text-[#D96B23]" />
|
||||
<span class="text-lg">加时赛题包</span>
|
||||
<span class="text-lg">加时PK环节</span>
|
||||
</div>
|
||||
<div class="text-sm text-[#D96B23]/60 font-medium">
|
||||
共 {{ pkQuestions.length }} 题 / 总计 {{ pkTotalScore }} 分
|
||||
共 {{ props.modelValue?.questions?.pk?.length || 0 }} 题 / 总计 {{ pkTotalScore }} 分
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-5">
|
||||
<div
|
||||
v-for="(item, idx) in pkQuestions"
|
||||
v-for="(item, idx) in props.modelValue?.questions?.pk"
|
||||
:key="idx"
|
||||
class="flex items-center gap-3"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user