feat: 新增题目导入服务并优化用户端答题流程
- 新增 question-importer 服务,支持从 JSON 文件批量导入题目到题库 - 重构用户端答题流程,整合抽题、答题、结果分析页面状态管理 - 将题目分类从 UI 模板类型切换为业务分类(question_category_name) - 在题库管理页面支持题目批量选择和删除功能 - 优化用户端组别选择,增加“已结束”状态提示和禁用逻辑 - 修复题目新增/更新 API 请求参数格式问题 - 为富文本编辑器配置排除不必要的工具栏按键
This commit is contained in:
@ -3,20 +3,15 @@ import { onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import CompetitionLayout from '@/components/custom/user/CompetitionLayout.vue'
|
||||
import { useRouterPush } from '@/hooks/common/router'
|
||||
import { fetchGetGroupList } from '@/service/api/competition'
|
||||
import { fetchGetGroupListByActivityID } from '@/service/api/game'
|
||||
|
||||
const { routerPushByKey, routerBack } = useRouterPush()
|
||||
const route = useRoute()
|
||||
|
||||
interface GroupItem {
|
||||
id: number
|
||||
name: string
|
||||
icon: string
|
||||
}
|
||||
|
||||
const groups = ref<GroupItem[]>([])
|
||||
const groups = ref<Api.Competition.ActivityTeamGroup[]>([])
|
||||
const loading = ref(false)
|
||||
const activityId = route.query.activityId as string
|
||||
const isAllEnd = ref(false)
|
||||
|
||||
async function getGroups() {
|
||||
if (!activityId)
|
||||
@ -24,7 +19,7 @@ async function getGroups() {
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const { data, error } = await fetchGetGroupList(activityId)
|
||||
const { data, error } = await fetchGetGroupListByActivityID(activityId, 0)
|
||||
if (error) {
|
||||
window?.$message?.error(error.message)
|
||||
return
|
||||
@ -33,11 +28,14 @@ async function getGroups() {
|
||||
const list = data?.data || []
|
||||
if (list && Array.isArray(list)) {
|
||||
groups.value = list.map((item: any) => ({
|
||||
id: item.Id,
|
||||
name: item.Name,
|
||||
...item,
|
||||
// id: item.Id,
|
||||
// name: item.Name,
|
||||
icon: 'activity', // Default icon since API might not provide one
|
||||
}))
|
||||
}
|
||||
isAllEnd.value = list.every((item: Api.Competition.ActivityTeamGroup) => item.IsEnd)
|
||||
// console.log(groups.value, 'groups.value')
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
@ -51,12 +49,15 @@ function handleBack() {
|
||||
}
|
||||
|
||||
function handleNext() {
|
||||
routerPushByKey('user_teams')
|
||||
routerPushByKey('user')
|
||||
}
|
||||
|
||||
function selectGroup(_id: number) {
|
||||
function selectGroup(item: Api.Competition.ActivityTeamGroup) {
|
||||
if (item.IsEnd)
|
||||
return
|
||||
|
||||
// 选择组别逻辑
|
||||
routerPushByKey('user_teams', { query: { activityId, groupsId: _id } })
|
||||
routerPushByKey('user_teams', { query: { activityId, groupsId: item.Id } })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@ -70,7 +71,8 @@ onMounted(() => {
|
||||
<template>
|
||||
<CompetitionLayout
|
||||
:show-back="true"
|
||||
:show-next="false"
|
||||
:show-next="isAllEnd"
|
||||
next-btn-text="查看队伍结果"
|
||||
title="展示组别"
|
||||
@back="handleBack"
|
||||
@next="handleNext"
|
||||
@ -81,10 +83,11 @@ onMounted(() => {
|
||||
<div
|
||||
v-for="(item, index) in groups"
|
||||
v-show="showContent"
|
||||
:key="item.id"
|
||||
:key="item.Id"
|
||||
class="group-item"
|
||||
:class="{ 'is-disabled': item.IsEnd }"
|
||||
:style="{ '--delay': `${index * 0.05}s` }"
|
||||
@click="selectGroup(item.id)"
|
||||
@click="selectGroup(item)"
|
||||
>
|
||||
<div class="icon-wrapper">
|
||||
<div class="flower-bg" />
|
||||
@ -94,7 +97,7 @@ onMounted(() => {
|
||||
</div>
|
||||
<div class="group-name-tag">
|
||||
<span class="sun-icon">☀️</span>
|
||||
{{ item.name }}
|
||||
{{ item.Name }}
|
||||
</div>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
@ -133,6 +136,16 @@ onMounted(() => {
|
||||
margin: 0;
|
||||
margin-bottom: 30px;
|
||||
|
||||
&.is-disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
filter: grayscale(100%);
|
||||
|
||||
&:hover {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user