first commit
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user