classfiy.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. <script setup lang="ts">
  2. import type { LoadMoreState } from 'wot-design-uni/components/wd-loadmore/types'
  3. import selectSku from '../../components/select-sku/index.vue'
  4. import { StaticUrl } from '@/config'
  5. import router from '@/router'
  6. const props = defineProps<{ categoryList: Api.xsbCategories[], hotText: Api.xsbSearchTerm[] }>()
  7. const { statusBarHeight, MenuButtonHeight } = storeToRefs(useSysStore())
  8. const { topNavActive, leftActive, SelectShopInfo } = storeToRefs(useSysXsbStore())
  9. const { userInfo, token } = storeToRefs(useUserStore())
  10. const classfiylist = computed(() => props.categoryList)
  11. const sortClassBtn = ref(1)
  12. const show = ref(false)
  13. const cartList = ref<Api.xsbCategoriesCartList[]>([])
  14. const cartIds = computed(() => cartList.value.filter(it => it.isDelete !== '1' && it.shopSkuStocks !== '0').map(it => it.id))
  15. const showball = ref(false)
  16. const _this = getCurrentInstance()
  17. const selectGoods = ref(false)
  18. // 多规格商品skuid
  19. const selectSkuId = ref(0)
  20. const SelectGoodsNum = ref(1)
  21. const goodsInTo = ref()
  22. const goodsInfo = ref<Api.xsbCategoryProductList | Api.xsbProductDetail | undefined>()
  23. definePage({
  24. name: 'xsb-classfiy',
  25. islogin: false,
  26. style: {
  27. navigationStyle: 'custom',
  28. navigationBarTitleText: '星闪豹分类',
  29. disableScroll: true,
  30. },
  31. })
  32. const isTopLoading = ref(false)
  33. const cartPopup = ref(false)
  34. const basllObj = ref({
  35. left: 0,
  36. top: 0,
  37. x: -402,
  38. y: 773,
  39. })
  40. const x = computed(() => `${basllObj.value.x}px`)
  41. const y = computed(() => `${basllObj.value.y}px`)
  42. const left = computed(() => `${basllObj.value.left}px`)
  43. const top = computed(() => `${basllObj.value.top}px`)
  44. const productList = ref<Api.xsbCategoryProductList[]>([])
  45. const topScrollView = ref()
  46. const scrollTop = ref<number | undefined>(0)
  47. const goodsLoading = ref<LoadMoreState>()
  48. const navHeight = computed(() => {
  49. return (`${Number(MenuButtonHeight.value) + Number(statusBarHeight.value)}px`)
  50. })
  51. const totalProduct = ref<Api.shoppingCartOrderConfirm>()
  52. function handleTopNavChange(item: Api.xsbCategoriesChildren) {
  53. topNavActive.value = item.code
  54. if (!item.children)
  55. return
  56. goodsLoading.value = 'loading'
  57. leftActive.value = item.children[0].code
  58. show.value = false
  59. topScrollView.value = null
  60. nextTick(() => {
  61. topScrollView.value = item.code
  62. })
  63. getProductList()
  64. }
  65. const categories = computed(() => {
  66. return classfiylist.value.find(it => it.code === topNavActive.value)?.children || []
  67. })
  68. const categoriesId = computed(() => {
  69. return categories.value.find(it => it.code === leftActive.value)?.id
  70. })
  71. async function getCartCategorList() {
  72. return new Promise((resolve, reject) => {
  73. Apis.xsb.myShoppingCartCategory({
  74. data: {
  75. businessType: 'XSB',
  76. channelId: unref(userInfo).channelId,
  77. shopId: unref(SelectShopInfo).shopId,
  78. },
  79. }).then((res) => {
  80. cartList.value = res.data
  81. if (cartList.value.length) {
  82. getGoodsPrice()
  83. }
  84. resolve(res)
  85. }).catch((err) => {
  86. reject(err)
  87. })
  88. })
  89. }
  90. function handleChange({ value }: { value: string }) {
  91. leftActive.value = value
  92. getProductList()
  93. }
  94. function handleLeftChange(item: Api.xsbCategories) {
  95. goodsLoading.value = 'loading'
  96. handleChange({ value: item.code })
  97. }
  98. async function getProductList() {
  99. const res = await Apis.xsb.getCategoryProductList({
  100. data: {
  101. categoryId: Number(categoriesId.value),
  102. shopId: Number(SelectShopInfo.value?.shopId) || 1,
  103. channelId: unref(userInfo).channelId || 1,
  104. },
  105. })
  106. productList.value = res.data
  107. if (!res.data.length) {
  108. scrollTop.value = undefined
  109. nextTick(() => {
  110. scrollTop.value = 0
  111. })
  112. }
  113. if (!isTopLoading.value) {
  114. scrollTop.value = undefined
  115. nextTick(() => {
  116. scrollTop.value = 0
  117. })
  118. }
  119. else {
  120. goodsInTo.value = null
  121. nextTick(() => {
  122. goodsInTo.value = res.data.length > 4 ? res.data[res.data.length - 4].prodId : null
  123. })
  124. }
  125. goodsLoading.value = 'finished'
  126. isTopLoading.value = false
  127. setProductNum()
  128. }
  129. function handlScrollBottom() {
  130. goodsLoading.value = 'loading'
  131. const index = categories?.value.findIndex(it => it.code === leftActive.value)
  132. console.log(index, '-================')
  133. if (index + 1 === categories.value.length) {
  134. goodsLoading.value = 'finished'
  135. return
  136. }
  137. if (index !== -1) {
  138. handleChange({ value: categories.value[index + 1].code })
  139. }
  140. }
  141. function handleSrollTop() {
  142. isTopLoading.value = true
  143. const index = categories?.value.findIndex(it => it.code === leftActive.value)
  144. if (index !== -1) {
  145. if (index === 0) {
  146. nextTick(() => isTopLoading.value = false)
  147. }
  148. else {
  149. handleChange({ value: categories.value[index - 1].code })
  150. }
  151. }
  152. }
  153. async function handleAddCart(event: WechatMiniprogram.TouchEvent, item: Api.xsbCategoryProductList) {
  154. await useUserStore().checkLogin()
  155. if (item.skuList.length > 1) {
  156. goodsInfo.value = item
  157. selectGoods.value = true
  158. return
  159. }
  160. if (showball.value)
  161. return
  162. basllObj.value.left = event.detail.x
  163. basllObj.value.top = event.detail.y
  164. showball.value = true
  165. setTimeout(() => {
  166. showball.value = false
  167. }, 500)
  168. await useSmqjhCartStore().addCart(item.skuList[0].skuId, 1, Number(item.shopId), 'XSB')
  169. await getCartCategorList()
  170. setProductNum()
  171. }
  172. async function handleSubCart(event: WechatMiniprogram.TouchEvent, item: Api.xsbCategoryProductList) {
  173. if (item.num === 1) {
  174. useGlobalMessage().confirm({
  175. msg: '是否删除该商品?',
  176. success: async () => {
  177. await useSmqjhCartStore().addCart(item.skuList[0].skuId, -1, Number(item.shopId), 'XSB')
  178. await getCartCategorList()
  179. setProductNum()
  180. totalProduct.value = undefined
  181. },
  182. })
  183. }
  184. else {
  185. if (showball.value)
  186. return
  187. basllObj.value.left = event.detail.x
  188. basllObj.value.top = event.detail.y
  189. showball.value = true
  190. setTimeout(() => {
  191. showball.value = false
  192. }, 500)
  193. await useSmqjhCartStore().addCart(item.skuList[0].skuId, -1, Number(item.shopId), 'XSB')
  194. await getCartCategorList()
  195. setProductNum()
  196. }
  197. }
  198. onMounted(async () => {
  199. if (!topNavActive.value || !leftActive.value) {
  200. topNavActive.value = props.categoryList && props.categoryList[0].code
  201. leftActive.value = props.categoryList[0].children && props.categoryList[0].children[0].code
  202. }
  203. goodsLoading.value = 'loading'
  204. if (leftActive.value) {
  205. handleChange({ value: leftActive.value })
  206. }
  207. if (topNavActive.value) {
  208. topScrollView.value = null
  209. nextTick(() => {
  210. topScrollView.value = topNavActive.value
  211. })
  212. }
  213. getCartBox()
  214. if (token.value) {
  215. await getCartCategorList()
  216. }
  217. })
  218. function getCartBox() {
  219. const query = uni.createSelectorQuery().in(_this)
  220. query.select('.cart-box').boundingClientRect()
  221. query.exec((res) => {
  222. basllObj.value.y = res[0].top
  223. uni.getSystemInfo().then((info) => {
  224. basllObj.value.x = -(info.screenWidth - res[0].left - 15)
  225. console.log(basllObj.value.x, basllObj.value.y)
  226. })
  227. })
  228. }
  229. function handleGo(item: Api.xsbCategoryProductList) {
  230. if (!item.prodId) {
  231. useGlobalToast().show('后端数据异常!')
  232. return
  233. }
  234. router.push({ name: 'xsb-goods', params: { id: String(item.prodId) } })
  235. }
  236. async function getGoodsPrice() {
  237. if (cartIds.value.length) {
  238. const res = await useSmqjhCartStore().getCartAddGoodsPrice(cartIds.value.join(','))
  239. totalProduct.value = res
  240. }
  241. }
  242. async function handleSub(item: Api.xsbCategoriesCartList) {
  243. if (item.num === 1) {
  244. useGlobalMessage().confirm({
  245. msg: '是否删除该商品?',
  246. success: async () => {
  247. cartPopup.value = false
  248. await useSmqjhCartStore().addCart(item.skuId, -1, item.shopId, 'XSB')
  249. await getCartCategorList()
  250. setProductNum()
  251. totalProduct.value = undefined
  252. },
  253. })
  254. }
  255. else {
  256. await useSmqjhCartStore().addCart(item.skuId, -1, item.shopId, 'XSB')
  257. getGoodsPrice()
  258. await getCartCategorList()
  259. setProductNum()
  260. }
  261. }
  262. async function handleAdd(item: Api.xsbCategoriesCartList) {
  263. await useSmqjhCartStore().addCart(item.skuId, 1, item.shopId, 'XSB')
  264. getGoodsPrice()
  265. await getCartCategorList()
  266. setProductNum()
  267. }
  268. onUnmounted(() => {
  269. console.log('组件卸载')
  270. topNavActive.value = ''
  271. leftActive.value = ''
  272. })
  273. async function handleDelCartGoods(item: Api.xsbCategoriesCartList) {
  274. const msg = item.isDelete ? '商品已被商家删除,是否确认删除该门店下的商品?' : '门店商品库存不足,是否删除该门店下的商品?'
  275. useGlobalMessage().confirm({
  276. title: '提示',
  277. msg,
  278. success: async () => {
  279. uni.showLoading({ mask: true })
  280. try {
  281. await Apis.common.deleteShoppingCart({
  282. pathParams: {
  283. ids: String(item.id),
  284. },
  285. })
  286. await getCartCategorList()
  287. uni.hideLoading()
  288. }
  289. catch {
  290. uni.hideLoading()
  291. }
  292. },
  293. })
  294. }
  295. function setProductNum() {
  296. if (!cartList.value.length) {
  297. productList.value = productList.value.map((goods) => {
  298. goods.num = undefined
  299. return goods
  300. })
  301. return
  302. }
  303. cartList.value.forEach((it) => {
  304. productList.value = productList.value.map((goods) => {
  305. if (goods.skuList.length && goods.skuList[0].skuId === it.skuId) {
  306. goods.num = it.num
  307. }
  308. return goods
  309. })
  310. })
  311. }
  312. async function handleSkuAddCart() {
  313. await useSmqjhCartStore().addCart(unref(selectSkuId), unref(SelectGoodsNum), Number(goodsInfo.value?.shopId), 'XSB')
  314. getGoodsPrice()
  315. await getCartCategorList()
  316. }
  317. function handlePay() {
  318. if (!totalProduct.value) {
  319. useGlobalToast().show('请选择商品')
  320. return
  321. }
  322. const shopSkuStock = totalProduct.value.skuList.filter(it => it.num > Number(it.shopSkuStocks))
  323. if (shopSkuStock.length) {
  324. useGlobalToast().show({ msg: `${shopSkuStock[0].skuName}库存不足` })
  325. return
  326. }
  327. router.push({ name: 'xsb-confirmOrder', params: { data: JSON.stringify(totalProduct.value) } })
  328. }
  329. </script>
  330. <template>
  331. <view class="page-xsb">
  332. <wd-navbar
  333. title="" custom-style="background-color:#F4FFD1" :bordered="false" :z-index="99" safe-area-inset-top
  334. fixed
  335. >
  336. <template #left>
  337. <view class="flex items-center" @click="router.push({ name: 'xsb-search' })">
  338. <view
  339. class="h60rpx w-474rpx flex items-center justify-between border-2rpx border-[var(--them-color)] rounded-40rpx border-solid bg-white pr6rpx"
  340. >
  341. <view class="flex items-center pb14rpx pl24rpx pt16rpx">
  342. <wd-icon name="search" size="14" color="#ccc" />
  343. <view class="search ml12rpx h-full w-full overflow-hidden">
  344. <wd-notice-bar
  345. :text="hotText.map((it) => it.searchName)" custom-class="notice-bar" color="#ccc"
  346. background-color="#fff" direction="vertical"
  347. />
  348. </view>
  349. </view>
  350. <view class="flex items-center pr28rpx">
  351. <wd-divider vertical />
  352. <view class="ml6rpx text-28rpx text-[var(--them-color)] font-semibold">
  353. 搜索
  354. </view>
  355. </view>
  356. </view>
  357. </view>
  358. </template>
  359. </wd-navbar>
  360. <view
  361. class="h162rpx flex items-center justify-between bg-#F4FFD1 pl24rpx"
  362. :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }"
  363. >
  364. <scroll-view
  365. :scroll-into-view-offset="-150" scroll-x enable-passive scroll-with-animation
  366. class="scrollx w-90% flex-shrink-0 whitespace-nowrap" :scroll-into-view="`id${topScrollView}`"
  367. >
  368. <view class="flex items-end pb10rpx">
  369. <view
  370. v-for="item in classfiylist" :id="`id${item.code}`" :key="item.code"
  371. class="mr24rpx flex flex-col items-center justify-center" @click="handleTopNavChange(item)"
  372. >
  373. <view class="relative">
  374. <view class="box-border" :class="[topNavActive == item.code ? 'overflow-hidden border-solid border-[var(--them-color)] border-2rpx rounded-26rpx h84rpx w-84rpx' : 'h72rpx w-72rpx']">
  375. <image
  376. :src="item.icon"
  377. class="h-full w-full"
  378. />
  379. </view>
  380. <view v-if="!item.children" class="absolute left-0 top-0 h-full w-full flex items-center justify-center rounded-26rpx bg-[rgba(0,0,0,0.6)] text-16rpx text-white">
  381. 敬请期待
  382. </view>
  383. </view>
  384. <view
  385. class="mt16rpx text-22rpx"
  386. :class="[topNavActive == item.code ? 'bg-[var(--them-color)] rounded-18rpx px-8rpx py2rpx text-white text-24rpx' : '']"
  387. >
  388. {{ item.name }}
  389. </view>
  390. </view>
  391. </view>
  392. </scroll-view>
  393. <view
  394. class="right-nav box-border h144rpx w64rpx flex flex-shrink-0 flex-col items-center justify-center px20rpx text-24rpx font-semibold"
  395. @click="show = true"
  396. >
  397. 展开
  398. <image :src="`${StaticUrl}/xia.png`" class="mt20rpx h20rpx w20rpx" />
  399. </view>
  400. <wd-popup v-model="show" position="top" custom-style="border-radius:32rpx;">
  401. <view
  402. class="box-border bg-#F4FFD1 p24rpx"
  403. :style="{ paddingTop: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 12}px` }"
  404. >
  405. <view class="mb24rpx mt24rpx text-28rpx font-semibold">
  406. 全部一级分类
  407. </view>
  408. <view class="h400rpx overflow-y-scroll">
  409. <view class="grid grid-cols-5 box-border gap-x-24rpx gap-y-24rpx">
  410. <view
  411. v-for="item in classfiylist" :key="item.code"
  412. class="box-border h150rpx w114rpx flex flex-col items-center justify-center"
  413. @click="handleTopNavChange(item)"
  414. >
  415. <image
  416. :src="item.icon"
  417. :class="[topNavActive == item.code ? 'overflow-hidden border-solid border-[var(--them-color)] border-2rpx rounded-26rpx h88rpx w-88rpx' : 'h76rpx w-76rpx']"
  418. />
  419. <view
  420. class="mt16rpx whitespace-nowrap text-nowrap text-22rpx"
  421. :class="[topNavActive == item.code ? 'bg-[var(--them-color)] rounded-18rpx px-8rpx py2rpx text-white text-24rpx' : '']"
  422. >
  423. {{ item.name }}
  424. </view>
  425. </view>
  426. </view>
  427. </view>
  428. <view class="mt24rpx w-full flex items-center justify-center" @click="show = false">
  429. <view class="mr8rpx text-24rpx">
  430. 点击收起
  431. </view>
  432. <wd-icon name="arrow-down" size="18px" />
  433. </view>
  434. </view>
  435. </wd-popup>
  436. </view>
  437. <view class="wraper">
  438. <scroll-view class="w200rpx" :scroll-into-view-offset="-150" enable-passive scroll-with-animation scroll-y :scroll-into-view="`id${leftActive}`">
  439. <view v-for="item in categories" :id="`id${item.code}`" :key="item.code" :class="[item.code == leftActive ? 'bg-white' : '']" class="relative h100rpx flex items-center justify-center whitespace-nowrap text-28rpx" @click="handleLeftChange(item)">
  440. {{ item.name }}
  441. <view v-if="item.code == leftActive" class="absolute left-0 top-20rpx h60rpx w8rpx rounded-4rpx bg-[var(--them-color)]" />
  442. </view>
  443. </scroll-view>
  444. <view class="content">
  445. <view class="p20rpx">
  446. <image :src="`${StaticUrl}/class.png`" class="h144rpx w-full" @click="useGlobalToast().show('敬请期待 !')" />
  447. <view class="my20rpx flex items-center justify-end rounded-16rpx bg-#F6F6F6 px20rpx py8rpx">
  448. <view class="mr40rpx text-24rpx">
  449. 销量
  450. </view>
  451. <wd-sort-button v-model="sortClassBtn" :line="false" title="价格" />
  452. </view>
  453. </view>
  454. <view class="relative">
  455. <scroll-view
  456. :lower-threshold="100"
  457. :refresher-triggered="isTopLoading" :scroll-top="scrollTop"
  458. :style="{ height: `calc(100vh - ${navHeight} - 700rpx)` }" enable-passive scroll-y scroll-anchoring refresher-enabled :throttle="false"
  459. :scroll-into-view="`class${goodsInTo}`"
  460. @refresherrefresh="handleSrollTop"
  461. @scrolltolower="handlScrollBottom"
  462. >
  463. <view v-if="productList.length" class="p20rpx">
  464. <view v-for="item in productList" :id="`class${item.prodId}`" :key="item.id" class="relative">
  465. <view class="flex" @click="handleGo(item)">
  466. <view class="mr20rpx h172rpx w172rpx flex-shrink-0 overflow-hidden rounded-16rpx bg-#F6F6F6">
  467. <image :src="item.pic" lazy-load class="h-full w-full" />
  468. </view>
  469. <view class="flex-1">
  470. <view class="text-left text-28rpx font-semibold">
  471. <!-- <view v-for="i in 2" :key="i" class="mr5px inline-block">
  472. <wd-tag type="primary">
  473. 新品{{ i }}
  474. </wd-tag>
  475. </view> -->
  476. {{ item.prodName }}
  477. </view>
  478. <view class="text-22rpx text-#AAAAAA">
  479. <view class="mt10rpx flex items-center">
  480. <view>{{ item.spec }}</view>
  481. </view>
  482. <view class="mt6rpx">
  483. 已售 {{ item.soldNum }}+
  484. </view>
  485. </view>
  486. <view class="flex items-center justify-between">
  487. <view class="text-#FF4D3A font-semibold">
  488. <text class="text-24rpx">
  489. </text> <text class="text-36rpx">
  490. {{ item.channelProdPrice }}
  491. </text>
  492. </view>
  493. <view v-if="!item.num">
  494. <view v-if="item.spuStock" @click.stop="handleAddCart($event, item)">
  495. <image :src="`${StaticUrl}/cart-yes.png`" class="h52rpx w52rpx" />
  496. </view>
  497. <view v-else>
  498. <image :src="`${StaticUrl}/cart-no.png`" class="h52rpx w52rpx" />
  499. </view>
  500. </view>
  501. <view v-else>
  502. <view class="flex items-center">
  503. <image
  504. :src="` ${StaticUrl}/sub-cart.png`"
  505. class="h44rpx w44rpx"
  506. @click.stop="handleSubCart($event, item)"
  507. />
  508. <view class="box-border h44rpx w84rpx flex items-center justify-center border border-#F0F0F0 border-solid text-24rpx text-#AAAAAA">
  509. {{ item.num }}
  510. </view>
  511. <image
  512. :src="` ${StaticUrl}/add-cart.png`"
  513. class="h44rpx w44rpx"
  514. @click.stop="handleAddCart($event, item)"
  515. />
  516. </view>
  517. </view>
  518. </view>
  519. </view>
  520. </view>
  521. <view class="line">
  522. <wd-divider color="#F0F0F0" />
  523. </view>
  524. <view v-if="!item.spuStock" class="absolute left-0 top-0 z-1 h-full w-full flex items-center bg-[rgba(255,255,255,.6)]">
  525. <view class="h172rpx w172rpx flex items-center justify-center">
  526. <view class="h36rpx w112rpx flex items-center justify-center rounded-16rpx bg-[rgba(0,0,0,.6)] text-28rpx text-white">
  527. 已售罄
  528. </view>
  529. </view>
  530. </view>
  531. <view v-if="!item.skuList.some((it) => it.saleStatus)" class="absolute left-0 top-0 z-1 h-full w-full flex items-center bg-[rgba(255,255,255,.6)]">
  532. <view class="h172rpx w172rpx flex items-center justify-center">
  533. <view class="h36rpx w112rpx flex items-center justify-center rounded-16rpx bg-[rgba(0,0,0,.6)] text-28rpx text-white">
  534. 不可售
  535. </view>
  536. </view>
  537. </view>
  538. </view>.
  539. </view>
  540. <StatusTip v-else tip="暂无内容" />
  541. <view v-if="goodsLoading == 'finished' || isTopLoading" class="h-40vh" />
  542. </scroll-view>
  543. <view v-if="goodsLoading == 'loading' || isTopLoading" class="absolute left-0 top-0 z-10 h-full w-full flex items-center justify-center bg-white">
  544. <wd-loading color="#9ED605" :size="20" />
  545. </view>
  546. </view>
  547. </view>
  548. </view>
  549. <view
  550. class="fixedShadow fixed bottom-60rpx left-0 z-100 box-border w-full flex items-center justify-between rounded-t-16rpx bg-white px24rpx pb60rpx pt10rpx"
  551. >
  552. <view class="ios w-full flex items-center justify-between">
  553. <view class="flex items-center" @click="cartPopup = true">
  554. <image :src="`${StaticUrl}/cart-lanzi.png`" class="cart-box h100rpx w100rpx" />
  555. </view>
  556. <view class="flex items-center">
  557. <view class="flex items-center font-semibold">
  558. <view class="text-22rpx text-#222">
  559. 总计:
  560. </view>
  561. <view class="flex items-baseline text-24rpx text-#FF4A39">
  562. <text class="text-36rpx">
  563. {{ totalProduct?.price || '0.00' }}
  564. </text>
  565. </view>
  566. </view>
  567. <view class="ml20rpx w160rpx">
  568. <wd-button block size="large" @click="handlePay">
  569. 结算
  570. </wd-button>
  571. </view>
  572. </view>
  573. </view>
  574. </view>
  575. <Zpopup v-model="cartPopup" :zindex="99">
  576. <view class="ios h800rpx overflow-y-scroll">
  577. <view class="p24rpx">
  578. <view
  579. v-for="item in cartList" :key="item.id" class="relative mt20rpx box-border flex items-center overflow-hidden rounded-16rpx bg-white p24rpx"
  580. >
  581. <view class="flex flex-1">
  582. <image
  583. :src="item.pic"
  584. class="h206rpx w200rpx flex-shrink-0"
  585. @click.stop="router.push({ name: 'xsb-goods', params: { id: String(item.prodId) } })"
  586. />
  587. <view class="ml20rpx flex-1">
  588. <view class="text-left text-28rpx font-semibold">
  589. <!-- <view v-for="i in 2" :key="i" class="mr5px inline-block">
  590. <wd-tag type="danger">
  591. 惊喜回馈
  592. </wd-tag>
  593. </view> -->
  594. {{ item.skuName }}
  595. </view>
  596. <view class="mt14rpx text-24rpx text-#AAAAAA">
  597. 规格:{{ item.spec }}
  598. </view>
  599. <view class="mt14rpx flex items-center justify-between">
  600. <view class="text-36rpx text-#FF4A39 font-semibold">
  601. ¥{{ item.price }}
  602. </view>
  603. <!-- <wd-input-number v-model="item.num" disable-input @change="handleChangeNum($event, item)" /> -->
  604. <view v-if="item.shopSkuStocks !== '0' && item.isDelete !== '1'" class="flex items-center">
  605. <image
  606. :src="` ${StaticUrl}/sub-cart.png`"
  607. class="h44rpx w44rpx"
  608. @click.stop="handleSub(item)"
  609. />
  610. <view class="box-border h44rpx w84rpx flex items-center justify-center border border-#F0F0F0 border-solid text-24rpx text-#AAAAAA">
  611. {{ item.num }}
  612. </view>
  613. <image
  614. :src="` ${StaticUrl}/add-cart.png`"
  615. class="h44rpx w44rpx"
  616. @click.stop="handleAdd(item)"
  617. />
  618. </view>
  619. </view>
  620. </view>
  621. </view>
  622. <view v-if="item.shopSkuStocks == '0' || item.isDelete == '1'" class="absolute left-0 top-0 z-1 h-full w-full bg-[rgba(255,255,255,.6)]">
  623. <view class="relative w-full flex items-center justify-center">
  624. <view class="rounded-16rpx bg-[rgba(0,0,0,.5)] p20rpx text-white">
  625. {{ item.shopSkuStocks == '0' ? '商品已售罄' : '商品已删除' }}
  626. </view>
  627. <view class="absolute bottom-20rpx right-20rpx">
  628. <wd-button @click="handleDelCartGoods(item)">
  629. 删除商品
  630. </wd-button>
  631. </view>
  632. </view>
  633. </view>
  634. </view>
  635. </view>
  636. <StatusTip v-if="!cartList.length" tip="暂无内容" />
  637. <view class="h320rpx" />
  638. </view>
  639. </Zpopup>
  640. <selectSku v-model:show="selectGoods" v-model:sku-id="selectSkuId" v-model:select-goods-num="SelectGoodsNum" :goods-info="goodsInfo!">
  641. <template #footer>
  642. <view class="box-border w-full flex items-center justify-between py20rpx">
  643. <view class="w-48%">
  644. <wd-button plain hairline block @click="selectGoods = false">
  645. 取消
  646. </wd-button>
  647. </view>
  648. <view class="w-48%">
  649. <wd-button block @click="handleSkuAddCart">
  650. 加入购物车
  651. </wd-button>
  652. </view>
  653. </view>
  654. </template>
  655. </selectSku>
  656. <view v-if="showball" class="ball">
  657. <image :src="`${StaticUrl}/cart-yes.png`" class="cart-img h52rpx w52rpx" />
  658. </view>
  659. </view>
  660. </template>
  661. <style scoped lang="scss">
  662. .right-nav {
  663. background: linear-gradient(180deg, #FAFFEC 0%, #F6FFDE 11%, #E7FFA5 100%);
  664. box-shadow: -10rpx 0rpx 12rpx 2rpx rgba(0, 0, 0, 0.07);
  665. }
  666. .fixedShadow{
  667. box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(0,0,0,0.05);
  668. }
  669. .wraper {
  670. display: flex;
  671. height: calc(100vh - var(--window-top) - v-bind(navHeight) - 390rpx - var(--window-bottom));
  672. height: calc(100vh - var(--window-top) - constant(safe-area-inset-bottom) - v-bind(navHeight) - 390rpx - var(--window-bottom));
  673. height: calc(100vh - var(--window-top) - env(safe-area-inset-bottom) - v-bind(navHeight) - 390rpx - var(--window-bottom));
  674. }
  675. .content {
  676. flex: 1;
  677. background: #fff;
  678. }
  679. @keyframes moveX {
  680. to {
  681. transform: translateX(v-bind(x));
  682. }
  683. }
  684. @keyframes moveY {
  685. to {
  686. transform: translateY(v-bind(y));
  687. }
  688. }
  689. .ball {
  690. position: fixed;
  691. z-index: 80;
  692. left: v-bind(left);
  693. top: v-bind(top);
  694. animation: moveX .5s linear forwards;
  695. }
  696. .cart-img {
  697. animation: moveY .5s cubic-bezier(1,-1.26,1,1) forwards;
  698. }
  699. </style>