feat(admin): 新增题库模块并优化比赛管理功能
新增题库模块,包含题目管理页面和Excel导入导出功能 优化比赛管理功能,包括分组管理、硬件绑定和题目配置 重构比赛添加流程,增加重置功能和数据校验 添加Excel工具函数,支持读取和导出Excel文件 更新依赖,添加xlsx库支持
This commit is contained in:
@ -0,0 +1,170 @@
|
||||
import { computed } from 'vue'
|
||||
|
||||
export interface QuestionItem {
|
||||
value: string | null
|
||||
score: number
|
||||
time: number
|
||||
}
|
||||
|
||||
export interface RoundModel {
|
||||
id: string
|
||||
name: string
|
||||
questions: QuestionItem[]
|
||||
}
|
||||
|
||||
export interface QuestionConfigModel {
|
||||
rounds: RoundModel[]
|
||||
}
|
||||
|
||||
export function useQuestionConfig(props: any) {
|
||||
// 计算每个轮次的分数
|
||||
const getRoundScore = (roundIndex: number) => {
|
||||
const round = props.modelValue?.rounds?.[roundIndex]
|
||||
if (!round)
|
||||
return 0
|
||||
return round.questions.reduce((sum: number, item: any) => sum + (Number(item.score) || 0), 0)
|
||||
}
|
||||
|
||||
// 计算每个轮次的时长
|
||||
const getRoundTime = (roundIndex: number) => {
|
||||
const round = props.modelValue?.rounds?.[roundIndex]
|
||||
if (!round)
|
||||
return 0
|
||||
return round.questions.reduce((sum: number, item: any) => sum + (Number(item.time) || 0), 0)
|
||||
}
|
||||
|
||||
// 总计统计
|
||||
const totalStats = computed(() => {
|
||||
const rounds = props.modelValue?.rounds || []
|
||||
return rounds.reduce((acc: any, round: any) => {
|
||||
acc.count += round.questions.length
|
||||
acc.score += round.questions.reduce((sum: number, item: any) => sum + (Number(item.score) || 0), 0)
|
||||
acc.time += round.questions.reduce((sum: number, item: any) => sum + (Number(item.time) || 0), 0)
|
||||
return acc
|
||||
}, { count: 0, score: 0, time: 0 })
|
||||
})
|
||||
|
||||
const questionOptions = [
|
||||
{ label: '汉字听写 - 根据提示书写汉字', value: 'hanzi' },
|
||||
{ label: '同音字辨析 - 根据拼音书写', value: 'tongyin' },
|
||||
{ label: '偏旁部首 - 按要求写字', value: 'pianpang' },
|
||||
{ label: '词语听写 - 综合练习', value: 'ciyu' },
|
||||
{ label: '成语填空 - 四字成语', value: 'chengyu' },
|
||||
{ label: '反义词挑战', value: 'fanyi' },
|
||||
{ label: '近义词挑战', value: 'jinyi' },
|
||||
{ label: '看图猜字', value: 'kantu' },
|
||||
{ label: '古诗词接龙', value: 'gushi' },
|
||||
{ label: '名句听写', value: 'mingju' },
|
||||
{ label: '极速成语接龙 - 每题10秒', value: 'speed10' },
|
||||
{ label: '极速成语接龙 - 每题20秒', value: 'speed20' },
|
||||
]
|
||||
|
||||
const scoreOptions = [
|
||||
{ label: '1分', value: 1 },
|
||||
{ label: '2分', value: 2 },
|
||||
{ label: '3分', value: 3 },
|
||||
{ label: '5分', value: 5 },
|
||||
{ label: '10分', value: 10 },
|
||||
]
|
||||
|
||||
const timeOptions = [
|
||||
{ label: '15s', value: 15 },
|
||||
{ label: '30s', value: 30 },
|
||||
{ label: '45s', value: 45 },
|
||||
{ label: '60s', value: 60 },
|
||||
{ label: '90s', value: 90 },
|
||||
]
|
||||
|
||||
// 新增轮次
|
||||
function addRound(customName?: string, customCount?: number) {
|
||||
if (!props.modelValue.rounds) {
|
||||
props.modelValue.rounds = []
|
||||
}
|
||||
const index = props.modelValue.rounds.length + 1
|
||||
const count = typeof customCount === 'number' ? customCount : 10
|
||||
const name = typeof customName === 'string' ? customName : `第${index}轮:比赛环节`
|
||||
|
||||
props.modelValue.rounds.push({
|
||||
id: `round_${Date.now()}`,
|
||||
name,
|
||||
questions: Array.from({ length: count }).map(() => ({
|
||||
value: null,
|
||||
score: 5,
|
||||
time: 30,
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
// 删除轮次
|
||||
function removeRound(index: number) {
|
||||
props.modelValue.rounds.splice(index, 1)
|
||||
// 重命名剩余轮次
|
||||
props.modelValue.rounds.forEach((round: RoundModel, idx: number) => {
|
||||
round.name = round.name.replace(/第\d+轮/, `第${idx + 1}轮`)
|
||||
})
|
||||
}
|
||||
|
||||
// 新增题目
|
||||
function addQuestion(roundIndex: number) {
|
||||
const round = props.modelValue.rounds[roundIndex]
|
||||
if (round) {
|
||||
round.questions.push({
|
||||
value: null,
|
||||
score: 5,
|
||||
time: 30,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 删除题目
|
||||
function removeQuestion(roundIndex: number, questionIndex: number) {
|
||||
const round = props.modelValue.rounds[roundIndex]
|
||||
if (round) {
|
||||
round.questions.splice(questionIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function validate() {
|
||||
const rounds = props.modelValue?.rounds || []
|
||||
if (rounds.length === 0) {
|
||||
window.$message?.error('请至少配置一个比赛环节')
|
||||
return false
|
||||
}
|
||||
|
||||
for (let i = 0; i < rounds.length; i++) {
|
||||
const round = rounds[i]
|
||||
if (round.questions.length === 0) {
|
||||
window.$message?.error(`${round.name} 至少需要配置一道题目`)
|
||||
return false
|
||||
}
|
||||
for (let j = 0; j < round.questions.length; j++) {
|
||||
if (!round.questions[j].value) {
|
||||
window.$message?.error(`${round.name} 第 ${j + 1} 题未选择题型`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function reset() {
|
||||
// 默认重置为1个轮次,10个题目
|
||||
props.modelValue.rounds = []
|
||||
addRound()
|
||||
}
|
||||
|
||||
return {
|
||||
getRoundScore,
|
||||
getRoundTime,
|
||||
totalStats,
|
||||
questionOptions,
|
||||
scoreOptions,
|
||||
timeOptions,
|
||||
addRound,
|
||||
removeRound,
|
||||
addQuestion,
|
||||
removeQuestion,
|
||||
validate,
|
||||
reset,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user