feat(admin): 新增题库模块并优化比赛管理功能
新增题库模块,包含题目管理页面和Excel导入导出功能 优化比赛管理功能,包括分组管理、硬件绑定和题目配置 重构比赛添加流程,增加重置功能和数据校验 添加Excel工具函数,支持读取和导出Excel文件 更新依赖,添加xlsx库支持
This commit is contained in:
@ -6,10 +6,11 @@ import CompetitionAddModal from '../competition-add/index.vue'
|
||||
import CompetitionCard from './modules/competition-card.vue'
|
||||
import { type CompetitionItem, competitionList } from './modules/data'
|
||||
|
||||
// 引入 store 用于判断移动端布局 (与你提供的风格保持一致)
|
||||
const appStore = useAppStore()
|
||||
const gap = computed(() => (appStore.isMobile ? 12 : 26))
|
||||
|
||||
const competitionListRef = ref(competitionList)
|
||||
|
||||
const showAddModal = ref(false)
|
||||
|
||||
function handleAdd() {
|
||||
@ -22,8 +23,43 @@ function handleCopy(item: CompetitionItem) {
|
||||
}
|
||||
|
||||
function handleDelete(item: CompetitionItem) {
|
||||
// TODO: 实现删除逻辑
|
||||
window.$message?.success(`已删除活动:${item.title}`)
|
||||
const d = window.$dialog?.warning({
|
||||
title: '确认删除',
|
||||
content: `确定删除活动:${item.title}吗?`,
|
||||
positiveText: '确认',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
if (d) {
|
||||
d.loading = true
|
||||
}
|
||||
// 模拟接口请求延迟 2秒
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
try {
|
||||
// 模拟 50% 概率失败
|
||||
if (Math.random() < 0.5) {
|
||||
throw new Error('模拟服务器异常,删除失败')
|
||||
}
|
||||
|
||||
// 成功逻辑
|
||||
const index = competitionListRef.value.findIndex(i => i.id === item.id)
|
||||
if (index > -1) {
|
||||
competitionListRef.value.splice(index, 1)
|
||||
window.$message?.success(`已删除活动:${item.title}`)
|
||||
}
|
||||
return true // 返回 true 关闭弹窗
|
||||
}
|
||||
catch (error: any) {
|
||||
window.$message?.error(error.message)
|
||||
return false // 返回 false 阻止关闭弹窗
|
||||
}
|
||||
finally {
|
||||
if (d) {
|
||||
d.loading = false
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -40,9 +76,9 @@ function handleDelete(item: CompetitionItem) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<NButton type="primary" size="medium" class="px-6 font-medium" @click="handleAdd">
|
||||
<NButton type="primary" size="large" class="px-6 font-medium" @click="handleAdd">
|
||||
<template #icon>
|
||||
<div class="i-carbon-add text-lg" />
|
||||
<icon-ic-outline-add-to-photos class="text-icon" />
|
||||
</template>
|
||||
新增比赛活动
|
||||
</NButton>
|
||||
@ -51,7 +87,7 @@ function handleDelete(item: CompetitionItem) {
|
||||
<!-- 卡片列表区域 -->
|
||||
<!-- 响应式布局:手机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 competitionListRef" :key="item.id" span="24 s:12 m:8 l:6">
|
||||
<CompetitionCard :item="item" @copy="handleCopy" @delete="handleDelete" />
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
@ -80,10 +80,7 @@ const decorationBgClass = computed(() => {
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton
|
||||
circle
|
||||
secondary
|
||||
size="small"
|
||||
class="shadow-sm backdrop-blur-sm !bg-white/80 hover:!bg-white"
|
||||
circle secondary size="small" class="shadow-sm backdrop-blur-sm !bg-white/80 hover:!bg-white"
|
||||
@click.stop="emit('copy', item)"
|
||||
>
|
||||
<template #icon>
|
||||
@ -97,12 +94,8 @@ const decorationBgClass = computed(() => {
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton
|
||||
circle
|
||||
secondary
|
||||
size="small"
|
||||
type="error"
|
||||
class="shadow-sm backdrop-blur-sm !bg-white/80 hover:!bg-red-50"
|
||||
@click.stop="emit('delete', item)"
|
||||
circle secondary size="small" type="error"
|
||||
class="shadow-sm backdrop-blur-sm !bg-white/80 hover:!bg-red-50" @click.stop="emit('delete', item)"
|
||||
>
|
||||
<template #icon>
|
||||
<icon-ic-baseline-delete class="text-icon" />
|
||||
@ -132,7 +125,7 @@ const decorationBgClass = computed(() => {
|
||||
<!-- 日期 -->
|
||||
<div class="mb-6 flex items-center text-gray-400">
|
||||
<icon-ic-baseline-calendar-month class="mr-2 text-xl" />
|
||||
<span class="text-base font-bold">{{ item.date }}</span>
|
||||
<span class="text-base font-bold">{{ item.date }} ~ {{ item.endDate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ export interface CompetitionItem {
|
||||
id: string
|
||||
title: string
|
||||
date: string
|
||||
endDate: string
|
||||
teamCount: number
|
||||
status: 'ongoing' | 'pending' | 'ended' // ongoing: 进行中, pending: 未开始, ended: 已结束
|
||||
isHighlight?: boolean // 用于标记第一个卡片的特殊背景
|
||||
@ -14,6 +15,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '1',
|
||||
title: '阅读之星大赛\n辞海遨游环节', // 使用换行符或在组件中处理换行
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 40,
|
||||
status: 'ongoing',
|
||||
isHighlight: true,
|
||||
@ -22,6 +24,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '2',
|
||||
title: '诗词大会总决赛',
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
@ -29,6 +32,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '3',
|
||||
title: '趣味百科大作战',
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'ended',
|
||||
},
|
||||
@ -36,6 +40,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '4',
|
||||
title: '经典文学研读周',
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
@ -43,6 +48,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '5',
|
||||
title: '未来科学家阅读赛',
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
@ -50,6 +56,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '6',
|
||||
title: '历史人文知识赛',
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
@ -57,6 +64,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '7',
|
||||
title: '少儿绘本创意营',
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
@ -64,6 +72,7 @@ export const competitionList: CompetitionItem[] = [
|
||||
id: '8',
|
||||
title: '唐诗三百首挑战',
|
||||
date: '2026.01.12',
|
||||
endDate: '2026.01.12',
|
||||
teamCount: 32,
|
||||
status: 'pending',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user