index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <script setup lang="ts">
  2. import { StaticUrl } from '@/config'
  3. import router from '@/router'
  4. const { statusBarHeight, MenuButtonHeight } = useSysStore()
  5. definePage({
  6. name: 'xsb-goods',
  7. islogin: false,
  8. style: {
  9. navigationStyle: 'custom',
  10. navigationBarTitleText: '星闪豹商品详情',
  11. },
  12. })
  13. const selectGoods = ref(false)
  14. const SelectGoodsNum = ref(1)
  15. const specId = ref()
  16. const { userInfo } = storeToRefs(useUserStore())
  17. const { SelectShopInfo } = storeToRefs(useSysXsbStore())
  18. const { getTotalNum } = storeToRefs(useXsbCartStore())
  19. // const goodsTab = ref(0)
  20. const current = ref<number>(0)
  21. const currentDetaile = ref(0)
  22. // const goodsTabList = ref([
  23. // { title: '相似商品', id: 0 },
  24. // { title: '经常一起买', id: 1 },
  25. // ])
  26. const goodsDetaileTabList = ref([
  27. { title: '商品', id: 0 },
  28. { title: '评价', id: 1 },
  29. { title: '详情', id: 2 },
  30. { title: '推荐', id: 3 },
  31. ])
  32. const goodsTabData = ref([])
  33. const isShowTab = ref(false)
  34. // const currentTabGoods = ref(0)
  35. const goodsId = ref()
  36. onLoad((option: any) => {
  37. goodsId.value = option.id
  38. getGoodsDetaile()
  39. })
  40. const goodsInfo = ref<Api.xsbProductDetail>()
  41. const swiperList = computed(() => {
  42. if (goodsInfo.value) {
  43. return goodsInfo.value.imgs?.split(',')
  44. }
  45. return []
  46. })
  47. const goodsContent = computed(() => {
  48. if (goodsInfo.value?.content) {
  49. return goodsInfo.value.content.replace(
  50. /<img/gi,
  51. '<img style="max-width:100%;height:auto" ',
  52. )
  53. }
  54. return '暂无数据'
  55. })
  56. onMounted(() => {
  57. // goodsTabData.value = splitArrayToPages([{ id: 1, name: '商品' }, { id: 2, name: '商品' }, { id: 3, name: '商品' }, { id: 4, name: '商品' }, { id: 8, name: '商品' }, { id: 5, name: '商品' }, { id: 10, name: '商品' }, { id: 6, name: '商品' }, { id: 9, name: '商品' }, { id: 7, name: '商品' }, { id: 11, name: '商品' }])
  58. console.log(goodsTabData.value, 'goodsTabData')
  59. })
  60. // function splitArrayToPages<T>(arr: T[]): T[][] {
  61. // const PAGE_SIZE = 6
  62. // const MAX_PAGES = 3
  63. // const result: T[][] = []
  64. // for (let i = 0; i < Math.min(MAX_PAGES, Math.ceil(arr.length / PAGE_SIZE)); i++) {
  65. // const start = i * PAGE_SIZE
  66. // const end = start + PAGE_SIZE
  67. // result.push(arr.slice(start, end))
  68. // }
  69. // return result
  70. // }
  71. onPageScroll((e) => {
  72. if (e.scrollTop >= 315) {
  73. isShowTab.value = true
  74. }
  75. else {
  76. isShowTab.value = false
  77. }
  78. })
  79. function handleGoCurren(id: number) {
  80. currentDetaile.value = id
  81. uni.pageScrollTo({ selector: `.view-${id}` })
  82. }
  83. async function getGoodsDetaile() {
  84. const res = await Apis.xsb.getProductDetail({ data: { id: goodsId.value, shopId: Number(SelectShopInfo.value?.shopId), channelId: userInfo.value.channelId || 1 } })
  85. console.log(res, '请求')
  86. goodsInfo.value = res.data
  87. specId.value = res.data.skuList?.[0].skuId
  88. }
  89. function handleConfimOrder() {
  90. if (Number(unref(goodsInfo)?.spuStock) < unref(SelectGoodsNum)) {
  91. useGlobalToast().show('库存不足,请调整购买数量')
  92. return
  93. }
  94. router.push({ name: 'xsb-confirmOrder' })
  95. }
  96. async function handleAddCart() {
  97. try {
  98. await useXsbCartStore().addCart(specId.value, unref(SelectGoodsNum), unref(SelectShopInfo.value.shopId))
  99. selectGoods.value = false
  100. useGlobalToast().show('添加成功')
  101. }
  102. catch (error) {
  103. console.log(error)
  104. }
  105. }
  106. </script>
  107. <template>
  108. <page-meta :page-style="selectGoods ? 'overflow: hidden;' : '' " />
  109. <view class="page-xsb">
  110. <wd-navbar
  111. title="商品详情" :custom-style="`background-color:${isShowTab ? '#FFF !important' : 'transparent !important'}`" :bordered="false" :z-index="99"
  112. safe-area-inset-top left-arrow fixed @click-left="router.back()"
  113. />
  114. <template v-if="goodsInfo">
  115. <wd-swiper v-model:current="current" :list="swiperList" :autoplay="false" :height="375">
  116. <template #indicator="{ current: currentIndex, total }">
  117. <view class="custom-indicator absolute bottom-60rpx right-20rpx px26rpx">
  118. {{ currentIndex + 1 }}/{{ total }}
  119. </view>
  120. </template>
  121. </wd-swiper>
  122. <view class="view-0 header relative z-3 rounded-t-32rpx px24rpx pt24rpx -mt30rpx">
  123. <view class="flex items-center justify-between">
  124. <view class="flex items-end text-#FF4D3A font-semibold">
  125. <view class="text-24rpx">
  126. </view>
  127. <view class="text-36rpx line-height-[36rpx]">
  128. {{ goodsInfo?.channelProdPrice }}
  129. </view>
  130. </view>
  131. <!-- <view>
  132. <image class="h40rpx w40rpx" :src="`${StaticUrl}/collect-yes.png`" />
  133. </view> -->
  134. </view>
  135. </view>
  136. <view class="sticky left-0 z-99 box-border h84rpx w-full flex items-center justify-between bg-white px24rpx" :style="{ top: `${statusBarHeight + MenuButtonHeight}px`, opacity: isShowTab ? 1 : 0 }" :class="[isShowTab ? '' : '']">
  137. <view v-for="item in goodsDetaileTabList" :key="item.id" class="relative flex items-center text-32rpx font-semibold" @click="handleGoCurren(item.id)">
  138. {{ item.title }}
  139. <view v-show="currentDetaile == item.id" class="line absolute left-50% h12rpx w40rpx rounded-8rpx bg-[var(--them-color)] -bottom-15rpx -translate-x-50%" />
  140. </view>
  141. </view>
  142. <view class="px24rpx">
  143. <view class="-mt64rpx">
  144. <view class="text-left text-28rpx font-semibold">
  145. <!-- <view v-for="i in 2" :key="i" class="mr5px inline-block">
  146. <wd-tag type="primary">
  147. 新品{{ i }}
  148. </wd-tag>
  149. </view> -->
  150. {{ goodsInfo.prodName }}
  151. </view>
  152. </view>
  153. <!-- <view class="mt16rpx text-24rpx text-#AAAAAA">
  154. 优选产地,皮薄核小,维c满满
  155. </view> -->
  156. <!-- <view class="mt20rpx flex items-center">
  157. <view
  158. v-for="item in 2" :key="item"
  159. class="mr16rpx flex items-center justify-center border-1rpx border-#BC9264 rounded-8rpx border-solid bg-[#FFF5E9] px16rpx py6rpx text-24rpx text-#BC9264 font-semibold"
  160. >
  161. 一口化渣{{ item }}
  162. </view>
  163. </view> -->
  164. <view class="mt20rpx flex items-center justify-between rounded-16rpx bg-white p24rpx">
  165. <view class="flex items-center">
  166. <view class="flex-shrink-0">
  167. <view class="text-28rpx font-semibold">
  168. {{ goodsInfo.brandName }}
  169. </view>
  170. <view class="mt16rpx text-24rpx text-#AAAAAA">
  171. 品牌
  172. </view>
  173. </view>
  174. </view>
  175. <view class="mx24rpx">
  176. <wd-divider vertical color="#F0F0F0" />
  177. </view>
  178. <view class="flex items-center">
  179. <view class="flex-shrink-0">
  180. <view class="text-28rpx font-semibold">
  181. {{ goodsInfo.skuList[0].weight }}g
  182. </view>
  183. <view class="mt16rpx text-24rpx text-#AAAAAA">
  184. 重量
  185. </view>
  186. </view>
  187. </view>
  188. <view class="mx24rpx">
  189. <wd-divider vertical color="#F0F0F0" />
  190. </view>
  191. <view class="flex items-center">
  192. <view class="flex-shrink-0">
  193. <view class="text-28rpx font-semibold">
  194. {{ goodsInfo.skuList[0].weightUnit }}
  195. </view>
  196. <view class="mt16rpx text-24rpx text-#AAAAAA">
  197. 单位
  198. </view>
  199. </view>
  200. </view>
  201. <wd-icon name="chevron-right" size="22px" color="#AAAAAA" />
  202. </view>
  203. <!-- <view class="view-1 mt20rpx flex items-center rounded-16rpx bg-white p24rpx">
  204. <view class="w-full flex items-center justify-between">
  205. <view class="text-32rpx font-semibold">
  206. 评价(10万+)
  207. </view>
  208. <view class="flex items-center">
  209. <view class="mr10rpx flex items-center text-28rpx text-#FF4D3A">
  210. <view>好评率</view>
  211. <view class="ml5rpx font-semibold">
  212. 99.8%
  213. </view>
  214. </view>
  215. <wd-icon name="chevron-right" size="22px" color="#AAAAAA" />
  216. </view>
  217. </view>
  218. </view> -->
  219. <!-- <view class="mt20rpx rounded-16rpx bg-white p24rpx">
  220. <wd-tabs v-model="goodsTab">
  221. <block v-for="item in goodsTabList" :key="item.id">
  222. <wd-tab :title="item.title" />
  223. </block>
  224. </wd-tabs>
  225. <swiper class="mt20rpx h900rpx" indicator-active-color="var(--them-color)" @change="(e) => currentTabGoods = e.detail.current">
  226. <swiper-item
  227. v-for="items in goodsTabData" :key="items"
  228. class="grid grid-cols-3 items-start gap-x-16rpx gap-y-16rpx pb20rpx"
  229. >
  230. <view
  231. v-for="goods in items" :key="goods"
  232. class="box-border w204rpx border border-2rpx border-#F0F0F0 rounded-16rpx border-solid px4rpx py8rpx"
  233. >
  234. <image lazy-load :src="`${StaticUrl}/shu.png`" class="h188rpx w198rpx" />
  235. <view class="mt20rpx px16rpx text-24rpx font-semibold">
  236. 新鲜现宰杀肋排200g
  237. </view>
  238. <view class="mt12rpx truncate px16rpx text-24rpx text-#AAAAAA">
  239. 维c满满,营养qweqwe
  240. </view>
  241. <view class="my20rpx flex items-center justify-between px16rpx">
  242. <view class="flex items-end text-#FF4D3A font-semibold">
  243. <view class="text-24rpx">
  244. </view>
  245. <view class="text-32rpx line-height-[32rpx]">
  246. 1.395
  247. </view>
  248. </view>
  249. <image :src="`${StaticUrl}/cart-yes.png`" class="h44rpx w44rpx" />
  250. </view>
  251. </view>
  252. </swiper-item>
  253. </swiper>
  254. <view class="mt24rpx flex items-center justify-center">
  255. <view v-for="item, idx in goodsTabData" :key="idx" class="mr14rpx transition-all transition-duration-400 ease-in" :class="[currentTabGoods == idx ? 'rounded-12rpx w-40rpx h12rpx bg-[var(--them-color)]' : 'w12rpx h12rpx rounded-50% bg-#F0F0F0']" />
  256. </view>
  257. </view> -->
  258. </view>
  259. <view class="view-2 mt20rpx bg-white">
  260. <view class="p24rpx text-32rpx font-semibold">
  261. 商品详情
  262. <rich-text :nodes="goodsContent" />
  263. </view>
  264. </view>
  265. <!-- <view class="view-3 mt28rpx flex items-center justify-center">
  266. <view class="flex items-center">
  267. <image
  268. :src="`${StaticUrl}/goods-recommend.png`"
  269. class="mr12rpx h25rpx w26rpx"
  270. />
  271. <view class="text-36rpx text-[var(--them-color)] font-semibold">
  272. 为你推荐
  273. </view>
  274. <image
  275. :src="`${StaticUrl}/goods-recommend.png`"
  276. class="ml12rpx h25rpx w26rpx"
  277. />
  278. </view>
  279. </view> -->
  280. <view class="h180rpx" />
  281. <view class="ios shadow-fixed fixed bottom-0 left-0 w-full rounded-t-32rpx bg-white">
  282. <view class="flex items-center justify-between px24rpx py20rpx">
  283. <view class="mr36rpx" @click="router.replace({ name: 'xsb-homeTabbar' })">
  284. <image
  285. :src="`${StaticUrl}/goods-home.png`"
  286. class="h44rpx w44rpx"
  287. />
  288. <view class="text-20rpx">
  289. 首页
  290. </view>
  291. </view>
  292. <view class="relative mr36rpx">
  293. <image
  294. :src="`${StaticUrl}/goods-kf.png`"
  295. class="h44rpx w44rpx"
  296. />
  297. <button class="zbutton" open-type="contact">
  298. <view class="text-20rpx">
  299. 客服
  300. </view>
  301. </button>
  302. </view>
  303. <wd-badge :model-value="getTotalNum">
  304. <view @click="router.replace({ name: 'xsb-homeTabbar', animationType: 'fade-out', params: { name: 'xsb-cart' } })">
  305. <image
  306. :src="`${StaticUrl}/goods-cart.png`"
  307. class="h44rpx w44rpx"
  308. />
  309. <view class="text-20rpx">
  310. 购物车
  311. </view>
  312. </view>
  313. </wd-badge>
  314. <view class="flex items-center">
  315. <view class="w220rpx">
  316. <wd-button plain hairline block @click="selectGoods = true">
  317. 加入购物车
  318. </wd-button>
  319. </view>
  320. <view class="ml20rpx w220rpx" @click="selectGoods = true">
  321. <wd-button block class="w-full">
  322. 立即购买
  323. </wd-button>
  324. </view>
  325. </view>
  326. </view>
  327. </view>
  328. <Zpopup v-model="selectGoods">
  329. <view class="bg-white px24rpx py28rpx">
  330. <view class="flex items-center">
  331. <image
  332. :src="goodsInfo.pic"
  333. class="h200rpx w200rpx flex-shrink-0 rounded-16rpx"
  334. />
  335. <view class="ml20rpx">
  336. <view class="flex items-end text-#FF4D3A font-semibold">
  337. <view class="text-24rpx">
  338. </view>
  339. <view class="text-36rpx line-height-[36rpx]">
  340. {{ goodsInfo?.channelProdPrice }}
  341. </view>
  342. </view>
  343. <view class="mt20rpx flex items-center">
  344. <view class="text-24rpx text-#AAAAAA">
  345. 已选
  346. </view>
  347. <view class="ml20rpx text-28rpx font-semibold">
  348. {{ goodsInfo.skuList.find((it) => it.skuId === specId)?.spec }} {{ SelectGoodsNum }}件
  349. </view>
  350. </view>
  351. </view>
  352. </view>
  353. <view class="my28rpx h2rpx w-full bg-#F0F0F0" />
  354. <view class="mb20rpx">
  355. <view class="text-28rpx font-semibold">
  356. 规格
  357. </view>
  358. <wd-radio-group v-model="specId" cell shape="button">
  359. <wd-radio v-for="item in goodsInfo.skuList" :key="item.skuId" :value="item.skuId">
  360. {{ item.spec }}
  361. </wd-radio>
  362. </wd-radio-group>
  363. </view>
  364. <view class="flex items-center justify-between">
  365. <view class="text-28rpx font-semibold">
  366. 数量
  367. </view>
  368. <wd-input-number v-model="SelectGoodsNum" />
  369. </view>
  370. <view class="h200rpx" />
  371. </view>
  372. <view class="shadow-fixed ios fixed bottom-0 left-0 box-border w-full rounded-t-32rpx bg-white px24rpx">
  373. <view class="box-border w-full flex items-center justify-between py20rpx">
  374. <view class="w-48%">
  375. <wd-button plain hairline block @click="handleAddCart">
  376. 加入购物车
  377. </wd-button>
  378. </view>
  379. <view class="w-48%">
  380. <wd-button block @click="handleConfimOrder">
  381. 立即购买
  382. </wd-button>
  383. </view>
  384. </view>
  385. </view>
  386. </Zpopup>
  387. </template>
  388. </view>
  389. </template>
  390. <style scoped lang="scss">
  391. .custom-indicator {
  392. border-radius: 16rpx;
  393. background: rgba(0, 0, 0, 0.5);
  394. color: #ffffff;
  395. font-size: 24rpx;
  396. }
  397. .shadow-fixed{
  398. box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(0,0,0,0.09);
  399. }
  400. .header {
  401. background: linear-gradient(180deg, #FFFFFF 0%, #FFFFFF 62%, #F6F6F6 100%);
  402. }
  403. .page-xsb {
  404. :deep() {
  405. .wd-tabs__nav-container .wd-tabs__nav-item:nth-child(2){
  406. width: 220rpx !important ;
  407. }
  408. .wd-tabs__nav-item {
  409. flex:unset !important;
  410. .wd-tabs__nav-item-text {
  411. font-size: 32rpx !important;
  412. }
  413. }
  414. .ios .wd-button{
  415. min-width: unset !important;
  416. }
  417. .wd-radio-group.is-button{
  418. padding: 0!important;
  419. }
  420. }
  421. }
  422. </style>