mi-assessment/uniapp/pages/index/index.vue
18631081161 81f38874c8
All checks were successful
continuous-integration/drone/push Build is passing
逻辑优化
2026-03-26 01:07:39 +08:00

462 lines
10 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>
<view class="home-page">
<!-- 自定义导航栏 -->
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="navbar-content" :style="{ height: navbarHeight + 'px' }">
<text class="navbar-title">首页</text>
</view>
</view>
<!-- 导航栏占位 -->
<view class="navbar-placeholder" :style="{ height: totalNavbarHeight + 'px' }"></view>
<!-- 页面内容 -->
<scroll-view
class="page-content"
scroll-y
refresher-enabled
:refresher-triggered="isRefreshing"
:style="{ height: 'calc(100vh - ' + totalNavbarHeight + 'px)' }"
@refresherrefresh="onRefresh"
>
<!-- Banner 轮播图 -->
<view class="banner-section" v-if="bannerList.length > 0">
<swiper
class="banner-swiper"
:indicator-dots="bannerList.length > 1"
indicator-color="rgba(255,255,255,0.5)"
indicator-active-color="#FFFFFF"
:autoplay="true"
:interval="4000"
:circular="true"
>
<swiper-item
v-for="(item, index) in bannerList"
:key="index"
@click="handleBannerClick(item)"
>
<image
:src="item.imageUrl"
mode="aspectFill"
class="banner-image"
/>
</swiper-item>
</swiper>
</view>
<!-- 专业测评入口 -->
<view class="section-card" v-if="assessmentList.length > 0">
<view class="section-header">
<view class="section-indicator"></view>
<text class="section-title">专业测评</text>
</view>
<scroll-view class="assessment-scroll" scroll-x enhanced :show-scrollbar="false">
<view class="assessment-grid">
<view
class="assessment-card"
v-for="(item, index) in assessmentList"
:key="index"
@click="handleCardClick(item)"
>
<image
:src="item.imageUrl"
mode="aspectFit"
class="assessment-image"
/>
</view>
</view>
</scroll-view>
</view>
<!-- 学业规划 -->
<view class="section-card">
<view class="section-header">
<view class="section-indicator"></view>
<text class="section-title">学业规划</text>
</view>
<view class="planner-btn" @click="goToPlanner">
<text class="planner-btn__text">预约入口</text>
</view>
</view>
<!-- 更多 -->
<view class="section-card" v-if="moreList.length > 0">
<view class="section-header">
<view class="section-indicator"></view>
<text class="section-title">更多</text>
</view>
<view class="more-grid">
<view
class="more-card"
v-for="(item, index) in moreList"
:key="index"
:class="{ 'more-card--full': moreList.length % 2 === 1 && index === moreList.length - 1 }"
@click="handleCardClick(item)"
>
<image
:src="item.imageUrl"
mode="aspectFit"
class="more-card__image"
/>
</view>
</view>
</view>
<!-- 加载状态 -->
<view class="loading-section" v-if="pageLoading">
<Loading type="inline" :loading="true" />
</view>
<!-- 底部安全间距 -->
<view class="safe-bottom"></view>
</scroll-view>
<!-- 客服二维码弹窗 -->
<Popup
:visible="showQrPopup"
:imageUrl="qrcodeUrl"
title="扫码咨询"
:content="qrcodeUrl ? '' : '暂未配置客服二维码'"
@close="showQrPopup = false"
/>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/user.js'
import { useNavbar } from '@/composables/useNavbar.js'
import { getBannerList, getNavigationList } from '@/api/home.js'
import { getContactInfo } from '@/api/system.js'
import Loading from '@/components/Loading/index.vue'
import Popup from '@/components/Popup/index.vue'
const userStore = useUserStore()
const { statusBarHeight, navbarHeight, totalNavbarHeight } = useNavbar()
// 页面数据
const pageLoading = ref(true)
const isRefreshing = ref(false)
const bannerList = ref([])
const assessmentList = ref([])
const moreList = ref([])
const qrcodeUrl = ref('')
const showQrPopup = ref(false)
/**
* 加载Banner数据
*/
async function loadBannerList() {
try {
const res = await getBannerList()
if (res && res.code === 0 && res.data) {
bannerList.value = Array.isArray(res.data) ? res.data : (res.data.list || [])
}
} catch (error) {
console.error('加载Banner失败:', error)
}
}
/**
* 加载专业测评区域数据position=1
*/
async function loadAssessmentList() {
try {
const res = await getNavigationList({ position: 1 })
if (res && res.code === 0 && res.data) {
assessmentList.value = Array.isArray(res.data) ? res.data : (res.data.list || [])
}
} catch (error) {
console.error('加载专业测评数据失败:', error)
}
}
/**
* 加载更多区域数据position=2
*/
async function loadMoreList() {
try {
const res = await getNavigationList({ position: 2 })
if (res && res.code === 0 && res.data) {
moreList.value = Array.isArray(res.data) ? res.data : (res.data.list || [])
}
} catch (error) {
console.error('加载更多区域数据失败:', error)
}
}
/**
* 加载客服二维码URL
*/
async function loadContactInfo() {
try {
const res = await getContactInfo()
if (res && res.code === 0 && res.data) {
qrcodeUrl.value = res.data.qrcodeUrl || ''
}
} catch (error) {
console.error('加载客服二维码失败:', error)
}
}
/**
* 初始化页面数据
*/
async function initPageData() {
pageLoading.value = true
try {
userStore.restoreFromStorage()
await Promise.all([
loadBannerList(),
loadAssessmentList(),
loadMoreList(),
loadContactInfo()
])
} finally {
pageLoading.value = false
}
}
/**
* 处理Banner点击
*/
function handleBannerClick(item) {
if (!item.linkUrl) return
if (item.linkType === 1) {
uni.navigateTo({
url: item.linkUrl,
fail: () => {
uni.switchTab({ url: item.linkUrl })
}
})
} else if (item.linkType === 2) {
uni.navigateTo({
url: `/pages/webview/index?url=${encodeURIComponent(item.linkUrl)}`
})
}
}
/**
* 处理卡片点击(根据 ActionType 分发)
*/
function handleCardClick(item) {
if (item.actionType === 3) {
uni.showToast({ title: '即将上线', icon: 'none', duration: 2000 })
return
}
if (item.actionType === 2) {
showQrPopup.value = true
return
}
// actionType === 1: 跳转页面
if (!item.linkUrl) return
uni.navigateTo({
url: item.linkUrl,
fail: () => {
uni.switchTab({ url: item.linkUrl })
}
})
}
/**
* 跳转学业规划预约
*/
function goToPlanner() {
uni.navigateTo({ url: '/pages/planner/list/index' })
}
/**
* 下拉刷新
*/
async function onRefresh() {
isRefreshing.value = true
await initPageData()
isRefreshing.value = false
}
onLoad((options) => {
// 解析分享链接中的邀请人参数
if (options && options.inviterId) {
console.log('[Index] 从页面参数获取inviterId:', options.inviterId)
uni.setStorageSync('inviterId', options.inviterId)
}
})
onMounted(() => {
initPageData()
})
</script>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.home-page {
min-height: 100vh;
background-color: $bg-color;
}
// 自定义导航栏
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: $bg-white;
z-index: 999;
.navbar-content {
display: flex;
align-items: center;
justify-content: center;
.navbar-title {
font-size: 34rpx;
font-weight: $font-weight-medium;
color: $text-color;
}
}
}
.navbar-placeholder {
width: 100%;
}
// 页面内容
.page-content {
// 高度通过内联 style 动态计算,不在此处设置
}
// Banner轮播
.banner-section {
width: 100%;
padding: 0 $spacing-lg;
box-sizing: border-box;
margin-top: $spacing-sm;
.banner-swiper {
width: 100%;
height: 330rpx;
border-radius: $border-radius-lg;
overflow: hidden;
.banner-image {
width: 100%;
height: 100%;
border-radius: $border-radius-lg;
}
}
}
// 通用区块卡片
.section-card {
margin: $spacing-lg $spacing-lg 0;
padding: $spacing-lg;
background-color: $bg-white;
border-radius: $border-radius-xl;
}
// 区块标题
.section-header {
display: flex;
align-items: center;
margin-bottom: $spacing-lg;
.section-indicator {
width: 8rpx;
height: 36rpx;
background-color: $warning-color;
border-radius: $border-radius-xs;
margin-right: $spacing-sm;
}
.section-title {
font-size: $font-size-xl;
font-weight: $font-weight-bold;
color: $text-color;
}
}
// 专业测评 - 横向滚动一屏最多显示2个
.assessment-scroll {
width: 100%;
white-space: nowrap;
}
.assessment-grid {
display: inline-flex;
gap: $spacing-md;
}
.assessment-card {
position: relative;
// 每个卡片宽度 = (卡片区域总宽 - 间距) / 2
// 卡片区域总宽 = 750rpx - 左右 section-card margin 32rpx*2 - 左右 section-card padding 32rpx*2 = 622rpx
width: 299rpx;
height: 240rpx;
overflow: hidden;
flex-shrink: 0;
.assessment-image {
width: 100%;
height: 100%;
}
}
// 学业规划 - 预约按钮
.planner-btn {
display: flex;
align-items: center;
justify-content: center;
height: 96rpx;
border-radius: $border-radius-round;
background: linear-gradient(90deg, #FFB347, #FF8C42);
&__text {
font-size: $font-size-lg;
font-weight: $font-weight-bold;
color: $text-white;
letter-spacing: 4rpx;
}
}
// 更多 - 网格布局每行2个
.more-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.more-card {
position: relative;
width: 48.5%;
height: 160rpx;
overflow: hidden;
box-sizing: border-box;
margin-bottom: $spacing-md;
// 奇数个时最后一个占满整行
&--full {
width: 100%;
}
&__image {
width: 100%;
height: 100%;
}
}
// 加载状态
.loading-section {
display: flex;
justify-content: center;
padding: 100rpx 0;
}
// 底部安全区域
.safe-bottom {
height: 40rpx;
padding-bottom: env(safe-area-inset-bottom);
}
</style>