index.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <route lang="json5">
  2. {
  3. style: {
  4. navigationBarTitleText: '购物车',
  5. navigationBarBackgroundColor: '#fff',
  6. },
  7. }
  8. </route>
  9. <script setup lang="ts">
  10. import TiltedButton from '@/components/tilted-button.vue'
  11. import Product from '../components/product.vue'
  12. import { shoppingBag } from '@designer-hub/assets/src/assets/svgs/index'
  13. import InvertedTrapezoidButton from '@/components/inverted-trapezoid-button.vue'
  14. import TrapeziumButton from '@/components/trapezium-button.vue'
  15. import {
  16. createProductItemBuy,
  17. deleteProductItemBuy,
  18. getProductItemBuy,
  19. productPlacing,
  20. } from '../../../../core/libs/requests'
  21. import PageHelper from '@/components/page-helper.vue'
  22. import BottomAppBar from '@/components/bottom-app-bar.vue'
  23. import { useUserStore } from '../../../../store'
  24. import { useRouter } from '../../../../core/utils/router'
  25. import { storeToRefs } from 'pinia'
  26. import { requestToast } from '../../../../core/utils/common'
  27. import type { ComponentExposed } from 'vue-component-type-helpers'
  28. import ButtonEvo from '@/components/button-evo.vue'
  29. import { usePermissions } from '../../../../composables/permissions'
  30. const { clickByPermission } = usePermissions()
  31. const pageHelperRef = ref<ComponentExposed<typeof PageHelper>>()
  32. const userStore = useUserStore()
  33. const router = useRouter()
  34. const { userInfo } = storeToRefs(userStore)
  35. const selected = ref([])
  36. const points = computed(() =>
  37. selected.value.reduce((acc, item) => acc + item.points * item.nums, 0),
  38. )
  39. const query = ref({ userId: userInfo.value?.userId })
  40. const handleSelect = (product) => {
  41. if (selected.value.map((it) => it.productId).includes(product.productId)) {
  42. selected.value = selected.value.filter(({ productId }) => productId !== product.productId)
  43. } else {
  44. selected.value = [...selected.value, product]
  45. }
  46. }
  47. const handleDelete = async (product: any) => {
  48. await requestToast(
  49. () =>
  50. deleteProductItemBuy({
  51. doList: [
  52. {
  53. productId: product.productId,
  54. userId: userInfo.value.userId,
  55. id: product.id,
  56. deleted: true,
  57. },
  58. ],
  59. }),
  60. {
  61. successTitle: '删除成功',
  62. success: true,
  63. },
  64. )
  65. await pageHelperRef.value?.refresh()
  66. }
  67. const handleProductNumsChange = async (nums, product) => {
  68. const changeNums = nums - product.nums
  69. if (changeNums > 0) {
  70. await createProductItemBuy({
  71. doList: [
  72. {
  73. userId: userInfo.value.userId,
  74. productId: product.productId,
  75. points: product.points,
  76. nums: Math.abs(changeNums),
  77. },
  78. ],
  79. })
  80. if (selected.value.map((it) => it.productId).includes(product.productId)) {
  81. selected.value = selected.value.map((it) =>
  82. it.productId === product.productId ? { ...it, nums } : it,
  83. )
  84. }
  85. } else {
  86. await deleteProductItemBuy({
  87. doList: [
  88. {
  89. productId: product.productId,
  90. userId: userInfo.value.userId,
  91. nums: Math.abs(changeNums),
  92. },
  93. ],
  94. })
  95. if (selected.value.map((it) => it.productId).includes(product.productId)) {
  96. selected.value = selected.value.map((it) =>
  97. it.productId === product.productId ? { ...it, nums } : it,
  98. )
  99. }
  100. }
  101. await pageHelperRef.value?.refresh()
  102. }
  103. const handlePlaceOrder = async () => {
  104. if (!selected.value.length) {
  105. await uni.showToast({ title: '请选择商品', icon: 'none' })
  106. return ''
  107. }
  108. const { code, data: res } = await requestToast(() =>
  109. productPlacing({
  110. isShoppingCart: 1,
  111. userId: userInfo.value.userId,
  112. item: 3,
  113. list: selected.value.map(
  114. ({ productId, prodcutName, productCoverImgUrl, nums, points, vendorId }) => ({
  115. productId,
  116. productName: prodcutName,
  117. orderImgUrl: productCoverImgUrl,
  118. nums,
  119. points,
  120. vendorId,
  121. }),
  122. ),
  123. couponList: [],
  124. }),
  125. )
  126. if (code === 0) {
  127. // router.push(`/pages/home/mall/confirm-order`)
  128. // await deleteProductItemBuy({
  129. // doList: selected.value.map(({ productId }) => ({
  130. // productId,
  131. // deleted: true,
  132. // userId: userInfo.value.userId,
  133. // })),
  134. // })
  135. pageHelperRef.value?.reload()
  136. router.push(`/pages/home/mall/confirm-order/index?data=${JSON.stringify(res)}`)
  137. }
  138. }
  139. </script>
  140. <template>
  141. <view class="flex-grow flex flex-col gap-14 bg-white px-3.5 py-6">
  142. <PageHelper
  143. ref="pageHelperRef"
  144. :request="getProductItemBuy"
  145. :query="query"
  146. class="flex-grow flex flex-col"
  147. >
  148. <template #default="{ source }">
  149. <div class="flex-grow flex flex-col gap-8">
  150. <!-- {{ selected }} -->
  151. <template v-for="(it, i) in source.list" :key="i">
  152. <wd-swipe-action>
  153. <div class="flex gap-3">
  154. <div class="flex items-center" @click="handleSelect(it)">
  155. <div
  156. class="w-4 h-4 rounded-full border border-black/60 border-solid"
  157. :class="`${selected.map((it) => it.productId).includes(it.productId) ? 'bg-black' : ''}`"
  158. ></div>
  159. </div>
  160. <div class="w-[110px] h-[110px] bg-[#f6f6f6] rounded-2xl overflow-hidden relative">
  161. <wd-img width="100%" height="100%" :src="it.productCoverImgUrl"></wd-img>
  162. <div
  163. v-if="it.status"
  164. class="absolute bottom-0 w-full h-5.5 bg-[#D7D7D7] flex items-center justify-center"
  165. >
  166. <div
  167. class="text-black/60 text-xs font-normal font-['PingFang_SC'] leading-normal"
  168. >
  169. 已下架
  170. </div>
  171. </div>
  172. <div
  173. v-if="it.deleted"
  174. class="absolute bottom-0 w-full h-5.5 bg-[#D7D7D7] flex items-center justify-center"
  175. >
  176. <div
  177. class="text-black/60 text-xs font-normal font-['PingFang_SC'] leading-normal"
  178. >
  179. 已失效
  180. </div>
  181. </div>
  182. </div>
  183. <div class="flex flex-col justify-between flex-1">
  184. <div
  185. class="text-black/40 text-base font-normal font-['PingFang_SC'] leading-normal"
  186. >
  187. {{ it.prodcutName }}
  188. </div>
  189. <div class="flex items-center gap-1.25">
  190. <div
  191. class="text-[#ef4343] text-[22px] font-normal font-['D-DIN_Exp'] leading-normal"
  192. >
  193. {{ it.points }}
  194. </div>
  195. <div
  196. class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-[34px]"
  197. >
  198. 积分
  199. </div>
  200. <div class="flex-1"></div>
  201. <!-- {{ it.nums }} -->
  202. <wd-input-number
  203. :model-value="Number(it.nums)"
  204. @update:model-value="(e) => handleProductNumsChange(e, it)"
  205. />
  206. </div>
  207. </div>
  208. </div>
  209. <template #right>
  210. <view class="h-full">
  211. <view
  212. class="inline-block h-full bg-[#ef4343] text-white flex items-center px-5"
  213. @click="handleDelete(it)"
  214. >
  215. 删除
  216. </view>
  217. </view>
  218. </template>
  219. </wd-swipe-action>
  220. </template>
  221. </div>
  222. </template>
  223. </PageHelper>
  224. <BottomAppBar fixed border>
  225. <div class="h-[63px] bg-white backdrop-blur-[20px] flex items-center justify-between">
  226. <div class="flex items-end gap-1.25">
  227. <div class="text-[#ef4343] text-2xl font-normal font-['D-DIN_Exp'] leading-6">
  228. {{ points }}
  229. </div>
  230. <div class="text-black text-base font-normal font-['PingFang_SC'] leading-5">积分</div>
  231. </div>
  232. <div class="" @click="clickByPermission('mallExchange', () => handlePlaceOrder())">
  233. <ButtonEvo>
  234. <div
  235. class="w-[65px] h-[22px] text-white text-base font-normal font-['PingFang_SC'] leading-tight"
  236. >
  237. 去结算
  238. </div>
  239. </ButtonEvo>
  240. </div>
  241. </div>
  242. </BottomAppBar>
  243. </view>
  244. </template>
  245. <style scoped lang="scss"></style>