classfiy.vue 25 KB

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