Files
market_page/miniprogram/src/pages/index/index.tsx
jeremygan2021 96d5598fb5 vb
2026-02-11 03:00:38 +08:00

127 lines
4.3 KiB
TypeScript

import { View, Text, Image, ScrollView, Button } from '@tarojs/components'
import Taro, { useLoad } from '@tarojs/taro'
import { useState, useEffect } from 'react'
import { getConfigs } from '../../api'
import ParticleBackground from '../../components/ParticleBackground'
import './index.scss'
export default function Index() {
const [products, setProducts] = useState<any[]>([])
const [typedText, setTypedText] = useState('')
const [loading, setLoading] = useState(true)
const [error, setError] = useState('')
const fullText = "未来已来 AI 核心驱动"
useLoad(() => {
fetchProducts()
})
useEffect(() => {
let i = 0
const interval = setInterval(() => {
i++
setTypedText(fullText.slice(0, i))
if (i >= fullText.length) clearInterval(interval)
}, 150)
return () => clearInterval(interval)
}, [])
const fetchProducts = async () => {
setLoading(true)
setError('')
try {
const res: any = await getConfigs()
const list = Array.isArray(res) ? res : (res.results || res.data || [])
setProducts(list)
} catch (err: any) {
console.error(err)
setError(err.errMsg || '加载失败,请检查网络')
} finally {
setLoading(false)
}
}
const goToDetail = (id: number) => {
Taro.navigateTo({ url: `/pages/goods/detail?id=${id}` })
}
return (
<View className='page-container'>
<ParticleBackground />
<ScrollView scrollY className='content-scroll'>
<View className='scroll-inner'>
<View className='header'>
<View className='logo-box'>
<Image src='../../assets/logo.svg' className='logo-img' mode='widthFix' />
<Text className='logo-text'>QUANT SPEED</Text>
</View>
<View className='title-container'>
<Text className='title-text'>{typedText}</Text>
<Text className='cursor'>|</Text>
</View>
<Text className='subtitle'> AI </Text>
</View>
{loading ? (
<View className='skeleton-wrapper'>
{[1, 2, 3].map(i => (
<View key={i} className='skeleton-card' />
))}
</View>
) : error ? (
<View className='status-box'>
<Text className='error-text'>{error}</Text>
<Button className='btn-retry' onClick={fetchProducts}></Button>
</View>
) : (
<View className='product-grid'>
{products.map((item, index) => (
<View
key={item.id}
className='card fade-in-up'
style={{ animationDelay: `${index * 0.1}s` }}
onClick={() => goToDetail(item.id)}
>
<View className='card-cover'>
{item.static_image_url ? (
<Image src={item.static_image_url} mode='aspectFill' className='card-img' />
) : (
<View className='placeholder-img'>
<View className='radar-scan'></View>
</View>
)}
<View className='card-overlay' />
</View>
<View className='card-body'>
<View className='card-header'>
<Text className='card-title'>{item.name}</Text>
<Text className='price'>¥{item.price}</Text>
</View>
<Text className='card-desc'>{item.description}</Text>
<View className='tags'>
<View className='tag cyan'><Text>{item.chip_type}</Text></View>
{item.has_camera && <View className='tag blue'><Text>Camera</Text></View>}
{item.has_microphone && <View className='tag purple'><Text>Mic</Text></View>}
</View>
<View className='card-footer'>
<Button className='btn-buy'></Button>
</View>
</View>
</View>
))}
</View>
)}
<View className='footer-spacer' />
</View>
</ScrollView>
</View>
)
}