feat(user): 重构用户端竞赛流程,集成后端API并优化交互体验

- 新增 `activityinfo` store 管理活动信息,支持持久化
- 重构 `competition` store,分离数据层与流程控制,新增音效管理
- 新增游戏API模块 (`game.ts`),实现抽题、题目详情、提交结果等接口
- 用户端页面全面对接后端数据:首页轮播展示活动列表,组别/队伍页动态加载,封面页显示题目卡片
- 抽题页改为竹签翻转动画,游戏页集成题目详情与倒计时
- 优化布局组件,支持点击返回首页,统一路由参数传递
- 更新类型定义,支持富文本题目渲染
- 添加 `activityinfo` 拼写检查词条
This commit is contained in:
2026-02-10 08:45:26 +08:00
parent 0fd8ef527a
commit 61a7412fc1
23 changed files with 962 additions and 643 deletions

View File

@ -1,9 +1,12 @@
<script lang="ts" setup>
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'
const { routerPushByKey } = useRouterPush()
const { routerPushByKey, routerBack } = useRouterPush()
const route = useRoute()
interface GroupItem {
id: number
@ -11,23 +14,40 @@ interface GroupItem {
icon: string
}
const groups = ref<GroupItem[]>([
{ id: 1, name: '初赛一组', icon: 'activity' },
{ id: 2, name: '初赛七组', icon: 'cast' },
{ id: 3, name: '初赛八组', icon: 'chrome' },
{ id: 4, name: '初赛九组', icon: 'heart' },
{ id: 5, name: '初赛十组', icon: 'activity' },
{ id: 6, name: '初赛六组', icon: 'cast' },
{ id: 7, name: '初赛七组', icon: 'chrome' },
{ id: 8, name: '初赛八组', icon: 'heart' },
{ id: 9, name: '初赛九组', icon: 'activity' },
{ id: 10, name: '初赛十组', icon: 'cast' },
])
const groups = ref<GroupItem[]>([])
const loading = ref(false)
const activityId = route.query.activityId as string
async function getGroups() {
if (!activityId)
return
loading.value = true
try {
const { data, error } = await fetchGetGroupList(activityId)
if (error) {
window?.$message?.error(error.message)
return
}
const list = data?.data || []
if (list && Array.isArray(list)) {
groups.value = list.map((item: any) => ({
id: item.Id,
name: item.Name,
icon: 'activity', // Default icon since API might not provide one
}))
}
}
finally {
loading.value = false
}
}
const showContent = ref(false)
function handleBack() {
routerPushByKey('user_home')
routerBack()
}
function handleNext() {
@ -36,12 +56,13 @@ function handleNext() {
function selectGroup(_id: number) {
// 选择组别逻辑
routerPushByKey('user_teams', { query: { id: _id.toString() } })
routerPushByKey('user_teams', { query: { activityId, groupsId: _id } })
}
onMounted(() => {
setTimeout(() => {
showContent.value = true
getGroups()
}, 100)
})
</script>