Files
school2-taro/src/pages/index/index.tsx
T
2026-07-13 14:44:13 +08:00

181 lines
5.7 KiB
TypeScript
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.
import { View, Image } from '@tarojs/components'
import { Search, Swiper, SwiperItem, Grid, GridItem } from '@antmjs/vantui'
import { useState, useEffect } from 'react'
import Taro from '@tarojs/taro'
import { getHomeData } from '@/api/home'
import type { CarouselItem, GridNavItem } from '@/api/home'
import './index.less'
// 背景图
import bgImg from '../../../static/img/bg.png'
// ==================== 本地兜底数据 ====================
// ==================== 工具函数 ====================
/** 排序 + 过滤启用的项 */
function prepareItems<T extends { status: number; sort: number }>(items: T[]): T[] {
return items
.filter((item) => item.status === 0)
.sort((a, b) => a.sort - b.sort)
}
/** 处理导航跳转 */
function handleNavigate(link: string): void {
if (!link) return
if(link.startsWith('http')) {
window.location.href = link
} else {
Taro.navigateTo({ url: link }).catch(() => {
Taro.switchTab({ url: link }).catch(() => {
console.warn('导航失败:', link)
})
})
}
}
// ==================== 页面组件 ====================
export default function Index() {
const [searchValue, setSearchValue] = useState('')
const [carousel, setCarousel] = useState<CarouselItem[]>([])
const [gridNav, setGridNav] = useState<GridNavItem[]>([])
const [loading, setLoading] = useState(true)
// 获取首页数据
useEffect(() => {
async function fetchHomeData() {
try {
const res = await getHomeData()
if (res.success && res.data) {
// 轮播图:API 有数据则用,否则兜底
if (res.data.carousel?.length > 0) {
setCarousel(prepareItems(res.data.carousel))
}
// 宫格导航:API 有数据则用,否则兜底
if (res.data.gridNav?.length > 0) {
setGridNav(prepareItems(res.data.gridNav))
}
}
} catch (err) {
console.warn('获取首页数据失败,使用本地兜底数据', err)
} finally {
setLoading(false)
}
}
fetchHomeData()
}, [])
return (
<View className='index'>
{/* 背景图层 */}
<Image className='bg-image' src={bgImg} mode='widthFix' />
{/* 内容层 */}
<View className='index-content'>
{/* 1. 顶部搜索栏 */}
<View className='search-wrapper'>
<Search
value={searchValue}
onChange={(e) => setSearchValue(e.detail)}
shape='round'
placeholder='搜索美食、餐厅...'
background='rgba(255,255,255,0.9)'
onSearch={() => {
// 搜索逻辑
}}
/>
</View>
{/* 2. 中间轮播图 */}
<View className='swiper-wrapper'>
{carousel.length > 0 ? (
<Swiper
autoPlay={3000}
loop
paginationVisible
paginationColor='#ffffff'
duration={500}
height={220}
>
{carousel.map((item) => (
<SwiperItem key={item.id}>
<Image
className='swiper-img'
src={item.image.preview_url}
mode='aspectFill'
onClick={() => handleNavigate(item.link)}
/>
</SwiperItem>
))}
</Swiper>
) : (
<View className='swiper-placeholder'>暂无轮播图</View>
)}
</View>
{/* 3. 宫格导航 */}
<View className='grid-wrapper'>
{gridNav.length > 0 ? (
<Grid columnNum={5} border={false} gutter={12} iconSize={48}>
{gridNav.map((item) => (
<GridItem
key={item.id}
icon={item.image.preview_url}
text={item.title}
onClick={() => handleNavigate(item.link)}
/>
))}
</Grid>
) : (
<View className='grid-placeholder'>暂无分类</View>
)}
</View>
{/* 4. 底部推荐卡片 */}
<View className='bottom-section'>
<View className='section-card card-hot'>
<View className='card-icon'>🔥</View>
<View className='card-info'>
<View className='card-title'>热门推荐</View>
<View className='card-desc'>查看同学们都在点什么</View>
</View>
<View className='card-arrow'></View>
</View>
<View className='section-card card-discount'>
<View className='card-icon'>💰</View>
<View className='card-info'>
<View className='card-title'>限时优惠</View>
<View className='card-desc'>超值套餐低至9.9</View>
</View>
<View className='card-arrow'></View>
</View>
<View className='section-card card-new'>
<View className='card-icon'></View>
<View className='card-info'>
<View className='card-title'>新品上架</View>
<View className='card-desc'>尝尝校园新味道</View>
</View>
<View className='card-arrow'></View>
</View>
<View className='section-card card-order'>
<View className='card-icon'>📋</View>
<View className='card-info'>
<View className='card-title'>我的订单</View>
<View className='card-desc'>查看订单状态与历史</View>
</View>
<View className='card-arrow'></View>
</View>
</View>
{/* 底部留白 */}
<View className='bottom-spacer' />
</View>
</View>
)
}