bk-shop/src/pages/item/espier-detail.js

881 lines
26 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import React, { useEffect, useRef, useMemo } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import Taro, {
getCurrentInstance,
useShareAppMessage,
useShareTimeline,
useReady
} from '@tarojs/taro'
import { View, Text, Swiper, SwiperItem, Video, Canvas, ScrollView } from '@tarojs/components'
import { useImmer } from 'use-immer'
import { AtCountdown, AtAccordion, AtIcon } from 'taro-ui'
import {
SpPrice,
SpCell,
SpImage,
SpLoading,
SpRecommend,
SpHtml,
SpPage,
SpSkuSelectNew,
SpPoster,
SpLogin,
SpFloatMenuItem,
SpChat,
SpGoodsPrice,
SpGoodsItem
} from '@/components'
import api from '@/api'
import req from '@/api/req'
import {
log,
calcTimer,
isArray,
canvasExp,
normalizeQuerys,
isAlipay,
isWeixin,
isWeb,
linkPage,
pickBy,
classNames,
navigateTo,
VERSION_PLATFORM,
isAPP
} from '@/utils'
import { fetchUserFavs } from '@/store/slices/user'
import doc from '@/doc'
import entryLaunch from '@/utils/entryLaunch'
import qs from 'qs'
import S from '@/spx'
import { Tracker } from '@/service'
import { useNavigation, useLogin } from '@/hooks'
import { ACTIVITY_LIST } from '@/consts'
import CompActivityBar from './comps/comp-activitybar'
import CompVipGuide from './comps/comp-vipguide'
import CompCouponList from './comps/comp-couponlist'
import CompStore from './comps/comp-store'
import CompPackageList from './comps/comp-packagelist'
import CompEvaluation from './comps/comp-evaluation'
import CompBuytoolbar from './comps/comp-buytoolbar'
import CompShare from './comps/comp-share'
import CompPromation from './comps/comp-promation'
import CompGroup from './comps/comp-group'
import { WgtFilm, WgtSlider, WgtWriting, WgtGoods, WgtHeading, WgtHeadline } from '../home/wgts'
import './espier-detail.scss'
const MSpSkuSelect = React.memo(SpSkuSelectNew)
const initialState = {
id: null,
type: null,
dtid: null,
info: null,
curImgIdx: 0,
play: false,
isDefault: false,
defaultMsg: '',
promotionPackage: [], // 组合优惠
mainGoods: {},
makeUpGoods: [], // 组合商品
packageOpen: false,
skuPanelOpen: false,
promotionOpen: false,
promotionActivity: [],
sharePanelOpen: false,
posterModalOpen: false,
skuText: '',
// sku选择器类型
selectType: 'picker',
evaluationList: [],
evaluationTotal: 0,
// 多规格商品选中的规格
curItem: null,
recommendList: [],
showSaleTotal: false,
showSku: true,
isOpen: false,
}
function EspierDetail (props) {
const $instance = getCurrentInstance()
// const { type, id, dtid } = $instance.router.params
// const { type, id, dtid } = await entryLaunch.getRouteParams()
const { getUserInfoAuth } = useLogin()
const pageRef = useRef()
const { userInfo } = useSelector((state) => state.user)
const { colorPrimary, openRecommend } = useSelector((state) => state.sys)
const { setNavigationBarTitle } = useNavigation()
const dispatch = useDispatch()
const skuSelectRef = useRef()
const [state, setState] = useImmer(initialState)
const {
info,
play,
isDefault,
defaultMsg,
evaluationList,
curImgIdx,
promotionPackage,
packageOpen,
skuPanelOpen,
promotionOpen,
promotionActivity,
sharePanelOpen,
posterModalOpen,
mainGoods,
makeUpGoods,
skuText,
selectType,
id,
type,
dtid,
curItem,
recommendList,
showSaleTotal,
showSku,
isOpen
} = state
useEffect(() => {
init()
}, [])
useEffect(() => {
const { path } = $instance.router
if (id && path === '/pages/item/espier-detail') {
fetch()
}
}, [userInfo])
useEffect(() => {
if (id) {
fetch()
getPackageList()
getEvaluationList()
}
}, [id])
useEffect(() => {
let video
if (isWeixin) {
video = Taro.createVideoContext('goods-video')
} else if (isWeb) {
video = document.getElementById('goods-video')
}
if (!video) {
return
}
if (play) {
setTimeout(() => {
console.log('video:', video)
video.play()
}, 200)
} else {
isWeixin ? video.stop() : video.pause()
}
}, [play])
useEffect(() => {
if (packageOpen || skuPanelOpen || sharePanelOpen || posterModalOpen || promotionOpen) {
pageRef.current.pageLock()
} else {
pageRef.current.pageUnLock()
}
}, [packageOpen, skuPanelOpen, sharePanelOpen, posterModalOpen, promotionOpen])
useShareAppMessage(async (res) => {
return getAppShareInfo()
})
useShareTimeline(async (res) => {
return getAppShareInfo()
})
const getAppShareInfo = () => {
const { itemName, imgs } = {} = info
const query = {
id,
dtid
}
if (userInfo) {
query['uid'] = userInfo.user_id
}
const path = `/pages/item/espier-detail?${qs.stringify(query)}`
log.debug(`share path----getAppShareInfo: ${path}`)
return {
title: itemName,
imageUrl: imgs.length > 0 ? imgs[0] : [],
path
}
}
const init = async () => {
const { type, id, dtid } = await entryLaunch.getRouteParams()
console.log("🚀 ~ type, id, dtid :", type, id, dtid)
setState((draft) => {
draft.id = id
draft.type = type
draft.dtid = dtid
})
if (S.getAuthToken()) {
await dispatch(fetchUserFavs())
}
}
const fetch = async () => {
let data
if (type == 'pointitem') {
} else {
try {
const itemDetail = await api.item.detail(id, {
showError: false,
distributor_id: dtid
})
data = pickBy(itemDetail, doc.goods.GOODS_INFO)
if (data.approveStatus == 'instock') {
setState((draft) => {
draft.isDefault = true
draft.defaultMsg = '商品已下架'
})
}
} catch (e) {
setState((draft) => {
draft.isDefault = true
draft.defaultMsg = e.res.data.data.message
})
console.log(e.res)
}
}
// 是否订阅
const { user_id: subscribe = false } = await api.user.isSubscribeGoods(id, { distributor_id: dtid })
setNavigationBarTitle(data?.itemName)
console.log(ACTIVITY_LIST[data.activityType])
if (ACTIVITY_LIST[data.activityType]) {
Taro.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: colorPrimary,
animation: {
duration: 400,
timingFunc: 'easeIn'
}
})
}
setState((draft) => {
draft.info = {
...data,
subscribe
}
draft.promotionActivity = data.promotionActivity
})
if (isAPP() && userInfo) {
try {
Taro.SAPPShare.init({
title: data?.itemName,
content: data.brief,
pic: `${data.img}?time=${new Date().getTime()}`,
link: `${process.env.APP_CUSTOM_SERVER}/pages/item/espier-detail?id=${data.itemId}&dtid=${data.distributorId}&company_id=${data.companyId}`,
path: `/pages/item/espier-detail?company_id=${data.company_id}&id=${data.v}&dtid=${data.distributor_id}&uid=${userInfo.user_id}`,
price: data.price,
weibo: false,
miniApp: true
})
log.debug('app share init success...')
} catch (e) {
console.error(e)
}
}
if (openRecommend == 1) {
getRecommendList() // 猜你喜欢
}
}
const getRecommendList = async () => {
const { list } = await api.cart.likeList({
page: 1,
pageSize: 30
})
setState((draft) => {
draft.recommendList = list
})
}
// 获取包裹
const getPackageList = async () => {
const { list } = await api.item.packageList({ item_id: id, showError: false })
setState((draft) => {
draft.promotionPackage = list
})
}
// 获取评论
const getEvaluationList = async () => {
const { list, total_count } = await api.item.evaluationList({
page: 1,
pageSize: 2,
item_id: id
})
setState((draft) => {
draft.evaluationList = list
draft.evaluationTotal = total_count
})
}
// 领券
const handleReceiveCoupon = () => {
const { itemId, distributorId } = info
Taro.navigateTo({
url: `/subpages/marketing/coupon-center?item_id=${itemId}&distributor_id=${distributorId}`
})
}
const onChangeSwiper = (e) => {
setState((draft) => {
draft.curImgIdx = e.detail.current
})
}
const onChangeToolBar = (key) => {
setState((draft) => {
draft.skuPanelOpen = true
draft.selectType = key
})
if (key === 'addcart') {
skuSelectRef.current?.addToCart?.()
} else if (key === 'fastbuy') {
skuSelectRef.current?.fastBuy?.()
}
}
const { windowWidth } = Taro.getSystemInfoSync()
let sessionFrom = {}
if (info) {
sessionFrom['商品'] = info?.itemName
if (userInfo) {
sessionFrom['昵称'] = userInfo.username
}
}
const handleClickStore = (item) => {
const url = `/subpages/store/index?id=${item.distributor_info?.distributor_id || item.goods_id}`
Taro.navigateTo({
url
})
}
return (
<SpPage
className='page-item-espierdetail'
scrollToTopBtn
isDefault={isDefault}
defaultMsg={defaultMsg}
ref={pageRef}
showNavHomeIcon
renderFloat={
false && <View>
<SpFloatMenuItem
onClick={() => {
Taro.navigateTo({ url: '/subpages/member/index' })
}}
>
<Text className='iconfont icon-huiyuanzhongxin'></Text>
</SpFloatMenuItem>
<SpChat sessionFrom={JSON.stringify(sessionFrom)}>
<SpFloatMenuItem>
<Text className='iconfont icon-headphones'></Text>
</SpFloatMenuItem>
</SpChat>
</View>
}
renderFooter={
<CompBuytoolbar
info={info}
onChange={onChangeToolBar}
onSubscribe={() => {
fetch()
}}
/>
}
>
{/* <Canvas id="canvas2" type="2d" onReady={onCanvasReady} /> */}
{!info && <SpLoading />}
{info && (
<ScrollView scrollY scrollWithAnimation showScrollbar={false} scrollTop={0} className='goods-contents' onScroll={(e) => {
// console.log('e', e.detail)
const { scrollTop } = e.detail
if (scrollTop >= 640) {
setState((draft) => {
draft.isShowScroll = true
})
} else {
setState((draft) => {
draft.isShowScroll = false
})
}
}}>
<View className='goods-pic-container'>
<Swiper
className='goods-swiper'
// current={curImgIdx}
onChange={onChangeSwiper}
>
{console.log('info', info)}
{info.imgs.map((img, idx) => (
<SwiperItem key={`swiperitem__${idx}`}>
<SpImage
mode='aspectFill'
src={img}
width={windowWidth * 2}
height={900}
></SpImage>
{false && (
<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={() => {
}}
/>
)}
</SwiperItem>
))}
</Swiper>
{info.imgs.length > 1 && (
<View className='swiper-pagegation'>{`${curImgIdx + 1}/${info.imgs.length}`}</View>
)}
{info.video && play && (
<View className='video-container'>
<Video
direction={90}
id='goods-video'
className='item-video'
src={info.video}
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%" }}
onClick={() => {
setState((draft) => {
draft.play = false
})
}}
/>
</View>
)}
{info.video && (
<View
className={classNames('btn-video', {
playing: play
})}
onClick={() => {
setState((draft) => {
play ? (draft.play = false) : (draft.play = true)
})
}}
>
{/* play2.png */}
{!play && <SpImage className='play-icon' src='cart/play.png' width={90} height={90} isNew />}
{/* {play ? '退出视频' : '播放视频'} */}
</View>
)}
</View>
{/* 拼团、秒杀、限时特惠显示活动价 */}
{ACTIVITY_LIST[info.activityType] && (
<CompActivityBar
info={{
...info.activityInfo,
priceObj: curItem ? curItem : info
}}
type={info.activityType}
onTimeUp={() => {
fetch()
}}
>
<SpGoodsPrice info={curItem ? curItem : info} />
</CompActivityBar>
)}
<View className='goods-info'>
<CompVipGuide
info={{
...info.vipgradeGuideTitle,
memberPrice: info.memberPrice
}}
/>
<CompCouponList
info={
info.couponList.list.length > 3
? info.couponList.list.slice(0, 3)
: info.couponList.list
}
onClick={handleReceiveCoupon}
/>
<View className='goods-name-wrap'>
<View className='goods-name'>
<View className='title'>{info?.itemName}</View>
{/* <View className='brief'>{info.brief}</View> */}
</View>
{/* {(isWeixin || isAPP()) && (
// {(
<View className='btn-share-wrap'>
<SpLogin
onChange={async () => {
if (isAPP()) {
Taro.SAPPShare.open()
} else {
await getUserInfoAuth()
setState((draft) => {
draft.sharePanelOpen = true
})
}
}}
>
<View className='btn-share'>
<Text className='iconfont icon-fenxiang-01'></Text>
<Text className='share-txt'>分享</Text>
</View>
</SpLogin>
</View>
)} */}
</View>
<View className='goods-info-title'>
{/* 拼团、秒杀、限时特惠不显示 */}
{!ACTIVITY_LIST[info.activityType] && (
<SpGoodsPrice info={curItem ? curItem : info} size="30" />
)}
</View>
{showSaleTotal && <View className='item-bn-sales'>
{/* <View className='item-bn'></View> */}
{info.salesSetting && <View className='item-sales'>{`销量:${info.sales || 0}`}</View>}
{info.store_setting && <View className='kc'>库存{info.store}</View>}
</View>}
</View>
<CompGroup info={info} />
{/* { !info.nospec && (
<View className='sku-block'>
<SpCell
title='规格'
isLink
onClick={() => {
setState((draft) => {
draft.skuPanelOpen = true
draft.selectType = 'picker'
})
}}
>
<Text className='cell-value'>{skuText}</Text>
</SpCell>
</View>
)} */}
{/* <View className='sku-block'>
{promotionPackage.length > 0 && (
<SpCell
title='组合优惠'
isLink
onClick={() => {
Taro.navigateTo({
url: `/subpages/marketing/package-list?id=${info.itemId}&distributor_id=${info.distributorId}`
})
// setState((draft) => {
// draft.packageOpen = true
// })
}}
>
<Text className='cell-value'>{`共${promotionPackage.length}种组合随意搭配`}</Text>
</SpCell>
)}
{promotionActivity.length > 0 && (
<SpCell
title='优惠活动'
isLink
onClick={() => {
setState((draft) => {
draft.promotionOpen = true
})
}}
>
{promotionActivity.map((item, index) => (
<View className='promotion-tag' key={`promotion-tag__${index}`}>
{item.promotionTag}
</View>
))}
</SpCell>
)}
</View> */}
{/* {info.itemParams.length > 0 && <View className='goods-params'>
<View className='params-hd'>商品参数</View>
<View className='params-bd'>
{info.itemParams.map((item, index) => (
<View className='params-item' key={`params-item__${index}`}>
<View className='params-label'>{`${item.attribute_name}`}</View>
<View className='params-value'>{item.attribute_value_name}</View>
</View>
))}
</View>
</View>} */}
{/* 商品评价 */}
{/* <CompEvaluation list={evaluationList} itemId={info.itemId}></CompEvaluation> */}
{/* 店铺 */}
{VERSION_PLATFORM && <CompStore info={info.distributorInfo} />}
{/* Sku选择器列表 */}
{/* Sku选择器 */}
<MSpSkuSelect
ref={skuSelectRef}
open={skuPanelOpen}
type={selectType}
info={info}
hideInputNumber
onClose={() => {
setState((draft) => {
draft.skuPanelOpen = false
})
}}
onChange={(skuText, curItem) => {
setState((draft) => {
draft.skuText = skuText
draft.curItem = curItem
})
}}
/>
<View className='goods-desc'>
<View className='desc-hd'>
<SpImage
className='sku-image'
src={skuSelectRef.current?.getImgs()}
width={160}
height={160}
mode='aspectFit'
/>
<View className='desc-title'>
<Text className='desc-title-txt'>{info?.itemName}</Text>
<SpGoodsPrice info={curItem ? curItem : info} />
</View>
</View>
{isArray(info.intro) ? (
<View>
{info.intro.map((item, idx) => (
<View className='wgt-wrap' key={`wgt-wrap__${idx}`}>
{item.name === 'film' && <WgtFilm info={item} />}
{item.name === 'slider' && <WgtSlider info={item} />}
{item.name === 'writing' && <WgtWriting info={item} />}
{/* {item.name === 'heading' && <WgtHeading info={item} />} */}
{item.name === 'headline' && <WgtHeadline info={item} />}
{item.name === 'goods' && <WgtGoods info={item} />}
</View>
))}
</View>
) : (
<>
{/* <SpHtml content={info.intro} /> */}
</>
)}
{[{ open: false }, { open: false }, {}, {}, {}, {}, {}, {}].map((item, index) => <View className={classNames('sp-accordion')} key={`item__${index}`}>
<AtAccordion
open={isOpen}
isAnimation={false}
onClick={() => {
setState((draft) => {
draft.isOpen = !draft.isOpen
})
}}
title={'标题' + (index + 1)}
>
<View>内容一</View>
<View>内容二</View>
<View>内容三</View>
<View>内容三</View>
<View>内容三</View>
<View>内容三</View>
{/* <SpHtml content={info.intro} /> */}
</AtAccordion>
<View onClick={() => {
setState((draft) => {
draft.isOpen = !draft.isOpen
})
}}>
{isOpen ? <AtIcon value='subtract' size='16' color='#000' /> :
<AtIcon value='add' size='16' color='#000' />}
{isOpen ? <></> : <View className="line"></View>}
</View>
</View>)}
<View className='bottom-box'>
<View className="bottom-box-tit">浏览历史</View>
<ScrollView scrollX scrollWithAnimation showScrollbar={true} scrollLeft={0} className="shop-box">
{[
{
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'
},
].map((item, idx) => (
<View className='goods-item-wrap' key={`goods-item-l__${idx}`}>
<SpGoodsItem
showSalePrice={false}
height={250}
width={250}
onStoreClick={handleClickStore}
info={{
...item
}}
/>
</View>
))}
</ScrollView>
</View>
</View>
</ScrollView>
)}
<SpRecommend info={recommendList} />
{/* 组合优惠 */}
<CompPackageList
open={packageOpen}
onClose={() => {
setState((draft) => {
draft.packageOpen = false
})
}}
info={{
mainGoods,
makeUpGoods
}}
/>
{/* 促销优惠活动 */}
<CompPromation
open={promotionOpen}
info={promotionActivity}
onClose={() => {
setState((draft) => {
draft.promotionOpen = false
})
}}
/>
{/* Sku选择器 */}
{/* <MSpSkuSelect
open={skuPanelOpen}
type={selectType}
info={info}
onClose={() => {
setState((draft) => {
draft.skuPanelOpen = false
})
}}
onChange={(skuText, curItem) => {
setState((draft) => {
draft.skuText = skuText
draft.curItem = curItem
})
}}
/> */}
{/* 分享 */}
<CompShare
open={sharePanelOpen}
onClose={() => {
setState((draft) => {
draft.sharePanelOpen = false
})
}}
onCreatePoster={() => {
setState((draft) => {
draft.sharePanelOpen = false
draft.posterModalOpen = true
})
}}
onShareEdit={() => {
const { itemId, companyId, distributorId } = info
Taro.navigateTo({
url: `/subpage/pages/editShare/index?id=${itemId}&dtid=${distributorId}&company_id=${companyId}`
})
}}
/>
{/* 海报 */}
{posterModalOpen && (
<SpPoster
info={info}
type='goodsDetial'
onClose={() => {
setState((draft) => {
draft.posterModalOpen = false
})
}}
/>
)}
</SpPage>
)
}
export default EspierDetail