- 新增配送员首页界面,包含订单管理、工资明细、配送小区、仓库地址等功能入口 - 实现小程序码保存到相册功能,支持权限检查和错误处理 - 添加相册写入权限配置和图片下载临时路径处理 - 修复订单列表商品信息显示问题,优化支付流程 - 更新首页轮播图广告代码,调整用户中心网格布局 - 增加订单页面返回时的数据刷新机制,提升用户体验
167 lines
4.9 KiB
TypeScript
167 lines
4.9 KiB
TypeScript
import {useEffect, useState} from 'react'
|
||
import {View} from '@tarojs/components'
|
||
import {Swiper} from '@nutui/nutui-react-taro'
|
||
import {CmsAd} from "@/api/cms/cmsAd/model";
|
||
import {Image} from '@nutui/nutui-react-taro'
|
||
import {getCmsAdByCode} from "@/api/cms/cmsAd";
|
||
import navTo from "@/utils/common";
|
||
import {pageCmsArticle} from "@/api/cms/cmsArticle";
|
||
|
||
type AdImage = {
|
||
url?: string
|
||
path?: string
|
||
title?: string
|
||
// Compatible keys (some backends use different fields)
|
||
src?: string
|
||
imageUrl?: string
|
||
}
|
||
|
||
function normalizeAdImages(ad?: CmsAd): AdImage[] {
|
||
const list = ad?.imageList
|
||
if (Array.isArray(list) && list.length) return list as AdImage[]
|
||
|
||
// Some APIs only return `images` as a JSON string.
|
||
const raw = ad?.images
|
||
if (!raw) return []
|
||
try {
|
||
const parsed = JSON.parse(raw)
|
||
return Array.isArray(parsed) ? (parsed as AdImage[]) : []
|
||
} catch {
|
||
return []
|
||
}
|
||
}
|
||
|
||
function toNumberPx(input: unknown, fallback: number) {
|
||
const n = typeof input === 'number' ? input : Number.parseInt(String(input ?? ''), 10)
|
||
return Number.isFinite(n) ? n : fallback
|
||
}
|
||
|
||
const MyPage = () => {
|
||
const [carouselData, setCarouselData] = useState<CmsAd>()
|
||
const [loading, setLoading] = useState(true)
|
||
// const [disableSwiper, setDisableSwiper] = useState(false)
|
||
|
||
// 用于记录触摸开始位置
|
||
// const touchStartRef = useRef({x: 0, y: 0})
|
||
|
||
// 加载数据
|
||
const loadData = async () => {
|
||
setLoading(true)
|
||
try {
|
||
const [flashRes] = await Promise.allSettled([
|
||
getCmsAdByCode('mp-ad'),
|
||
getCmsAdByCode('hot_today'),
|
||
pageCmsArticle({ limit: 1, recommend: 1 }),
|
||
])
|
||
|
||
if (flashRes.status === 'fulfilled') {
|
||
console.log('flashflashflash', flashRes.value)
|
||
setCarouselData(flashRes.value)
|
||
} else {
|
||
console.error('Failed to fetch flash:', flashRes.reason)
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('Banner数据加载失败:', error)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
useEffect(() => {
|
||
loadData().then()
|
||
}, [])
|
||
|
||
// 轮播图高度,默认300px
|
||
const carouselHeight = toNumberPx(carouselData?.height, 300)
|
||
const carouselImages = normalizeAdImages(carouselData)
|
||
console.log(carouselImages,'carouselImages')
|
||
|
||
// 骨架屏组件
|
||
const BannerSkeleton = () => (
|
||
<View className="flex p-2 justify-between" style={{height: `${carouselHeight}px`}}>
|
||
{/* 左侧轮播图骨架屏 */}
|
||
<View style={{width: '50%', height: '100%'}}>
|
||
<View
|
||
className="bg-gray-200 rounded animate-pulse"
|
||
style={{height: `${carouselHeight}px`}}
|
||
/>
|
||
</View>
|
||
|
||
{/* 右侧骨架屏 */}
|
||
<View className="flex flex-col" style={{width: '50%', height: '100%'}}>
|
||
{/* 上层骨架屏 */}
|
||
<View className="ml-2 bg-white rounded-lg">
|
||
<View className="px-3 my-2">
|
||
<View className="bg-gray-200 h-4 w-16 rounded animate-pulse"/>
|
||
</View>
|
||
<View className="px-3 flex" style={{height: '110px'}}>
|
||
{[1, 2].map(i => (
|
||
<View key={i} className="item flex flex-col mr-4">
|
||
<View className="bg-gray-200 rounded animate-pulse" style={{width: 70, height: 70}}/>
|
||
<View className="bg-gray-200 h-3 w-16 rounded mt-2 animate-pulse"/>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
{/* 下层骨架屏 */}
|
||
<View className="ml-2 bg-white rounded-lg mt-3">
|
||
<View className="px-3 my-2">
|
||
<View className="bg-gray-200 h-4 w-20 rounded animate-pulse"/>
|
||
</View>
|
||
<View className="rounded-lg px-3 pb-3">
|
||
<View className="bg-gray-200 rounded animate-pulse" style={{width: '100%', height: 106}}/>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
)
|
||
|
||
// 如果正在加载,显示骨架屏
|
||
if (loading) {
|
||
return <BannerSkeleton />
|
||
}
|
||
|
||
return (
|
||
<Swiper
|
||
defaultValue={0}
|
||
height={carouselHeight}
|
||
indicator
|
||
autoPlay
|
||
duration={3000}
|
||
style={{
|
||
height: `${carouselHeight}px`,
|
||
touchAction: 'pan-y' // 关键修改:允许垂直滑动
|
||
}}
|
||
disableTouch={false}
|
||
direction="horizontal"
|
||
className="custom-swiper"
|
||
>
|
||
{carouselImages.map((img, index) => {
|
||
const src = img.url || img.src || img.imageUrl
|
||
if (!src) return null
|
||
return (
|
||
<Swiper.Item key={index} style={{ touchAction: 'pan-x pan-y' }}>
|
||
<Image
|
||
width="100%"
|
||
height="100%"
|
||
src={src}
|
||
mode={'scaleToFill'}
|
||
onClick={() => (img.path ? navTo(`${img.path}`) : undefined)}
|
||
lazyLoad={false}
|
||
style={{
|
||
height: `${carouselHeight}px`,
|
||
borderRadius: '4px',
|
||
touchAction: 'manipulation' // 关键修改:优化触摸操作
|
||
}}
|
||
/>
|
||
</Swiper.Item>
|
||
)
|
||
})}
|
||
</Swiper>
|
||
)
|
||
}
|
||
|
||
export default MyPage
|