mi-assessment/uniapp/pages/index/index.vue
2026-02-23 19:19:35 +08:00

422 lines
9.5 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"
@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>