feat(admin): 添加比赛管理页面功能优化

refactor(utils): 为工具函数添加注释并导出新模块
feat(utils): 新增防抖和节流工具函数
docs(utils): 为现有工具类添加中文注释

style(admin): 优化比赛配置页面UI样式
feat(admin): 实现比赛基础信息表单双向绑定
feat(admin): 新增页面头部公共组件
feat(admin): 完善分组管理自动生成逻辑
feat(admin): 增强题目配置功能与交互

fix(admin): 修复表单数据更新死循环问题
This commit is contained in:
2026-01-20 10:58:42 +08:00
parent 1e8e2d1495
commit 2639aef69b
13 changed files with 443 additions and 128 deletions

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { NButton, NCard, NTag, useMessage } from 'naive-ui'
import { NButton, NTag, useMessage } from 'naive-ui'
import { ref } from 'vue'
import { useRoute } from 'vue-router'
import BasicInfoCard from './modules/BasicInfoCard.vue'
@ -31,27 +31,29 @@ function handleSave() {
<!-- 右侧主要内容区 -->
<div class="h-full flex flex-col flex-1 overflow-hidden">
<!-- 新增顶部全局操作栏 -->
<NCard :bordered="false" class="mb-4 flex-shrink-0 rounded-xl shadow-sm">
<div class="flex items-center justify-between">
<div class="text-sm text-gray-500">
当前状态
<NTag :type="isEdit ? 'warning' : 'success'" size="small" :bordered="false">
{{ isEdit ? '编辑中' : '预览中' }}
</NTag>
</div>
<PageHeader class="mb-4 flex-shrink-0">
<div class="text-sm text-gray-500">
当前状态
<NTag :type="isEdit ? 'warning' : 'success'" size="small" :bordered="false">
{{ isEdit ? '编辑中' : '预览中' }}
</NTag>
</div>
<template #action>
<div class="flex gap-3">
<NButton type="error" secondary>
<template #icon>
<div class="i-carbon-trash-can" />
<icon-ic-baseline-delete class="text-icon" />
</template>
删除
删除赛事
</NButton>
<div class="w-1px bg-gray-200" />
<NButton v-if="!isEdit" type="primary" secondary @click="isEdit = true">
<template #icon>
<div class="i-carbon-edit" />
<icon-ic-baseline-edit class="text-icon" />
</template>
编辑
进入编辑模式
</NButton>
<template v-else>
@ -60,21 +62,21 @@ function handleSave() {
</NButton>
<NButton type="primary" @click="handleSave">
<template #icon>
<div class="i-carbon-save" />
<icon-ic-baseline-save class="text-icon" />
</template>
保存提交
保存更改
</NButton>
</template>
<NButton v-if="!isEdit" type="primary" color="#1a202c">
<NButton v-if="!isEdit" type="success">
<template #icon>
<div class="i-carbon-rocket" />
<icon-ic-baseline-rocket-launch class="text-icon" />
</template>
发布
立即发布
</NButton>
</div>
</div>
</NCard>
</template>
</PageHeader>
<!-- 滚动内容区 -->
<div class="no-scrollbar flex flex-col flex-1 gap-4 overflow-y-auto">

View File

@ -36,26 +36,26 @@ const scoreOptions = [
<div
class="flex items-center justify-between border-b rounded-t-lg px-4 py-3"
:class="type === 'regular'
? 'bg-gray-50 border-gray-100'
? 'bg-blue-50/50 border-blue-100'
: 'bg-orange-50/50 border-orange-100'"
>
<div class="flex items-center gap-2 text-gray-700 font-bold">
<div :class="type === 'regular' ? 'i-carbon-document-tasks text-blue-500' : 'i-carbon-timer text-orange-500'" />
<div class="flex items-center gap-2 font-bold" :class="type === 'regular' ? 'text-gray-800' : 'text-[#5E3218]'">
<div :class="type === 'regular' ? 'i-carbon-document-tasks text-blue-500' : 'i-carbon-timer text-[#D96B23]'" />
{{ type === 'regular' ? '常规赛题包' : '加时赛题包' }}
</div>
<div class="text-xs" :class="type === 'regular' ? 'text-gray-400' : 'text-orange-400'">
配置详情
<div class="text-xs font-medium" :class="type === 'regular' ? 'text-[#8DA5C3]' : 'text-[#D96B23]/60'">
{{ type === 'regular' ? 10 : 5 }} / 总计 {{ type === 'regular' ? 10 : 7 }}
</div>
</div>
<!-- 列表区域 -->
<div
class="flex flex-col gap-3 border border-t-0 rounded-b-lg p-4"
:class="type === 'regular' ? 'border-gray-100' : 'border-orange-100 bg-orange-50/10'"
:class="type === 'regular' ? 'border-blue-100 bg-[#F5F9FF]' : 'border-orange-100 bg-[#FFF9F5]'"
>
<div v-for="i in (type === 'regular' ? 10 : 5)" :key="`${type}-${i}`" class="flex items-center gap-2">
<!-- 题号 -->
<div class="w-16 flex-shrink-0 text-xs font-bold" :class="type === 'regular' ? 'text-gray-400' : 'text-orange-400'">
<div class="w-16 flex-shrink-0 text-xs font-bold" :class="type === 'regular' ? 'text-[#8DA5C3]' : 'text-[#FF8C38]'">
{{ type === 'regular' ? `${i}` : `PK${i}` }}:
</div>