feat(competition): 新增比赛活动管理功能模块

实现比赛活动的创建、编辑、详情查看功能,包括基础信息配置、分组管理、题库配置和硬件绑定
添加比赛列表页面的路由跳转逻辑,优化卡片点击交互
完善比赛详情页的编辑状态管理,支持基础信息和题包配置的修改
新增本地SVG图标资源,更新系统Logo组件样式
This commit is contained in:
2026-01-19 18:03:45 +08:00
parent 77315b36ed
commit d13077a3f1
24 changed files with 971 additions and 200 deletions

View File

@ -1,17 +1,19 @@
<script setup lang="ts">
import { NButton, NGi, NGrid, NSpace } from 'naive-ui'
import { computed } from 'vue'
import { useRouterPush } from '@/hooks/common/router'
import { useAppStore } from '@/store/modules/app'
import CompetitionCard from './modules/competition-card.vue'
import { competitionList } from './modules/data'
const { routerPushByKey } = useRouterPush()
// 引入 store 用于判断移动端布局 (与你提供的风格保持一致)
const appStore = useAppStore()
const gap = computed(() => (appStore.isMobile ? 12 : 16))
// 模拟新增操作
function handleAdd() {
window.$message?.success('点击了新增比赛活动')
routerPushByKey('competition_competition-add')
}
</script>
@ -39,11 +41,7 @@ function handleAdd() {
<!-- 卡片列表区域 -->
<!-- 响应式布局手机1列平板2列中屏3列大屏4列 -->
<NGrid :x-gap="gap" :y-gap="gap" responsive="screen" item-responsive>
<NGi
v-for="item in competitionList"
:key="item.id"
span="24 s:12 m:8 l:6"
>
<NGi v-for="item in competitionList" :key="item.id" span="24 s:12 m:8 l:6">
<CompetitionCard :item="item" />
</NGi>
</NGrid>

View File

@ -2,13 +2,16 @@
import type { CompetitionItem } from './data'
import { NButton, NCard, NTag } from 'naive-ui'
import { computed } from 'vue'
import { useRouterPush } from '@/hooks/common/router'
const props = defineProps<Props>()
const { routerPushByKey } = useRouterPush()
interface Props {
item: CompetitionItem
}
const props = defineProps<Props>()
// 状态配置:颜色和文本
const statusConfig = computed(() => {
if (props.item.status === 'ongoing') {
@ -19,13 +22,17 @@ const statusConfig = computed(() => {
// 处理标题换行
const formattedTitle = computed(() => props.item.title.replace(/\n/g, '<br/>'))
function toDetail(item: CompetitionItem) {
routerPushByKey('competition_competition-detail', { query: { id: item.id } })
}
</script>
<template>
<NCard
:bordered="false"
class="group relative h-full overflow-hidden rounded-2xl transition-all duration-300 hover:shadow-lg"
content-style="padding: 24px; display: flex; flex-direction: column; height: 100%;"
content-style="padding: 24px; display: flex; flex-direction: column; height: 100%;" @click="toDetail(item)"
>
<!-- 特殊背景装饰 (仅高亮卡片显示) -->
<div
@ -38,12 +45,7 @@ const formattedTitle = computed(() => props.item.title.replace(/\n/g, '<br/>'))
<div>
<!-- 状态标签 -->
<div class="mb-4">
<NTag
:bordered="false"
size="small"
round
class="px-3 font-medium" :class="[statusConfig.bgClass]"
>
<NTag :bordered="false" size="small" round class="px-3 font-medium" :class="[statusConfig.bgClass]">
{{ statusConfig.text }}
</NTag>
</div>
@ -66,12 +68,7 @@ const formattedTitle = computed(() => props.item.title.replace(/\n/g, '<br/>'))
<span class="text-xs text-gray-500 font-medium">
{{ item.teamCount }} 支参赛队伍
</span>
<NButton
text
type="primary"
size="small"
class="font-bold hover:underline"
>
<NButton text type="primary" size="small" class="font-bold hover:underline">
查看配置详情
</NButton>
</div>