Files
gym-manage/gym-manage-uniapp/components/index/QuickEntry.vue
T

200 lines
4.7 KiB
Vue

<template>
<view class="quick-entry">
<view
v-for="(item, index) in entries"
:key="index"
class="entry-item"
@tap="handleEntryClick(item)"
>
<view :class="['entry-icon', { accent: item.accent }]">
<image :src="item.icon" mode="aspectFit" class="icon-img" />
</view>
<text class="entry-title">{{ item.title }}</text>
<text class="entry-desc">{{ item.desc }}</text>
</view>
</view>
</template>
<script setup>
import { qrSignInGroupCourse } from '@/api/groupCourse.js'
import { getMemberId } from '@/utils/request.js'
const handleEntryClick = (item) => {
if (item.title === '签到') {
const token = uni.getStorageSync('token')
if (!token) {
uni.showModal({
title: '请登录',
content: '是否跳转到登录页面?',
confirmText: '确定',
cancelText: '取消',
confirmColor: '#FF6B35',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/login/login'
})
}
}
})
return
}
// 直接调用扫码签到
qrScanSignIn()
} else if (item.path) {
if (item.isTabBar) {
uni.switchTab({
url: item.path
})
} else {
uni.navigateTo({
url: item.path
})
}
}
}
const qrScanSignIn = () => {
uni.scanCode({
onlyFromCamera: true,
success: async (res) => {
console.log('扫码结果:', res)
const qrContent = res.result
// 解析二维码内容获取 courseId 和课程名称
let courseId = null
let courseName = ''
try {
const parsed = JSON.parse(qrContent)
courseId = Number(parsed.id || parsed.courseId)
courseName = parsed.courseName || ''
} catch {
const num = Number(qrContent)
if (!isNaN(num)) {
courseId = num
}
}
if (!courseId) {
uni.showToast({ title: '无效的签到二维码', icon: 'none' })
return
}
const memberId = getMemberId()
if (!memberId) {
uni.showToast({ title: '请先登录', icon: 'none' })
return
}
uni.showLoading({ title: '签到中...' })
try {
const result = await qrSignInGroupCourse(courseId, memberId)
uni.hideLoading()
if (result.success) {
uni.showToast({ title: courseName ? `${courseName}」签到成功` : '签到成功', icon: 'success' })
setTimeout(() => {
uni.navigateTo({ url: '/pages/memberInfo/myCourses' })
}, 1200)
} else {
uni.showToast({ title: result.message || '签到失败', icon: 'none', duration: 3000 })
}
} catch (e) {
uni.hideLoading()
console.error('团课签到失败:', e)
let errMsg = e?.message || e?.data?.message || '签到失败'
// 附加课程名称(如果已知)
if (courseName && !errMsg.includes(courseName)) {
errMsg = `${courseName}${errMsg}`
}
uni.showToast({ title: errMsg, icon: 'none', duration: 3000 })
}
},
fail: (err) => {
console.error('扫码失败:', err)
}
})
}
const entries = [
{
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/icons/course.png',
title: '找课程',
desc: '精品课程',
accent: false,
path: "/pages/groupCourse/list"
},
{
icon: 'https://gymfuture.oss-cn-chengdu.aliyuncs.com/static/icons/checkIn.png',
title: '签到',
desc: '打卡签到',
accent: false,
path: "/pages/checkIn/checkIn"
}
]
</script>
<style lang="scss" scoped>
.quick-entry {
display: flex;
justify-content: space-between;
padding: 32rpx 24rpx;
background: #FFFFFF;
margin: 24rpx;
border-radius: 28rpx;
box-shadow: 0 8rpx 32rpx rgba(45,74,90,0.08);
}
.entry-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.entry-icon {
width: 104rpx;
height: 104rpx;
border-radius: 24rpx;
background: rgba(130, 220, 130, 0.9);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
box-shadow: 0 6rpx 20rpx rgba(130, 220, 130, 0.35);
position: relative;
}
.badge-dot {
position: absolute;
top: 8rpx;
right: 8rpx;
width: 16rpx;
height: 16rpx;
background: linear-gradient(135deg, #FF4757, #FF2D55);
border-radius: 50%;
box-shadow: 0 2rpx 8rpx rgba(255, 71, 87, 0.5);
z-index: 99;
animation: pulse 2s infinite;
}
.icon-img {
width: 52rpx;
height: 52rpx;
}
.entry-icon.accent {
background: rgba(130, 220, 130, 0.9);
}
.entry-title {
font-size: 26rpx;
font-weight: 600;
color: #2D4A5A;
margin-bottom: 4rpx;
}
.entry-desc {
font-size: 22rpx;
color: var(--tabbar-text-inactive);
}
</style>