422 lines
9.5 KiB
Vue
422 lines
9.5 KiB
Vue
<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"
|
||
@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="assessment-section" v-if="navigationList.length > 0">
|
||
<view class="section-header">
|
||
<view class="section-indicator"></view>
|
||
<text class="section-title">专业测评</text>
|
||
</view>
|
||
<view class="assessment-grid">
|
||
<view
|
||
class="assessment-card"
|
||
v-for="(item, index) in navigationList"
|
||
:key="index"
|
||
@click="handleNavigationClick(item)"
|
||
>
|
||
<!-- 即将上线标签 -->
|
||
<!-- <view v-if="item.status === 2" class="coming-soon-tag">
|
||
<text>即将上线</text>
|
||
</view> -->
|
||
<image
|
||
:src="item.imageUrl"
|
||
mode="aspectFit"
|
||
class="assessment-icon"
|
||
/>
|
||
<text class="assessment-name">{{ item.name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 关于我们 - 宣传长图 -->
|
||
<view class="promotion-section" v-if="promotionList.length > 0">
|
||
<view class="section-header">
|
||
<view class="section-indicator"></view>
|
||
<text class="section-title">关于我们</text>
|
||
</view>
|
||
<image
|
||
v-for="(item, index) in promotionList"
|
||
:key="index"
|
||
:src="item.imageUrl"
|
||
mode="widthFix"
|
||
class="promotion-image"
|
||
/>
|
||
</view>
|
||
|
||
<!-- 加载状态 -->
|
||
<view class="loading-section" v-if="pageLoading">
|
||
<Loading type="inline" :loading="true" />
|
||
</view>
|
||
|
||
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useUserStore } from '@/store/user.js'
|
||
import { useNavbar } from '@/composables/useNavbar.js'
|
||
import { getBannerList, getAssessmentList, getNavigationList, getPromotionList } from '@/api/home.js'
|
||
import Loading from '@/components/Loading/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 navigationList = ref([])
|
||
const promotionList = ref([])
|
||
|
||
// 导航栏样式已直接在模板中绑定
|
||
|
||
/**
|
||
* 加载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)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 加载测评入口数据
|
||
*/
|
||
async function loadAssessmentList() {
|
||
try {
|
||
const res = await getAssessmentList()
|
||
if (res && res.code === 0 && res.data) {
|
||
assessmentList.value = Array.isArray(res.data) ? res.data : (res.data.list || [])
|
||
}
|
||
} catch (error) {
|
||
console.error('加载测评入口失败:', error)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 加载首页导航入口数据
|
||
*/
|
||
async function loadNavigationList() {
|
||
try {
|
||
const res = await getNavigationList()
|
||
if (res && res.code === 0 && res.data) {
|
||
navigationList.value = Array.isArray(res.data) ? res.data : (res.data.list || [])
|
||
}
|
||
} catch (error) {
|
||
console.error('加载导航入口失败:', error)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 加载宣传图数据
|
||
*/
|
||
async function loadPromotionList() {
|
||
try {
|
||
const res = await getPromotionList()
|
||
if (res && res.code === 0 && res.data) {
|
||
promotionList.value = Array.isArray(res.data) ? res.data : (res.data.list || [])
|
||
}
|
||
} catch (error) {
|
||
console.error('加载宣传图失败:', error)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 初始化页面数据
|
||
*/
|
||
async function initPageData() {
|
||
pageLoading.value = true
|
||
try {
|
||
// 恢复用户登录状态
|
||
userStore.restoreFromStorage()
|
||
|
||
// 并行加载所有数据
|
||
await Promise.all([
|
||
loadBannerList(),
|
||
loadAssessmentList(),
|
||
loadNavigationList(),
|
||
loadPromotionList()
|
||
])
|
||
} finally {
|
||
pageLoading.value = false
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理Banner点击
|
||
*/
|
||
function handleBannerClick(item) {
|
||
if (!item.linkUrl) return
|
||
|
||
// 根据链接类型跳转(0=无 1=内部页面 2=外部链接 3=小程序)
|
||
if (item.linkType === 1) {
|
||
// 小程序内页面跳转
|
||
uni.navigateTo({
|
||
url: item.linkUrl,
|
||
fail: () => {
|
||
// 如果是tabBar页面,使用switchTab
|
||
uni.switchTab({
|
||
url: item.linkUrl
|
||
})
|
||
}
|
||
})
|
||
} else if (item.linkType === 2) {
|
||
// 跳转到webview页面
|
||
uni.navigateTo({
|
||
url: `/pages/webview/index?url=${encodeURIComponent(item.linkUrl)}`
|
||
})
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理导航入口点击
|
||
*/
|
||
function handleNavigationClick(item) {
|
||
// 即将上线的导航,弹出提示
|
||
if (item.status === 2) {
|
||
uni.showToast({
|
||
title: '该功能即将上线',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
return
|
||
}
|
||
|
||
// 根据后台配置的跳转链接进行导航
|
||
if (!item.linkUrl) return
|
||
|
||
uni.navigateTo({
|
||
url: item.linkUrl,
|
||
fail: () => {
|
||
// 如果是tabBar页面,使用switchTab
|
||
uni.switchTab({ url: item.linkUrl })
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* scroll-view 下拉刷新
|
||
*/
|
||
async function onRefresh() {
|
||
isRefreshing.value = true
|
||
await initPageData()
|
||
isRefreshing.value = false
|
||
}
|
||
|
||
/**
|
||
* 页面加载
|
||
*/
|
||
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%;
|
||
}
|
||
|
||
// 页面内容(scroll-view 需要固定高度)
|
||
.page-content {
|
||
height: calc(100vh - var(--navbar-height, 0px));
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
}
|
||
|
||
// Banner轮播
|
||
.banner-section {
|
||
width: 100%;
|
||
padding: 0 $spacing-lg;
|
||
box-sizing: border-box;
|
||
margin-top: $spacing-sm;
|
||
|
||
.banner-swiper {
|
||
width: 100%;
|
||
// 按设计图比例 750:360 ≈ 2:1,减去两侧 padding 后约 686rpx 宽,高度约 330rpx
|
||
height: 330rpx;
|
||
border-radius: $border-radius-lg;
|
||
overflow: hidden;
|
||
|
||
.banner-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: $border-radius-lg;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 区块标题
|
||
.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;
|
||
}
|
||
}
|
||
|
||
// 测评入口 - 横向排列
|
||
.assessment-section {
|
||
padding: $spacing-xl $spacing-lg $spacing-lg;
|
||
|
||
.assessment-grid {
|
||
display: flex;
|
||
gap: $spacing-md;
|
||
}
|
||
|
||
.assessment-card {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
width: 200rpx;
|
||
|
||
.coming-soon-tag {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
background-color: $warning-color;
|
||
padding: 4rpx 16rpx;
|
||
border-radius: 0 $border-radius-xl 0 $border-radius-lg;
|
||
z-index: 1;
|
||
|
||
text {
|
||
font-size: $font-size-xs;
|
||
color: $text-white;
|
||
}
|
||
}
|
||
|
||
.assessment-icon {
|
||
width: 200rpx;
|
||
height: 200rpx;
|
||
border-radius: $border-radius-xl;
|
||
}
|
||
|
||
.assessment-name {
|
||
margin-top: $spacing-sm;
|
||
font-size: $font-size-md;
|
||
font-weight: $font-weight-bold;
|
||
color: $text-color;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 关于我们 - 宣传长图
|
||
.promotion-section {
|
||
padding: $spacing-lg $spacing-lg 0;
|
||
|
||
.promotion-image {
|
||
width: 100%;
|
||
display: block;
|
||
margin-bottom: $spacing-md;
|
||
border-radius: $border-radius-lg;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 加载状态
|
||
.loading-section {
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 100rpx 0;
|
||
}
|
||
|
||
// 底部安全区域
|
||
.safe-bottom {
|
||
height: 40rpx;
|
||
padding-bottom: env(safe-area-inset-bottom);
|
||
}
|
||
</style>
|