feat(ID1000926):新增测评视频

This commit is contained in:
Haiyi 2023-03-09 20:11:35 +08:00
parent fdbe02791a
commit 254f060671
10 changed files with 513 additions and 107 deletions

View File

@ -1,56 +1,56 @@
{ {
"miniprogramRoot": "dist/", "miniprogramRoot": "dist/",
"projectname": "EShop", "projectname": "EShop",
"description": "项目配置文件详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", "description": "项目配置文件详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"appid": "wx714eaf2dfdb9c6bb", "appid": "wx714eaf2dfdb9c6bb",
"setting": { "setting": {
"urlCheck": false, "urlCheck": false,
"es6": false, "es6": false,
"enhance": true, "enhance": true,
"postcss": false, "postcss": false,
"preloadBackgroundData": false, "preloadBackgroundData": false,
"minified": false, "minified": false,
"newFeature": false, "newFeature": false,
"coverView": true, "coverView": true,
"nodeModules": false, "nodeModules": false,
"autoAudits": false, "autoAudits": false,
"showShadowRootInWxmlPanel": true, "showShadowRootInWxmlPanel": true,
"scopeDataCheck": false, "scopeDataCheck": false,
"uglifyFileName": false, "uglifyFileName": false,
"checkInvalidKey": true, "checkInvalidKey": true,
"checkSiteMap": true, "checkSiteMap": true,
"uploadWithSourceMap": true, "uploadWithSourceMap": true,
"compileHotReLoad": true, "compileHotReLoad": true,
"lazyloadPlaceholderEnable": false, "lazyloadPlaceholderEnable": false,
"useMultiFrameRuntime": true, "useMultiFrameRuntime": true,
"useApiHook": true, "useApiHook": true,
"useApiHostProcess": true, "useApiHostProcess": true,
"babelSetting": { "babelSetting": {
"ignore": [], "ignore": [],
"disablePlugins": [], "disablePlugins": [],
"outputPath": "" "outputPath": ""
},
"useIsolateContext": true,
"userConfirmedBundleSwitch": false,
"packNpmManually": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"disableUseStrict": false,
"minifyWXML": true,
"showES6CompileOption": false,
"useCompilerPlugins": false,
"ignoreUploadUnusedFiles": true
}, },
"compileType": "miniprogram", "useIsolateContext": true,
"libVersion": "2.30.1", "userConfirmedBundleSwitch": false,
"srcMiniprogramRoot": "dist/", "packNpmManually": false,
"packOptions": { "packNpmRelationList": [],
"ignore": [], "minifyWXSS": true,
"include": [] "disableUseStrict": false,
}, "minifyWXML": true,
"editorSetting": { "showES6CompileOption": false,
"tabIndent": "insertSpaces", "useCompilerPlugins": false,
"tabSize": 2 "ignoreUploadUnusedFiles": true
}, },
"condition": {} "compileType": "miniprogram",
"libVersion": "2.30.1",
"srcMiniprogramRoot": "dist/",
"packOptions": {
"ignore": [],
"include": []
},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
},
"condition": {}
} }

View File

@ -1,52 +1,43 @@
{ {
"projectname": "EShop", "projectname": "EShop",
"setting": { "setting": {
"compileHotReLoad": true, "compileHotReLoad": true,
"bigPackageSizeSupport": true, "bigPackageSizeSupport": true,
"urlCheck": false "urlCheck": false
}, },
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"condition": { "condition": {
"plugin": { "miniprogram": {
"list": [] "list": [
{
"name": "收藏夹",
"pathName": "pages/collection/collectionDetail/index",
"query": "",
"launchMode": "default",
"scene": null
}, },
"game": { {
"list": [] "name": "",
"pathName": "pages/sampleComparison/index",
"query": "",
"launchMode": "default",
"scene": null
}, },
"gamePlugin": { {
"list": [] "name": "",
"pathName": "pages/searchList/hightSearchList",
"query": "",
"launchMode": "default",
"scene": null
}, },
"miniprogram": { {
"list": [ "name": "",
{ "pathName": "pages/cutSampleList/index",
"name": "收藏夹", "query": "",
"pathName": "pages/collection/collectionDetail/index", "launchMode": "default",
"query": "", "scene": null
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/sampleComparison/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/searchList/hightSearchList",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "",
"pathName": "pages/cutSampleList/index",
"query": "",
"scene": null,
"launchMode": "default"
}
]
} }
]
} }
} }
}

View File

@ -83,3 +83,25 @@ export const mallsearchHistorydelete = () => {
method: 'delete', method: 'delete',
}) })
} }
/**
*
* @returns
*/
export const MallCherryestimate_catevideolist = () => {
return useRequest({
url: '/v3/mallCherry/estimate_cate/video/list',
method: 'get',
})
}
/**
*
* @returns
*/
export const MallCherryestimate_catevideoview = () => {
return useRequest({
url: '/v3/mallCherry/estimate_cate/video/view',
method: 'get',
})
}

View File

@ -1,11 +1,11 @@
// export const BASE_URL = CURRENT_BASE_URL export const BASE_URL = CURRENT_BASE_URL
// export const BASE_URL = `http://192.168.0.75:50001/lymarket` // export const BASE_URL = `http://192.168.0.75:50001/lymarket`
// export const BASE_URL = `http://192.168.0.89:50001/lymarket` // export const BASE_URL = `http://192.168.0.89:50001/lymarket`
// export const BASE_URL = `http://10.0.0.5:50001/lymarket` // export const BASE_URL = `http://10.0.0.5:50001/lymarket`
// export const BASE_URL = `http://192.168.0.89:40001/lymarket` // export const BASE_URL = `http://192.168.0.89:40001/lymarket`
// export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞 // export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞
// export const BASE_URL = 'https://test.zzfzyc.com/lymarket' // 测试环境 // export const BASE_URL = 'https://test.zzfzyc.com/lymarket' // 测试环境
export const BASE_URL = 'https://pre.zzfzyc.com/lymarket' // 预发布 // export const BASE_URL = 'https://pre.zzfzyc.com/lymarket' // 预发布
// export const BASE_URL = `http://192.168.1.9:40001/lymarket` // 发 // export const BASE_URL = `http://192.168.1.9:40001/lymarket` // 发
// export const BASE_URL = `http://192.168.1.9:50005/lymarket` // 发 // export const BASE_URL = `http://192.168.1.9:50005/lymarket` // 发
// export const BASE_URL = `http://192.168.1.30:50001/lymarket` // 发 // export const BASE_URL = `http://192.168.1.30:50001/lymarket` // 发
@ -13,7 +13,7 @@ export const BASE_URL = 'https://pre.zzfzyc.com/lymarket' // 预发布
// export const BASE_URL = 'https://www.zzfzyc.com/lymarket' // 正式环境 // export const BASE_URL = 'https://www.zzfzyc.com/lymarket' // 正式环境
// export const BASE_URL = `http://192.168.1.5:40001/lymarket` // 王霞 // export const BASE_URL = `http://192.168.1.5:40001/lymarket` // 王霞
// export const BASE_URL = 'http://192.168.1.7:50002/lymarket' // 添 // export const BASE_URL = 'http://192.168.1.7:50002/lymarket' // 添
// export const BASE_URL = 'http://192.168.1.28:50001/lymarket' // 婷 // export const BASE_URL = 'http://192.168.1.28:50002/lymarket' // 婷
// export const BASE_URL = 'http://192.168.1.42:50002/lymarket' // 杰 // export const BASE_URL = 'http://192.168.1.42:50002/lymarket' // 杰
// CDN // CDN

View File

@ -56,3 +56,44 @@
width: 130px; width: 130px;
height: 130px; height: 130px;
} }
.no_bg_moveBtn_next {
box-shadow: none;
background-color: transparent;
border: none;
width: 200px;
height: 130px;
}
.no_bg_moveBtn_next_ever {
display: none;
}
.video_box {
border-radius: 16px;
width: 300px;
height: 300px;
// background-color: red;
position: relative;
.clearBtn {
z-index: 9999;
position: absolute;
top: 20px;
right: 10px;
}
.bottom_box {
width: 100%;
position: absolute;
bottom: -100px;
z-index: 999;
text-align: center;
width: 100%;
height: 40px;
line-height: 40px;
background-color: #337fff;
color: #fff;
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
font-size: 26px;
}
}

View File

@ -1,4 +1,4 @@
import { Button, Image, MovableArea, MovableView, View } from '@tarojs/components' import { Button, CoverView, Image, MovableArea, MovableView, Video, View } from '@tarojs/components'
import Taro, { useDidShow, useReady, useRouter } from '@tarojs/taro' import Taro, { useDidShow, useReady, useRouter } from '@tarojs/taro'
import type { ReactElement } from 'react' import type { ReactElement } from 'react'
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
@ -12,6 +12,8 @@ import { useSelector } from '@/reducers/hooks'
import { alert } from '@/common/common' import { alert } from '@/common/common'
import { formatImgUrl } from '@/common/fotmat' import { formatImgUrl } from '@/common/fotmat'
import { ORDER_STATUS } from '@/common/enum' import { ORDER_STATUS } from '@/common/enum'
import IconFont from '@/components/iconfont/iconfont'
import { IMG_CND_Prefix } from '@/common/constant'
type ShowStatus = 'shop'|'customer'|'order'|'code' type ShowStatus = 'shop'|'customer'|'order'|'code'
interface param { interface param {
@ -22,8 +24,11 @@ interface param {
messagePath?: string messagePath?: string
showCart?: false|true showCart?: false|true
orderObj?: any orderObj?: any
playVideo?: boolean
floatVideoFile?: any[]
showFloatVideo?: boolean
} }
const MoveBtn = ({ orderObj = {}, children = null, onShopClick, showList = [], messageTitle = '', messagePath = '', showCart = false }: param) => { const MoveBtn = ({ showFloatVideo = false, floatVideoFile = [], playVideo = true, orderObj = {}, children = null, onShopClick, showList = [], messageTitle = '', messagePath = '', showCart = false }: param) => {
const userInfo = useSelector(state => state.userInfo) const userInfo = useSelector(state => state.userInfo)
// 获取购物车数据数量 // 获取购物车数据数量
const { getShopCount, commonData } = useCommonData() const { getShopCount, commonData } = useCommonData()
@ -94,6 +99,21 @@ const MoveBtn = ({ orderObj = {}, children = null, onShopClick, showList = [], m
].includes(orderObj.status) ].includes(orderObj.status)
}, [orderObj.status]) }, [orderObj.status])
const [showVido, setshowVido] = useState(true)
const handShowVideo = () => {
const videoplay = Taro.createVideoContext('video')
videoplay.pause()
setshowVido(false)
}
useEffect(() => {
if (!playVideo) {
const videoplay = Taro.createVideoContext('video')
videoplay.pause()
}
}, [playVideo])
return ( return (
<MovableArea className={styles.movableItem}> <MovableArea className={styles.movableItem}>
{children} {children}
@ -128,6 +148,29 @@ const MoveBtn = ({ orderObj = {}, children = null, onShopClick, showList = [], m
> >
<Image mode="aspectFit" src={formatImgUrl('/mall/float_button_customer_service.png')} /> <Image mode="aspectFit" src={formatImgUrl('/mall/float_button_customer_service.png')} />
</MovableView>} </MovableView>}
{onShow('order') && <MovableView
className={classnames(styles.moveBtn, showVido && showFloatVideo ? styles.no_bg_moveBtn_next : styles.no_bg_moveBtn_next_ever)}
direction="all"
inertia
x="470rpx"
y="100rpx"
>
<View className={styles.video_box}>
<View className={styles.clearBtn} onClick={() => handShowVideo()}>
<IconFont name="icon-qingchuxinxi" size={60} color="#acacac"></IconFont>
</View>
<Video
style={{ width: '300rpx', height: '400rpx', borderRadius: '32rpx' }}
autoplay
id="video"
src={floatVideoFile.length ? IMG_CND_Prefix + floatVideoFile[0].video_url[0] : ''}
loop
object-fit="contain"
></Video>
<View className={styles.bottom_box}>{floatVideoFile?.[0]?.title}</View>
</View>
</MovableView>}
{showCode && <CodeSelect orderObj={orderObj} y={screenHeight.code as number} />} {showCode && <CodeSelect orderObj={orderObj} y={screenHeight.code as number} />}
<Customer messageTitle={messageTitle} messagePath={messageTitle} show={customer_service_show} showCard={showCart} onClose={customerClose} /> <Customer messageTitle={messageTitle} messagePath={messageTitle} show={customer_service_show} showCard={showCart} onClose={customerClose} />
</MovableArea> </MovableArea>

View File

@ -0,0 +1,9 @@
.scrollStyle {
white-space: nowrap;
width: 100%;
// border-radius: 16px;
// height: 450px;
// background-color: #fff;
// margin-top: 25px;
// margin-bottom: 25px;
}

View File

@ -0,0 +1,29 @@
import { Button, Icon, RichText, ScrollView, Text, View } from '@tarojs/components'
import Taro, { useDidShow, usePullDownRefresh, useRouter } from '@tarojs/taro'
import type { ReactNode } from 'react'
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import styles from './index.module.scss'
interface Params {
children?: ReactNode | null
onScrollToLower: () => void
}
const ScrollViewX = (Props: Params) => {
return (
<ScrollView
className={styles.scrollStyle}
scrollX
lowerThreshold={50}
onScrollToLower={Props.onScrollToLower}
enhanced
pagingEnabled
enablePassive="true"
>
{Props.children}
</ScrollView>
)
}
export default memo(ScrollViewX)

View File

@ -169,6 +169,145 @@ page {
} }
} }
} }
.ccum_box {
border-radius: 16px;
width: 100%;
// display: flex;
height: 450px;
overflow: hidden;
overflow-x: auto;
white-space: nowrap;
background-color: #fff;
// flex-shrink: 0;
margin-top: 25px;
margin-bottom: 25xp;
}
.scroll_box {
padding-top: 30px;
width: 100%;
border-radius: 16px;
height: 450px;
background-color: #fff;
margin-top: 25px;
margin-bottom: 25px;
.title {
margin-left: 25px;
color: rgba(0, 0, 0, 0.8);
font-weight: 500;
font-size: 28px;
margin-bottom: 20px;
}
}
.item_box {
display: inline-block;
// margin-left: 40px;
// margin-top: 30px;
margin: 20px;
width: 300px;
height: 190px;
position: relative;
.cricle {
position: absolute;
top: 20px;
right: 20px;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #c7c7c7;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
z-index: 45;
.icon {
margin-left: 20px;
width: 0px;
height: 0px;
border: 15px solid transparent; /*以下四个样式对应四种三角形,任选其一即可实现*/
/* border-top-color:lightseagreen; */
border-left-color: #fff;
// border-right-color: lightseagreen;
// border-bottom-color: lightseagreen;
}
}
.img_style {
border-top-right-radius: 16px;
border-top-left-radius: 16px;
// top: 0;
// left: 0;
position: absolute;
z-index: 12;
width: 300px;
height: 242px;
}
.bottom_box {
position: absolute;
bottom: -102px;
z-index: 50;
text-align: center;
width: 100%;
height: 50px;
line-height: 50px;
background-color: #c9c9c9;
color: #fff;
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
font-size: 26px;
}
.title_name {
text-align: center;
font-size: 28px;
margin-top: 10px;
}
}
.tag_box {
padding-top: 30px;
// padding-bottom: 30px;
width: 100%;
border-radius: 16px;
background-color: #fff;
margin-top: 25px;
margin-bottom: 25px;
.title {
margin-left: 25px;
color: rgba(0, 0, 0, 0.8);
font-weight: 500;
font-size: 28px;
margin-bottom: 20px;
}
.tag_big {
// display: flex;
// flex-wrap: wrap;
display: grid;
grid-template-columns: 25% 25% 25% 25%;
justify-content: space-between;
.tag_item {
box-sizing: border-box;
// margin-left: 30px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-bottom: 28px;
// flex: 1;
.tag_img {
width: 90px;
height: 90px;
border-radius: 50%;
margin-bottom: 15px;
}
.tag_title {
text-align: center;
font-size: 28px;
margin-top: 10px;
}
}
}
}
.product_detail { .product_detail {
// padding: 20px; // padding: 20px;
background-color: #fff; background-color: #fff;
@ -187,6 +326,7 @@ page {
background-color: #fff; background-color: #fff;
padding-bottom: constant(safe-area-inset-bottom); padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);
z-index: 9999;
.icon_btn { .icon_btn {
display: flex; display: flex;
flex: 1; flex: 1;

View File

@ -1,4 +1,4 @@
import { Button, Icon, RichText, Text, View } from '@tarojs/components' import { Button, CoverView, Icon, Image, RichText, Text, Video, View } from '@tarojs/components'
import Taro, { useDidShow, usePullDownRefresh, useRouter } from '@tarojs/taro' import Taro, { useDidShow, usePullDownRefresh, useRouter } from '@tarojs/taro'
import classnames from 'classnames' import classnames from 'classnames'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
@ -7,9 +7,10 @@ import OrderCount from './components/orderCount'
import styles from './index.module.scss' import styles from './index.module.scss'
import FeaturePopup from './components/feature' import FeaturePopup from './components/feature'
import Recommend from './components/recommend' import Recommend from './components/recommend'
import ScrollViewX from './components/scrollViewX'
import ShopCart from '@/components/shopCart' import ShopCart from '@/components/shopCart'
import { formatDateTime, formatHashTag, formatImgUrl, formatPriceDiv, formatRemoveHashTag } from '@/common/fotmat' import { formatDateTime, formatHashTag, formatImgUrl, formatPriceDiv, formatRemoveHashTag } from '@/common/fotmat'
import { GetProductDetailApi } from '@/api/material' import { GetProductDetailApi, MallCherryestimate_catevideolist, MallCherryestimate_catevideoview } from '@/api/material'
import useLogin from '@/use/useLogin' import useLogin from '@/use/useLogin'
import { AnalysisShortCodeApi, GetShortCodeApi } from '@/api/share' import { AnalysisShortCodeApi, GetShortCodeApi } from '@/api/share'
import { SHARE_SCENE } from '@/common/enum' import { SHARE_SCENE } from '@/common/enum'
@ -26,6 +27,7 @@ import IconFont from '@/components/iconfont/iconfont'
import LabAndImgShow from '@/components/LabAndImgShow' import LabAndImgShow from '@/components/LabAndImgShow'
import PopupSelectColor from '@/components/popupSelectColor' import PopupSelectColor from '@/components/popupSelectColor'
import { GetColorCardOrderByProductApi } from '@/api/colorCard' import { GetColorCardOrderByProductApi } from '@/api/colorCard'
import { IMG_CND_Prefix } from '@/common/constant'
interface item { title: string; img: string; url: string; id: number } interface item { title: string; img: string; url: string; id: number }
@ -274,8 +276,81 @@ const Details = (props: Params) => {
}) })
} }
// 获取性能测评视频
const [videoList, setvideoList] = useState<any[]>([])
// 浮窗视频url
const [floatUrl, setfloatUrl] = useState<any[]>([])
useEffect(() => {
getVideoList()
}, [])
const { fetchData: viewFetch } = MallCherryestimate_catevideolist()
const getVideoList = async() => {
console.log(router.params.id, '4545646')
const res = await viewFetch({ ...videoCurrent.current })
if (videoCurrent.current.page == 1 && res.data.list.length) {
// setfloatUrl(IMG_CND_Prefix + res.data.list?.[0].video_url[0] || '')
setfloatUrl([res.data.list[0]] || [])
setshowFloatVideo(true)
}
if (!res.data.list.length) {
setfloatUrl([])
setshowVideoPlay(false)
setshowFloatVideo(false)
}
if (res.data.list.length) {
// setvideoList(val => ({ ...val, ...res.data.list }))
setvideoList([...videoList, ...res.data.list])
console.log(videoList, '456456')
}
videoCurrent.current.total = res.data.total
}
const videoCurrent = useRef({
page: 1,
size: 10,
product_id: Number(router.params.id),
total: 0,
status: 0,
})
// 分页控制
const handOnScrollToLower = () => {
if (videoCurrent.current.page * videoCurrent.current.size >= videoCurrent.current.total) { return }
videoCurrent.current.page += 1
getVideoList()
console.log(111, videoCurrent.current.page)
}
// 视频播放
const { fetchData: viewNumsFetch } = MallCherryestimate_catevideoview()
const handPlay = async(id, elementId) => {
await viewNumsFetch({ id })
setshowVideoPlay(false)
const videoplay = Taro.createVideoContext(elementId)
videoplay.requestFullScreen({ direction: 0 })
videoplay.play()
}
const handleClose = (event, elementId) => {
if (!event.detail.fullScreen) {
const videoplay = Taro.createVideoContext(elementId)
videoplay.pause()
}
}
// 控制浮窗的视频是否被其他的视频影响
const [showVideoPlay, setshowVideoPlay] = useState(true)
const [showFloatVideo, setshowFloatVideo] = useState(false)
return ( return (
<MoveBtn showList={['order']}> <MoveBtn showList={['order']} playVideo={showVideoPlay} floatVideoFile={floatUrl} showFloatVideo={showFloatVideo}>
<View className={styles.main}> <View className={styles.main}>
<View className={styles.content}> <View className={styles.content}>
<DesSwiper list={productInfo.texture_url ? productInfo.texture_url.toString().split(',') : []} /> <DesSwiper list={productInfo.texture_url ? productInfo.texture_url.toString().split(',') : []} />
@ -360,6 +435,62 @@ const Details = (props: Params) => {
})} })}
</View> </View>
</View> </View>
{
videoList.length > 0 && <View className={styles.scroll_box}>
<View className={styles.title}></View>
<ScrollViewX
onScrollToLower={() => handOnScrollToLower()}
>
{
videoList.map((item, index) => {
return (
<View className={styles.item_box} key={index}>
<View className={styles.cricle} onClick={() => handPlay(item.estimate_video_id, `video${index}`)}>
<View className={styles.icon}></View>
</View>
<Image
className={styles.img_style}
src={item.video_pic.length ? IMG_CND_Prefix + item.video_pic[0] : IMG_CND_Prefix + item.frame_pic}
mode="aspectFill"
></Image>
<Video
style={{ width: '300rpx', height: '290rpx', borderRadius: '16rpx' }}
id={`video${index}`}
src={IMG_CND_Prefix + item.video_url[0]}
object-fit="contain"
show-center-play-btn={false}
show-play-btn={false}
show-fullscreen-btn={false}
onFullScreenChange={event => handleClose(event, `video${index}`)}
></Video>
<View className={styles.bottom_box}>{item.result}</View>
<View className={styles.title_name}>{item.title}</View>
</View>
)
})
}
</ScrollViewX>
</View>
}
{
(productInfo?.clothes_is_consult && productInfo?.clothes_is_consult?.length > 0)
&& <View className={styles.tag_box}>
<View className={styles.title}></View>
<View className={styles.tag_big}>
{
productInfo?.clothes_is_consult.map((item, index) => {
return (
<View className={styles.tag_item} key={index}>
<Image className={styles.tag_img} mode="aspectFill" src={IMG_CND_Prefix + item?.icon[0]}></Image>
<View className={styles.tag_title}>{item?.product_label_name}</View>
</View>
)
})
}
</View>
</View>
}
<View className={styles.product_detail}> <View className={styles.product_detail}>
<RichText nodes={html}></RichText> <RichText nodes={html}></RichText>
</View> </View>