bk-shop/src/pages/index.js

603 lines
20 KiB
JavaScript
Executable File

import React, { useEffect, useState, useCallback } from 'react'
import Taro, {
getCurrentInstance,
useShareAppMessage,
useShareTimeline,
useDidShow,
usePageScroll,
usePullDownRefresh
} from '@tarojs/taro'
import { View, Image, Swiper, SwiperItem, Video, ScrollView } from '@tarojs/components'
import { useSelector, useDispatch } from 'react-redux'
import {
SpScreenAd,
SpPage,
SpSearch,
SpRecommend,
SpTabbar,
SpCouponPackage,
SpNavBar,
SpImage,
SpGoodsItem,
SpChat
} from '@/components'
import api from '@/api'
import {
isWeixin,
isAPP,
isEmpty,
getDistributorId,
VERSION_STANDARD,
VERSION_PLATFORM,
VERSION_IN_PURCHASE,
VERSION_B2C,
classNames,
getCurrentPageRouteParams,
resolveStringifyParams
} from '@/utils'
import entryLaunch from '@/utils/entryLaunch'
import { updateLocation } from '@/store/slices/user'
import { updateShopInfo } from '@/store/slices/shop'
import { useImmer } from 'use-immer'
import { useLogin, useNavigation } from '@/hooks'
import HomeWgts from './home/comps/home-wgts'
import { WgtHomeHeader, WgtHomeHeaderShop } from './home/wgts'
import CompAddTip from './home/comps/comp-addtip'
import CompFloatMenu from './home/comps/comp-floatmenu'
import './home/index.scss'
const MCompAddTip = React.memo(CompAddTip)
const initialState = {
wgts: [],
showBackToTop: false,
loading: true,
searchComp: null,
pageData: null,
fixedTop: false,
filterWgts: [],
isShowHomeHeader: false,
swiperList: [],
list: [
{
type: 'image',
src: process.env.APP_IMAGE_CDN_NEW + '/index/22.jpg'
},
{
type: 'image',
// src: '//img10.360buyimg.com/ling/jfs/t1/181258/24/10385/53029/60d04978Ef21f2d42/92baeb21f907cd24.jpg'
src: process.env.APP_IMAGE_CDN_NEW + '/index/33.jpg'
},
{
type: 'video',
src: 'https://espier-oss-cdn.oss-cn-shanghai.aliyuncs.com/default_project/wxAssets/index/video-1.mp4'
}
],
length: 2,
showBottom: false,
scrollTop: 0,
isUpOperation: false,
showRecommend: false,
currentIndex: 0,
shopList: [
{
brief: "副标题",
itemName: "测试商品1",
price: "1099",
goods_id: 6,
pic: 'https://espier-oss-cdn.oss-cn-shanghai.aliyuncs.com/default_project/image/1/2024/01/15/46fe6ca52277038e39ee2c026a4af3c9xHQuJ96YIcZWtjRS0HBCTzp7dzXIs2pl'
},
{
brief: "副标题",
itemName: "测试商品2",
price: "1099",
goods_id: 6,
pic: 'https://espier-oss-cdn.oss-cn-shanghai.aliyuncs.com/default_project/image/1/2024/01/15/801c18d59d95ea26930fefc43bf66febTQjxb65cpnCqVLaOsYmiHdkDdYqBnXVm'
},
{
brief: "副标题",
itemName: "测试商品3",
price: "1099",
goods_id: 6,
pic: 'https://espier-oss-cdn.oss-cn-shanghai.aliyuncs.com/default_project/image/1/2024/01/15/46fe6ca52277038e39ee2c026a4af3c90XruENsSSAhRiz0HPI3PjR8XQNVgbxHb'
},
],
goodList: [],
recommend: []
}
function Home () {
const [state, setState] = useImmer(initialState)
const [startY, setStartY] = useState(0)
const [startX, setStartX] = useState(0)
const [likeList, setLikeList] = useImmer([])
const { initState, openRecommend, openLocation, openStore, appName, openScanQrcode } = useSelector(
(state) => state.sys
)
const { shopInfo } = useSelector(
(state) => state.shop
)
const showAdv = useSelector((member) => member.user.showAdv)
const { location } = useSelector((state) => state.user)
const { setNavigationBarTitle } = useNavigation()
const { windowWidth } = Taro.getSystemInfoSync()
const imgW = parseFloat(((windowWidth * 2 - 60 - 32) / 3).toFixed(4))
const { wgts, loading, searchComp, pageData, fixedTop, filterWgts, isShowHomeHeader, isUpOperation, showRecommend, shopList, swiperList, goodList, recommend } = state
const dispatch = useDispatch()
useEffect(() => {
if (initState) {
init()
setNavigationBarTitle(appName)
getSwiperList()
getRecommendItems()
}
}, [initState])
useEffect(() => {
if (shopInfo && VERSION_STANDARD) {
fetchWgts()
}
}, [shopInfo])
useEffect(() => {
if (location && VERSION_STANDARD) {
fetchWgts()
}
}, [location])
useShareAppMessage(async (res) => {
const { title, imageUrl } = await api.wx.shareSetting({ shareindex: 'index' })
let params = getCurrentPageRouteParams()
const dtid = getDistributorId()
if (dtid && !('dtid' in params)) {
params = Object.assign(params, { dtid })
}
let path = `/pages/index${isEmpty(params) ? '' : '?' + resolveStringifyParams(params)}`
console.log('useShareAppMessage path:', path, params)
return {
title: title,
imageUrl: imageUrl,
path
}
})
useShareTimeline(async (res) => {
const { title, imageUrl } = await api.wx.shareSetting({ shareindex: 'index' })
let params = getCurrentPageRouteParams()
const dtid = getDistributorId()
if (dtid && !('dtid' in params)) {
params = Object.assign(params, { dtid })
}
return {
title: title,
imageUrl: imageUrl,
query: resolveStringifyParams(params)
}
})
const init = async () => {
fetchLocation()
// 非云店
if (!VERSION_STANDARD) {
fetchWgts()
} else {
fetchStoreInfo(location)
}
}
const getRecommendItems = async () => {
const req = {
page: 1,
pageSize: 10,
approve_status: 'onsale',
approve_status: 'onsale,only_show',
item_type: 'normal',
is_point: false,
// goodsSort: 6,
distributor_id: 0
}
const { list: jdList } = await api.item.search({ ...req, tag_id: 1 })
const { list: newList } = await api.item.search({ ...req, tag_id: 2 })
const { list: hotList } = await api.item.search({ ...req, tag_id: 3 })
setState((draft) => {
draft.recommend = [{
type: 'new',
text: "新品推荐",
btnTxt: '查看更多',
postions: 'left',
url: '',
img: 'index/rec/new.png',
list: newList.map(item => ({ ...item, price: (item.price / 100) }))
}, {
type: 'hot',
text: "热销单品",
btnTxt: '查看更多',
postions: 'left',
url: '',
img: 'index/rec/hot.png',
list: hotList.map(item => ({ ...item, price: (item.price / 100) }))
}, {
type: 'jd',
text: "ARIZONA",
btnTxt: '经典双扣',
postions: 'right',
url: '',
img: 'index/rec/jd.png',
list: jdList.map(item => ({ ...item, price: (item.price / 100) }))
}
]
})
}
const getSwiperList = async () => {
const res = await api.shop.homeSwiperList({ page: 1, pageSize: 999 })
const list = res?.list?.map((item) => {
return {
type: item.type || 'image',
src: item.pic,
goods: (item.goods_info_detail || []).map((ite) => {
return {
itemName: ite.item_name,
goods_id: ite.item_id,
itemId: ite.item_id,
pic: ite.pics?.[0],
brief: ite.brief,
price: ite.price ? ite.price / 100 : 0,
spec_images: ite.spec_images || [],
tagList: ite.tagList || []
}
})
}
}) || []
setState((draft) => {
draft.swiperList = list
draft.goodList = list[0].goods || []
})
}
const fetchWgts = async () => {
setState((draft) => {
draft.wgts = []
draft.pageData = []
draft.filterWgts = []
draft.loading = true
})
const { config } = await api.shop.getShopTemplate({
distributor_id: getDistributorId()
})
const searchComp = config.find((wgt) => wgt.name == 'search')
const pageData = config.find((wgt) => wgt.name == 'page')
let filterWgts = []
if (searchComp && searchComp.config.fixTop) {
filterWgts = config.filter((wgt) => wgt.name !== 'search' && wgt.name != 'page')
} else {
filterWgts = config.filter((wgt) => wgt.name != 'page')
}
const fixedTop = searchComp && searchComp.config.fixTop
const isShowHomeHeader =
VERSION_PLATFORM ||
(openScanQrcode == 1 && isWeixin) ||
(VERSION_STANDARD && openStore && openLocation == 1) ||
fixedTop
setState((draft) => {
draft.wgts = config
draft.searchComp = searchComp
draft.pageData = pageData
draft.fixedTop = fixedTop
draft.isShowHomeHeader = isShowHomeHeader
draft.filterWgts = filterWgts
draft.loading = false
})
}
const fetchLikeList = async () => {
if (openRecommend == 1) {
const query = {
page: 1,
pageSize: 30
}
const { list } = await api.cart.likeList(query)
setLikeList(list)
}
}
// 定位
const fetchLocation = () => {
if (!location && ((VERSION_STANDARD && openLocation == 1) || VERSION_PLATFORM)) {
try {
entryLaunch.isOpenPosition((res) => {
if (res.lat) {
dispatch(updateLocation(res))
}
})
} catch (e) {
console.error('map location fail:', e)
}
}
}
const fetchStoreInfo = async (location) => {
let params = {
distributor_id: getDistributorId() // 如果店铺id和经纬度都传会根据哪个去定位传参
}
if (openLocation == 1 && location) {
const { lat, lng } = location
params.lat = lat
params.lng = lng
// params.distributor_id = undefined
}
const res = await api.shop.getShop(params)
console.log('fetchStoreInfo:', res)
dispatch(updateShopInfo(res))
}
const handleTouchStart = (e) => {
const { clientY, clientX } = e.touches[0]
setStartY(clientY)
setStartX(clientX)
}
const handleTouchEnd = (e) => {
const { clientX, clientY } = e.changedTouches[0]
const deltaY = clientY - startY
const deltaX = clientX - startX
if (Math.abs(deltaY) < 50) return
if (deltaY > 0) {
// 下滑操作
setState((draft) => {
draft.showBottom = false
draft.showRecommend = false
})
if (state.showBottom) {
setTimeout(() => {
setState((draft) => {
draft.isUpOperation = false
})
}, 500)
}
} else if (deltaY < 0) {
// 上滑操作
setState((draft) => {
draft.showBottom = true
draft.isUpOperation = true
})
setTimeout(() => {
setState((draft) => {
draft.showRecommend = true
})
}, 500)
if (!state.showBottom) {
}
}
}
const onSwiperChange = (e) => {
const { current } = e.detail
setState((draft) => {
draft.currentIndex = current
draft.goodList = swiperList[current].goods || []
})
}
const handleClickStore = (item) => {
const url = `/subpages/store/index?id=${item.distributor_info?.distributor_id || item.goods_id}`
Taro.navigateTo({
url
})
}
return (
<SpPage
className='page-index'
scrollToTopBtn
// renderNavigation={<SpNavBar />}
// pageConfig={pageData?.base}
// renderFloat={wgts.length > 0 && <CompFloatMenu />}
renderFooter={<SpTabbar />}
loading={loading}
isTop={!isUpOperation}
isBlack
>
<View
className={classNames('home-body', {
'has-home-header': isShowHomeHeader && isWeixin
})}
>
{isShowHomeHeader && <WgtHomeHeader>{fixedTop && <SpSearch info={searchComp} />}</WgtHomeHeader>}
{
filterWgts.length > 0 && <HomeWgts wgts={filterWgts} onLoad={fetchLikeList}>
{/* 猜你喜欢 */}
<SpRecommend className='recommend-block' info={likeList} />
</HomeWgts>
}
</View>
{/* 小程序搜藏提示 */}
{isWeixin && <MCompAddTip />}
{/* 开屏广告 */}
{isWeixin && !showAdv && <SpScreenAd />}
{/* 优惠券包 */}
{VERSION_STANDARD && <SpCouponPackage />}
<View className="content-box">
<View className="swiper-wapper" onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd}>
{/* <ScrollView
className='swiper-wapper'
scrollY
scrollWithAnimation
scrollTop={0}
// style={{ height: "calc(100vh - 140px)" }}
lowerThreshold={0}
upperThreshold={20}
// onScrollToUpper={this.onScrollToUpper.bind(this)} // 使用箭头函数的时候 可以这样写 `onScrollToUpper={this.onScrollToUpper}`
onScroll={onScroll}
onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd}
showScrollbar={false}
> */}
<Swiper
className={classNames('swiper', {
"swiper-narrow": state.showBottom
})}
indicatorColor="#999"
indicatorActiveColor="#333"
current={state.currentIndex}
interval={5000}
duration={800}
// indicatorDots
circular
autoplay={!isUpOperation}
onChange={onSwiperChange}
>
{state.swiperList.map((item, index) => (
<SwiperItem key={index} className="" style={{ height: "100%" }}>
{item.type === "image" && (
<Image
src={item.src}
style={{ width: "100%", height: "100%", objectPosition: "center" }}
mode={isUpOperation ? 'aspectFill' : 'aspectFill'}
showMenuByLongpress={false}
/>
// <SpImage style={{ width: "100%", height: "100%" }} height="100%" src={item.src} isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
)}
{item.type === "video" && (
<Video
id="video"
src={item.src}
poster={item.poster}
initialTime={0}
controls={false}
autoplay={true}
loop={true}
muted={true}
showProgress={false}
showFullscreenBtn={false}
showPlayBtn={false}
showCenterPlayBtn={false}
enableProgressGesture={false}
objectFit="cover"
style={{ width: "100%", height: "100%" }}
onPlay={() => {
}}
onEnded={() => {
}}
/>
)}
{/* {isUpOperation && <View className="item-btns">
<View className="item-tit">BOSTON</View>
<View className="item-btn">
<View className="item-btn-txt">立即预约</View>
<View className="item-btn-icon icon-my icon-arrow-right"></View>
</View>
</View>} */}
</SwiperItem>
))}
</Swiper>
{!isUpOperation && <View className="item-img-box">
<View className="item-img-txt"> </View>
<Image className="item-img" height="62" src={require('../assets/i-sou.gif')} isShowMenuByLongpress={false} lazyLoad isNew={false} />
</View>}
{!isUpOperation && <View className='spot-pagination'>
{swiperList.map((_, index) => (
<View key={index} className={'spot-pagination-bullet ' + ((state.currentIndex == index) ? 'spot-pagination-bullet-active' : "")} style={{ width: 1 / state.length * 100 + '%' }}></View>
))}
</View>}
{isUpOperation && <View className="icon-kf">
<SpChat><SpImage height="62" src='index/kf.png' isShowMenuByLongpress={false} lazyLoad isNew /></SpChat>
</View>}
</View>
{isUpOperation && <ScrollView scrollX scrollWithAnimation showScrollbar={true} scrollLeft={0} className="shop-box fadeIn" >
{goodList.map((item, idx) => (
<View className='goods-item-wrap fadeIn' animation={{ duration: 500, timingFunction: 'ease-in-out', delay: 0 }} key={`goods-item-l__${idx + item.goods_id}`}>
<SpGoodsItem
onStoreClick={handleClickStore}
info={{
...item
}}
/>
</View>
))}
</ScrollView>}
{/* 推荐图片+商品 */}
{isUpOperation && <>
{recommend.length > 0 && recommend.map((_item, id) => <View key={id + '__item'}>
<SpImage width={windowWidth * 2} height={windowWidth >= 400 ? 920 : 800} mode='scaleToFill' src={_item.img} isShowMenuByLongpress={false} lazyLoad isNew >
{/* <View className="recommend_btn" style={{ [_item.postions]: '70rpx' }}>
<View className="recommend_btn-title">{_item.text}</View>
<View className="recommend_btn-btn">{_item.btnTxt}</View>
</View> */}
</SpImage>
<ScrollView scrollX scrollWithAnimation showScrollbar={true} scrollLeft={0} className="shop-box fadeIn" >
{_item.list?.map((item, idx) => (
<View className='goods-item-wrap fadeIn' animation={{ duration: 500, timingFunction: 'ease-in-out', delay: 0 }} key={`goods-item-l__${idx + item.goods_id}`}>
<SpGoodsItem
onStoreClick={handleClickStore}
info={{
...item
}}
/>
</View>
))}
</ScrollView>
</View>)}
</>}
{isUpOperation && showRecommend && <View className="brand" style={{ padding: '0 15px 15px', height: '250px' }}>
<SpImage width={windowWidth * 2 - 60} mode='widthFix' src="index/story/story.png" onClick={() => Taro.navigateTo({
url: '/pages/home/story'
})} isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
{/* <SpImage width={windowWidth * 2 - 60} mode='widthFix' src="index/story/more.png" isShowMenuByLongpress={false} lazyLoad isNew></SpImage> */}
{/* <View style={{ marginTop: '30px' }}>
<SpImage onClick={() => Taro.navigateTo({
url: '/pages/webview?url=' + encodeURIComponent('https://www.baidu.com')
})} width={windowWidth * 2 - 60} mode='widthFix' src="index/story/more.png" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
</View> */}
</View>}
{false && isUpOperation && showRecommend && <View className="brand" style={{ padding: '15px', height: '550px' }}>
<View className="brand-title">品牌介绍</View>
<ScrollView scrollX scrollWithAnimation showScrollbar={false} scrollLeft={0} className="brand-img" style={{ height: '220px' }}>
<View className="brand-img-left brand-img-item" style={{ marginRight: '8px' }}>
<SpImage className="brand-img-top" width={imgW} height={294} mode='aspectFill' src="index/img/1774-1902.jpg" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
<SpImage width={imgW} height={130} mode='aspectFill' src="index/img/1913.jpg" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
</View>
<View className="brand-img-center brand-img-item" style={{ marginRight: '8px' }}>
<SpImage height={440} width={imgW} mode='aspectFill' src="index/img/1968.jpg" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
</View>
<View className="brand-img-right brand-img-item" style={{ marginRight: '0px' }}>
<SpImage className="brand-img-top" width={imgW} height={324} mode='aspectFill' src="index/img/70.jpg" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
<SpImage width={imgW} height={100} mode='aspectFill' src="index/img/1980.jpg" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
</View>
</ScrollView>
<SpImage onClick={() => Taro.navigateTo({
url: '/pages/webview?url=' + encodeURIComponent('https://www.baidu.com')
})} className="brand-guanzhu" mode="widthFix" src="index/guanzhu.png" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
<View className="brand-dy">
<View className="brand-dy-tit">订阅消息</View>
<SpImage width={30} mode="widthFix" src="index/xiaoxi.png" isShowMenuByLongpress={false} lazyLoad isNew></SpImage>
</View>
{/* <SpImage className="brand-logo" width={168} mode="widthFix" src="index/logo.png" isShowMenuByLongpress={false} lazyLoad isNew></SpImage> */}
</View>}
{/* </ScrollView> */}
</View>
</SpPage>
)
}
export default Home