edu/uniapp/src/pages/index/index.vue

487 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<page-meta :page-style="$theme.pageStyle">
<!-- #ifndef H5 -->
<navigation-bar :front-color="$theme.navColor" :background-color="$theme.navBgColor" />
<!-- #endif -->
</page-meta>
<view class="index">
<!-- 顶部区域Logo + 欢迎文字 + 首页图片 -->
<view class="header-section">
<image
:src="schoolLogoSrc"
mode="aspectFit"
class="school-logo"
/>
<view class="welcome-text">
<view class="title" v-if="isTeacher">您好招生老师</view>
<view class="title" v-else>欢迎来到预报名系统</view>
<view class="subtitle" v-if="isTeacher">祝您招生顺利业绩长虹</view>
<view class="subtitle" v-else>请选择下方功能开始操作</view>
</view>
<image
:src="homeImageSrc"
mode="widthFix"
class="home-image"
/>
<!-- 快捷操作标题 -->
<view class="section-title" v-if="isLogin && isTeacher">
<view class="title-icon"></view>
<text>快捷操作</text>
</view>
</view>
<!-- 主要内容区域 -->
<view class="main-content">
<!-- 招生老师:快捷操作入口 -->
<view class="quick-actions" v-if="isLogin && isTeacher">
<view class="action-item" @click="goToPreRegistration">
<view class="action-icon blue">
<u-icon name="edit-pen" size="40" color="#FFFFFF"></u-icon>
</view>
<text class="action-text">预报名</text>
</view>
<view class="action-item" @click="goToMyRecruitment">
<view class="action-icon green">
<u-icon name="list" size="40" color="#FFFFFF"></u-icon>
</view>
<text class="action-text">我的招生</text>
</view>
<view class="action-item" @click="goToPayment">
<view class="action-icon orange">
<u-icon name="rmb-circle" size="40" color="#FFFFFF"></u-icon>
</view>
<text class="action-text">缴费</text>
</view>
<view class="action-item" @click="goToUser">
<view class="action-icon purple">
<u-icon name="account" size="40" color="#FFFFFF"></u-icon>
</view>
<text class="action-text">个人中心</text>
</view>
</view>
<!-- 学生:功能入口 -->
<view class="quick-actions" v-if="isLogin && !isTeacher">
<view class="action-item" @click="goToPreRegistration">
<view class="action-icon blue">
<u-icon name="edit-pen" size="40" color="#FFFFFF"></u-icon>
</view>
<text class="action-text">预报名</text>
</view>
<view class="action-item" @click="goToPayment">
<view class="action-icon orange">
<u-icon name="rmb-circle" size="40" color="#FFFFFF"></u-icon>
</view>
<text class="action-text">缴费</text>
</view>
</view>
<!-- 未登录提示 -->
<view class="login-tip" v-if="!isLogin">
<view class="tip-icon">🔒</view>
<view class="tip-text">登录后查看更多功能</view>
<view class="tip-button" @click="goToLogin">立即登录</view>
</view>
</view>
<!-- #ifdef H5 -->
<view class="footer" v-if="isH5">
<router-navigate
class="footer-link"
:to="{
path: '/pages/webview/webview',
query: {
url: item.value
}
}"
v-for="item in appStore.getCopyrightConfig"
:key="item.key"
>
{{ item.key }}
</router-navigate>
</view>
<!-- #endif -->
<!-- 返回顶部按钮 -->
<u-back-top
:scroll-top="scrollTop"
:top="100"
:customStyle="{
backgroundColor: '#FFF',
color: '#000',
boxShadow: '0px 3px 6px rgba(0, 0, 0, 0.1)'
}"
>
</u-back-top>
<!-- #ifdef MP -->
<!-- 微信小程序隐私弹窗 -->
<MpPrivacyPopup></MpPrivacyPopup>
<!-- #endif -->
<tabbar />
</view>
</template>
<script setup lang="ts">
import { getIndex } from '@/api/shop'
import { getEnrollmentStatistical, getTeacherInfo } from '@/api/app'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { computed, reactive, ref } from 'vue'
import { useAppStore } from '@/stores/app'
import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia'
import { getAliyunImageUrl } from '@/utils/imageUtils'
import { ensureStorageConfig } from '@/utils/configUtils'
// #ifdef MP
import MpPrivacyPopup from './component/mp-privacy-popup.vue'
// #endif
const appStore = useAppStore()
const userStore = useUserStore()
const { isLogin, userInfo, isTeacher } = storeToRefs(userStore)
const state = reactive<{
pages: any[]
meta: any[]
article: any[]
}>({
pages: [],
meta: [],
article: []
})
const scrollTop = ref<number>(0)
const stats = ref({
total: 0,
today: 0,
week: 0
})
const isH5 = ref(false)
// #ifdef H5
isH5.value = true
// #endif
const getData = async () => {
try {
const data = await getIndex()
if (data?.page?.data) {
state.pages = JSON.parse(data.page.data)
}
if (data?.page?.meta) {
state.meta = JSON.parse(data.page.meta)
}
state.article = data?.article || []
} catch (error) {
console.error('获取首页数据失败:', error)
}
}
const getStats = async () => {
if (!isLogin.value) {
return
}
try {
// 先获取教师信息,获取 teacherId
let teacherId: number | undefined = undefined
// 尝试从 userInfo 中获取
if (userInfo.value?.teacherId) {
teacherId = userInfo.value.teacherId
} else {
// 如果 userInfo 中没有,调用 getTeacherInfo 获取
try {
const teacherRes = await getTeacherInfo({ id: userInfo.value.id })
if (teacherRes && teacherRes.code === 1 && teacherRes.data) {
teacherId = teacherRes.data.teacherId
// 更新 userInfo
userInfo.value.teacherId = teacherId
}
} catch (error) {
console.error('获取教师信息失败:', error)
}
}
if (teacherId) {
console.log('首页获取招生统计teacherId:', teacherId)
const res = await getEnrollmentStatistical(teacherId)
// 接口直接返回数据对象,没有 code 包装
if (res && res.total_enroll_count !== undefined) {
stats.value = {
total: res.total_enroll_count,
today: res.today_enroll_count,
week: res.week_enroll_count
}
}
} else {
console.log('未找到 teacherId跳过获取招生统计')
}
} catch (error) {
console.error('获取招生统计失败:', error)
}
}
const goToPreRegistration = () => {
uni.navigateTo({
url: '/pages/pre_registration/pre_registration'
})
}
const goToMyRecruitment = () => {
uni.navigateTo({
url: '/pages/my_recruitment/my_recruitment'
})
}
const goToUser = () => {
uni.reLaunch({
url: '/pages/user/user'
})
}
const goToPayment = () => {
uni.navigateTo({
url: '/pages/payment/payment'
})
}
const goToLogin = () => {
uni.navigateTo({
url: '/pages/login/login'
})
}
// 初始化图片源
const schoolLogoSrc = ref(getAliyunImageUrl('static/yubaoming/school_logo.png'))
const homeImageSrc = ref(getAliyunImageUrl('static/yubaoming/home.png'))
const initImageSources = async () => {
await ensureStorageConfig()
schoolLogoSrc.value = getAliyunImageUrl('static/yubaoming/school_logo.png')
homeImageSrc.value = getAliyunImageUrl('static/yubaoming/home.png')
}
const shareQrcode = () => {
uni.reLaunch({
url: '/pages/user/user'
})
setTimeout(() => {
uni.$emit('openQrcodeModal')
}, 300)
}
onLoad((options: any) => {
initImageSources()
getData()
if (options.scene) {
const invitationCode = decodeURIComponent(options.scene)
if (isLogin.value) {
uni.navigateTo({
url: `/pages/pre_registration/pre_registration?invitationCode=${invitationCode}`
})
} else {
uni.navigateTo({
url: `/pages/login/login?invitationCode=${invitationCode}`
})
}
}
})
onShow(async () => {
// 等待登录状态确定
await new Promise(resolve => setTimeout(resolve, 100))
// 如果没有登录,跳过
if (!isLogin.value) {
return
}
// 如果 userInfo 中没有用户信息,先调用 getUser 获取用户信息
if (!userInfo.value?.id) {
await userStore.getUser()
}
// 获取招生统计getStats 内部会处理获取 teacherId
getStats()
})
</script>
<style lang="scss" scoped>
.index {
min-height: 100vh;
background-color: #F5F7FA;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
}
/* 顶部区域 */
.header-section {
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 30rpx;
position: relative;
.school-logo {
width: 350rpx;
height: 350rpx;
margin-top: -40rpx;
margin-bottom: -80rpx;
}
.welcome-text {
text-align: center;
margin-bottom: -100rpx;
.title {
font-size: 40rpx;
font-weight: 600;
color: #000000;
margin-bottom: 12rpx;
}
.subtitle {
font-size: 28rpx;
color: #333333;
}
}
.home-image {
width: calc(100% + 60rpx);
margin-left: -30rpx;
margin-right: -30rpx;
}
}
/* 主要内容区域 */
.main-content {
padding: 0 30rpx 30rpx;
position: relative;
z-index: 1;
}
/* 快捷操作标题 */
.section-title {
display: flex;
align-items: center;
font-size: 32rpx;
font-weight: 600;
color: #000000;
padding: 20rpx 0;
position: absolute;
bottom: 50rpx;
left: 30rpx;
z-index: 10;
.title-icon {
margin-right: 12rpx;
width: 10rpx;
height: 32rpx;
background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
border-radius: 3rpx;
}
}
/* 快捷操作 */
.quick-actions {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 20rpx;
margin-top: -30rpx;
.action-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
background: #FFFFFF;
border-radius: 24rpx;
padding: 30rpx 20rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
&:active {
opacity: 0.7;
}
.action-icon {
width: 100rpx;
height: 100rpx;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
&.blue {
background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
}
&.green {
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
}
&.purple {
background: linear-gradient(135deg, #8B5CF6 0%, #7C3AED 100%);
}
&.orange {
background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%);
}
}
.action-text {
font-size: 26rpx;
color: #1F2937;
font-weight: 500;
}
}
}
/* 未登录提示 */
.login-tip {
background: #FFFFFF;
border-radius: 24rpx;
padding: 60rpx 40rpx;
text-align: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
.tip-icon {
font-size: 80rpx;
margin-bottom: 20rpx;
}
.tip-text {
font-size: 30rpx;
color: #6B7280;
margin-bottom: 30rpx;
}
.tip-button {
display: inline-block;
background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
color: #FFFFFF;
font-size: 30rpx;
font-weight: 500;
padding: 20rpx 60rpx;
border-radius: 40rpx;
&:active {
opacity: 0.9;
}
}
}
/* 底部 */
.footer {
padding: 40rpx 30rpx;
text-align: center;
.footer-link {
font-size: 24rpx;
color: #9CA3AF;
margin: 0 16rpx;
}
}
</style>