This commit is contained in:
Quincy_J 2025-07-29 22:42:56 +08:00
parent c7bbf42e96
commit cd569f2881
8 changed files with 305 additions and 7 deletions

View File

@ -35,7 +35,7 @@ export default defineUniPages({
{
iconPath: 'static/tabbar/document.svg',
selectedIconPath: 'static/tabbar/documentHL.svg',
pagePath: 'pages/fate/fate',
pagePath: 'pages/exam/my',
text: '考试',
},
],

View File

@ -32,7 +32,7 @@
{
"iconPath": "static/tabbar/document.svg",
"selectedIconPath": "static/tabbar/documentHL.svg",
"pagePath": "pages/fate/fate",
"pagePath": "pages/exam/my",
"text": "考试"
}
]
@ -45,6 +45,13 @@
"navigationBarTitleText": ""
}
},
{
"path": "pages/exam/my",
"type": "home",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/exam/detail",
"type": "home",
@ -86,7 +93,7 @@
"type": "page",
"layout": "default",
"style": {
"navigationBarTitleText": "红娘"
"navigationBarTitleText": ""
}
},
{

282
src/pages/exam/my.vue Normal file
View File

@ -0,0 +1,282 @@
<!-- 使用 type="home" 属性设置首页其他页面不需要设置默认为page推荐使用json5更强大且允许注释 -->
<route lang="json5" type="home">
{
style: {
navigationBarTitleText: '',
},
}
</route>
<template>
<view class="px-4 py-3" @click="closeUserMenu">
<!-- 顶部栏 -->
<view class="flex items-center justify-between mb-6">
<text class="text-lg font-bold">我的考试</text>
</view>
<!-- 考试列表 -->
<view class="space-y-6">
<view
v-for="exam in examList"
:key="exam.id"
class="bg-white rounded-lg shadow-xl p-4 border-2 border-gray-400 relative transition-all duration-300 hover:shadow-2xl hover:-translate-y-1 hover:border-gray-500 cursor-pointer"
style="
box-shadow:
0 8px 16px -4px rgba(0, 0, 0, 0.15),
0 4px 8px -2px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
padding-top: 2.5rem;
"
@mouseenter="handleCardHover(exam.id)"
@mouseleave="handleCardLeave(exam.id)"
>
<!-- 状态标签 -->
<view
:class="[
'absolute left-4 top-4 px-3 py-1 rounded-full text-xs font-bold',
statusClass(exam.status),
]"
>
{{ statusText(exam.status) }}
</view>
<view class="h-4"></view>
<!-- 第一行考试名称 -->
<view class="mb-2">
<text class="text-xl font-bold text-gray-800">{{ exam.examName }}</text>
</view>
<!-- 第二行考试时间 -->
<view class="mb-2">
<text class="text-base text-gray-600">
{{ formatExamTime(exam.examDate, exam.startTime, exam.endTime) }}
</text>
</view>
<!-- 第三行考试地点 -->
<view class="mb-2">
<text class="text-base text-gray-600">
{{
formatExamLocation(exam.provinceName, exam.cityName, exam.address, exam.locationName)
}}
</text>
</view>
<!-- 第四五行空白间距 -->
<view class="h-4"></view>
<view class="h-4"></view>
<!-- 第六行报名截止信息 -->
<view class="mb-4">
<text class="text-sm text-gray-500">报名截止{{ exam.registrationDeadline }}</text>
</view>
</view>
</view>
<!-- 加载状态 -->
<view v-if="loading" class="text-center py-8">
<text class="text-gray-500">加载中...</text>
</view>
<!-- 空状态 -->
<view v-if="!loading && examList.length === 0" class="text-center py-8">
<text class="text-gray-500">暂无可报名的考试</text>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { getAlreadyBookExamList } from '@/service/exam'
import { onLoad, onShow } from '@dcloudio/uni-app'
defineOptions({
name: 'Home',
})
const userName = ref('')
const showUserMenu = ref(false)
const examList = ref([])
const loading = ref(false)
//
const getExamList = async () => {
loading.value = true
try {
const res = await getAlreadyBookExamList()
examList.value = res.data.list || []
} catch (error) {
console.error('获取考试列表失败:', error)
uni.showToast({
title: '获取考试列表失败',
icon: 'none',
})
} finally {
loading.value = false
}
}
//
const formatExamTime = (examDate: string, startTime: string, endTime: string) => {
if (!examDate || !startTime || !endTime) return ''
return `${examDate} ${startTime}-${endTime}`
}
//
const formatExamLocation = (
provinceName: string,
cityName: string,
address: string,
locationName: string,
) => {
const parts = [provinceName, cityName, address, locationName].filter(Boolean)
return parts.join('')
}
//
const handleRegisterExam = (exam: any) => {
uni.navigateTo({
url: `/pages/exam/detail?id=${exam.id}`,
})
}
// hover
const handleCardHover = (examId: string) => {
// hover
console.log('卡片hover:', examId)
}
const handleCardLeave = (examId: string) => {
//
console.log('卡片离开:', examId)
}
//
const toggleUserMenu = () => {
showUserMenu.value = !showUserMenu.value
}
//
const closeUserMenu = () => {
showUserMenu.value = false
}
//
const handleModifyPassword = () => {
showUserMenu.value = false
uni.navigateTo({
url: '/pages/user/modify-password',
})
}
//
const handleModifyProfile = () => {
showUserMenu.value = false
uni.navigateTo({
url: '/pages/user/profile',
})
}
// 退
const handleLogout = () => {
showUserMenu.value = false
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
//
uni.removeStorageSync('token')
uni.removeStorageSync('loginData')
//
uni.reLaunch({
url: '/pages/login/index',
})
}
},
})
}
//
const statusText = (status: string) => {
switch (status) {
case '2':
return '待举办'
case '4':
return '待考试'
case '5':
return '进行中'
case '100':
return '已结束'
case '101':
return '已发证'
case '-4':
return '撤销考试'
default:
return '已报名'
}
}
//
const statusClass = (status: string) => {
switch (status) {
case '2':
return 'bg-blue-100 text-blue-600'
case '4':
return 'bg-yellow-100 text-yellow-700'
case '5':
return 'bg-green-100 text-green-600'
case '100':
return 'bg-gray-100 text-gray-500'
case '101':
return 'bg-purple-100 text-purple-600'
case '-4':
return 'bg-red-100 text-red-600'
default:
return 'bg-gray-200 text-gray-500'
}
}
onLoad(() => {
//
try {
const loginData = uni.getStorageSync('loginData')
userName.value = loginData.user.nickName
} catch (e) {
userName.value = ''
}
// getExamList() // onShow
})
onShow(() => {
getExamList()
})
//
onPullDownRefresh(() => {
getExamList().then(() => {
uni.stopPullDownRefresh()
})
})
</script>
<style scoped>
/* 菜单淡入淡出动画 */
.menu-fade-enter-active,
.menu-fade-leave-active {
transition: all 0.2s ease-in-out;
}
.menu-fade-enter-from {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
.menu-fade-leave-to {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
.menu-fade-enter-to,
.menu-fade-leave-from {
opacity: 1;
transform: scale(1) translateY(0);
}
</style>

View File

@ -2,7 +2,7 @@
<view class="mb-8">
<view class="flex justify-between items-center mb-4">
<view class="flex items-center">
<text class="text-2xl font-bold text-primary">红娘推荐</text>
<text class="text-2xl font-bold text-primary">红娘推荐111</text>
<view class="ml-2 px-2 py-1 bg-primary/10 rounded-full">
<text class="text-xs text-primary font-medium">专业认证</text>
</view>

View File

@ -2,7 +2,7 @@
{
layout: 'default',
style: {
navigationBarTitleText: '红娘',
navigationBarTitleText: '',
},
}
</route>

View File

@ -162,7 +162,7 @@ const formatExamLocation = (
locationName: string,
) => {
const parts = [provinceName, cityName, address, locationName].filter(Boolean)
return parts.join(' ')
return parts.join('')
}
//

View File

@ -15,6 +15,7 @@ export interface ExamItem {
estimatedAttendees: string
examinersName?: string
supervisorsName?: string
status?: number
}
/** 获取可报名考试列表 */
@ -25,6 +26,13 @@ export const getCanBookExamListAPI = () =>
export const getCanBookExamInfoAPI = (id: string) =>
request.get<BaseResponse<ExamItem>>('/exam/getCanBookExamInfo', { params: { id } })
export const getAlreadyBookExamList = (id: string) =>
request.get<BaseResponse<ExamItem>>('/exam/getAlreadyBookExamList', { params: { id } })
/** 报名接口 */
export const joinExamInfoAPI = (id: string) =>
request.get<BaseResponse<any>>('/exam/joinExamInfo', { params: { id } })
/** 获取已报名考试列表 */
export const getAlreadyBookExamListAPI = () =>
request.get<BaseResponse<ExamItem[]>>('/exam/getAlreadyBookExamList')

View File

@ -5,6 +5,7 @@
interface NavigateToOptions {
url: "/pages/index/index" |
"/pages/exam/my" |
"/pages/exam/detail" |
"/pages/activity/detail" |
"/pages/activity/index" |
@ -32,7 +33,7 @@ interface NavigateToOptions {
interface RedirectToOptions extends NavigateToOptions {}
interface SwitchTabOptions {
url: "/pages/index/index" | "/pages/fate/fate"
url: "/pages/index/index" | "/pages/exam/my"
}
type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;