index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. <script lang="ts" setup>
  2. import {getRecommendList} from "~/apis/merchant";
  3. import MerchantProductCard from "~/pages/store/home/components/MerchantProductCard.vue";
  4. import {deleteCartItem, getCartCount, getCartList} from "~/apis/user";
  5. import type {ShoppingResult} from "~/apis/model/shopping.model";
  6. import FPrice from "~/components/FPrice/FPrice.vue";
  7. import FButton from "~/components/FButton/FButton.vue";
  8. import CXBYaojinTag from "~/components/CXBYaojinTag/CXBYaojinTag.vue";
  9. import {
  10. DyProductModel, IProductDetail,
  11. JdProductModel,
  12. SuNingProductModel,
  13. TaobaoProductThirdPartyWaresModel, VipProductModel
  14. } from "~/apis/model/product.model";
  15. import {DcProductModel} from "~/apis/model/dacang.model";
  16. import {encodeBase64} from "~/utils/http/helper";
  17. import {CDN_URL} from "~/config/app";
  18. import {uniq} from "lodash-es";
  19. import {cartChange} from "~/apis/order.api";
  20. import type CXBBackTop from "~/components/CXBBackTop/CXBBackTop.vue";
  21. const gouwucheImage = CDN_URL + '/static/assets/gouwuche.png'
  22. const like_adorn_220628Image = CDN_URL + '/static/assets/like_adorn_220628.png'
  23. const pageStore = usePageStoreWidthOut()
  24. const userStore = useUserStore()
  25. const state = reactive({
  26. recommendList: [],
  27. currentPage: 1,
  28. pageSize: 10,
  29. total: 0,
  30. totalPage: 0,
  31. totalCartCount: 0,
  32. totalPrice: 0,
  33. selectAllIndeterminate: false,
  34. cart_id: [],
  35. isManage: true,
  36. currentType: '',
  37. })
  38. // 距离顶部距离
  39. let Scroll_X = ref(0)
  40. const shopping = ref<ShoppingResult>()
  41. onBeforeMount(() => {
  42. if (!userStore.uid) {
  43. return uni.navigateTo({
  44. url: '/user/login/index'
  45. })
  46. }
  47. })
  48. onLoad((options) => {
  49. uni.$on('cart-reload', () => {
  50. // console.log('新商品添加...')
  51. state.cart_id = []
  52. loadCartList()
  53. })
  54. state.cart_id = []
  55. loadCartList()
  56. })
  57. onShow(() => {
  58. // pageStore.setPageConfig({
  59. // orderBack: {
  60. // type: 'tab',
  61. // url: '/pages/order_addcart/index'
  62. // }
  63. // })
  64. if (!state.isManage) {
  65. state.isManage = true
  66. }
  67. loadCartCount()
  68. loadList('reload')
  69. })
  70. function loadList(action: 'page' | 'reload', callback?: (items) => void) {
  71. const params = {
  72. page: state.currentPage,
  73. limit: state.pageSize
  74. }
  75. if (action === 'reload') {
  76. params.page = 1
  77. }
  78. getRecommendList({
  79. ...params
  80. }).then(res => {
  81. if (action === 'page') {
  82. state.recommendList = state.recommendList.concat(res.list)
  83. }
  84. if (action === 'reload') {
  85. // state.list = state.list.concat(res.list)
  86. state.recommendList = res.list
  87. }
  88. state.totalPage = Math.ceil(res.count / state.pageSize);
  89. state.status = 'more'
  90. if (callback) {
  91. callback(res.list)
  92. }
  93. })
  94. }
  95. function handleScrollToLower() {
  96. state.status = 'loading';
  97. state.currentPage += 1;
  98. // console.log(state.totalPage)
  99. if (state.currentPage > state.totalPage) {
  100. state.status = 'noMore';
  101. } else {
  102. setTimeout(() => {
  103. loadList('page')
  104. }, 300)
  105. }
  106. }
  107. onReachBottom(() => {
  108. handleScrollToLower()
  109. })
  110. // 加载购物车数据
  111. function loadCartList() {
  112. uni.showLoading({
  113. title: '加载中',
  114. icon: 'none'
  115. })
  116. // state.totalCartCount = 0
  117. getCartList().then(res => {
  118. uni.hideLoading()
  119. shopping.value = res
  120. // console.log(res)
  121. shopping.value?.list.forEach((shopItem, index) => {
  122. // shopItem.allCheck = true
  123. shopItem.allCheck = false
  124. shopItem.indeterminate = false
  125. shopItem.list.forEach(goodItem => {
  126. goodItem.check = false
  127. // state.cart_id.push(goodItem.cart_id)
  128. // if (goodItem.cart_num === 1) {}
  129. // state.totalCartCount += Number.parseInt(goodItem.cart_num)
  130. })
  131. // console.log(shopItem)
  132. })
  133. // cartAllCheck("all")
  134. // if (shopping.value) {
  135. // handleSelectAll()
  136. // }
  137. })
  138. }
  139. const hasShopping = computed(() => {
  140. return shopping.value && shopping.value?.list.length > 0
  141. })
  142. const totalCartInfo = computed(() => {
  143. let totalPrice = 0
  144. let goodsNum = 0
  145. if (shopping.value && shopping.value?.list.length > 0) {
  146. for (let i = 0; i < shopping.value?.list.length; i++) {
  147. for (let j = 0; j < shopping.value?.list[i].list.length; j++) {
  148. let num = Number.parseInt(shopping.value?.list[i].list[j].cart_num);
  149. let price = Number.parseFloat(shopping.value?.list[i].list[j].productAttr.price)
  150. totalPrice += (num * price)
  151. goodsNum += num
  152. }
  153. }
  154. }
  155. return {
  156. totalPrice,
  157. goodsNum
  158. }
  159. })
  160. const totalMoney = ref(0)
  161. const isAllSelect = ref(false)
  162. function handleGoodsItemCheck(check) {
  163. cartAllCheck('single')
  164. }
  165. function shopCheck(shopItem) {
  166. // console.log('shoo...')
  167. // if (type === 'active') {
  168. // console.log('shooo...')
  169. // if (shopItem.allCheck) {
  170. // console.log(shopItem)
  171. // shopItem.list.forEach((good, index) => {
  172. // good.check = true
  173. // })
  174. // // cartAllCheck('single')
  175. //
  176. // } else {
  177. // shopItem.list.forEach((good, index) => {
  178. // good.check = false
  179. // })
  180. // }
  181. // }
  182. }
  183. function handleShopTitleClick(shopItem) {
  184. if (shopItem.allCheck) {
  185. shopItem.list.forEach((good, index) => {
  186. good.check = true
  187. })
  188. } else {
  189. shopItem.list.forEach((good, index) => {
  190. good.check = false
  191. })
  192. }
  193. }
  194. function cartAllCheck(type: 'single' | 'all') {
  195. let allArr = []
  196. let totalMoney = 0
  197. let totalNum = 0
  198. state.currentType = type
  199. // 解决下单多次
  200. state.cart_id = []
  201. // console.log(type)
  202. shopping.value?.list.forEach((goods, index) => {
  203. if (type === 'single') {
  204. // 如果单选的情况下, 获取已选中的
  205. let tempArr = goods.list.filter(goodItem => {
  206. // if (goodItem.check) {
  207. return goodItem.check === true
  208. // }
  209. })
  210. // console.log(tempArr)
  211. if (goods.list.length === tempArr.length) {
  212. goods.allCheck = true
  213. allArr.push(goods)
  214. // goods.indeterminate = false
  215. }
  216. if (tempArr.length < goods.list.length) {
  217. goods.allCheck = false
  218. }
  219. // if (tempArr.length > 0) {
  220. // goods.indeterminate = true
  221. // }
  222. if (tempArr.length <= 0) {
  223. goods.allCheck = false
  224. // state.currentType = 'all'
  225. // state.indeterminate = false
  226. }
  227. } else {
  228. goods.list.forEach(goodItem => {
  229. goodItem.check = isAllSelect.value
  230. })
  231. goods.allCheck = isAllSelect.value
  232. if (goods.allCheck) {
  233. allArr.push(goods)
  234. }
  235. }
  236. // 总金额|总数
  237. goods.list.forEach(goodItem => {
  238. if (goodItem.check) {
  239. totalMoney += (goodItem.productAttr.price * goodItem.cart_num)
  240. totalNum += Number.parseFloat(goodItem.cart_num)
  241. state.cart_id.push(goodItem.cart_id)
  242. }
  243. })
  244. })
  245. isAllSelect.value = allArr.length === shopping.value?.list.length
  246. // state.totalCartCount = totalNum
  247. state.totalPrice = totalMoney
  248. }
  249. function reTotal() {
  250. let allArr = []
  251. let totalMoney = 0
  252. let totalNum = 0
  253. shopping.value?.list.forEach((goods, index) => {
  254. // 总金额|总数
  255. goods.list.forEach(goodItem => {
  256. if (goodItem.check) {
  257. totalMoney += (goodItem.productAttr.price * goodItem.cart_num)
  258. // state.cart_id.push(goodItem.cart_id)
  259. }
  260. totalNum += Number.parseFloat(goodItem.cart_num)
  261. })
  262. })
  263. // isAllSelect.value = allArr.length === shopping.value?.list.length
  264. // state.totalCartCount = totalNum
  265. loadCartCount()
  266. state.totalPrice = totalMoney
  267. }
  268. function handleSelectAll(checked: boolean) {
  269. cartAllCheck('all')
  270. }
  271. function loadCartCount() {
  272. // pageStore.setPageConfig({
  273. // orderBack: {
  274. // type: 'tab',
  275. // url: '/pages/order_addcart/index'
  276. // }
  277. // })
  278. getCartCount().then(res => {
  279. // console.log(res)
  280. // state.cartCount = res[0].count
  281. state.totalCartCount = res[0].count
  282. }).catch(error => {
  283. // console.log(error)
  284. if (error === '请登录') {
  285. setTimeout(() => {
  286. uni.navigateTo({
  287. url: '/pages/user/login/index'
  288. })
  289. }, 500)
  290. }
  291. })
  292. }
  293. function handleManageCart() {
  294. state.isManage = !state.isManage
  295. }
  296. function handleSubmit() {
  297. // console.log(state.isManage)
  298. if (!state.isManage) {
  299. handleDelete()
  300. } else { // submit
  301. state.cart_id = uniq(state.cart_id)
  302. // console.log(state.cart_id)
  303. if (state.cart_id && state.cart_id.length > 0) {
  304. uni.navigateTo({
  305. url: `/pages/order-confirm/index?cartId=${state.cart_id.join(',')}`
  306. })
  307. } else {
  308. return uni.showToast({
  309. title: '请选择商品',
  310. icon: 'none'
  311. })
  312. }
  313. }
  314. }
  315. function handleDelete() {
  316. // const cart_id = <any>[]
  317. shopping.value?.list.forEach(shopItem => {
  318. shopItem.list.forEach(goodItem => {
  319. if (goodItem.check) {
  320. state.cart_id.push(goodItem.cart_id)
  321. }
  322. })
  323. })
  324. state.cart_id = uniq(state.cart_id)
  325. // console.log(cart_id)
  326. if (state.cart_id.length === 0) {
  327. return uni.showToast({
  328. title: '请选择产品',
  329. icon: "none"
  330. })
  331. } else {
  332. uni.showModal({
  333. title: '温馨提示',
  334. content: '确认将宝贝删除?',
  335. success: (res) => {
  336. if (res.confirm) {
  337. deleteCartItem(state.cart_id).then(res => {
  338. uni.showToast({
  339. title: '删除成功'
  340. })
  341. state.isManage = true
  342. state.cart_id = []
  343. state.totalPrice = ''
  344. loadCartList()
  345. })
  346. } else if (res.cancel) {
  347. }
  348. }
  349. })
  350. }
  351. }
  352. function handleProductItemClick(
  353. item:
  354. JdProductModel
  355. & DcProductModel
  356. & DyProductModel
  357. & SuNingProductModel
  358. & TaobaoProductThirdPartyWaresModel
  359. & VipProductModel
  360. ) {
  361. // function navigateToDetail(params) {
  362. // let otherDetailUrl = `/pages/store/product/other`
  363. // return uni.navigateTo({
  364. // url: `${otherDetailUrl}?params=${params}`
  365. // })
  366. // }
  367. // 大仓
  368. uni.navigateTo({
  369. url: `/pages/store/product/detail?id=${item.product_id}`
  370. })
  371. }
  372. function handleNumberChange(num, goodItem) {
  373. // console.log(goodItem)
  374. uni.showLoading()
  375. // console.log(num)
  376. cartChange(goodItem.cart_id, num).then(res => {
  377. reTotal()
  378. uni.hideLoading()
  379. })
  380. // console.log(goodItem)
  381. // console.log(num)
  382. // const
  383. // goodItem.productAttr.price = goodItem.productAttr.price * num
  384. // goodItem.productAttr.price = goodItem.productAttr.price * goodItem.cart_num
  385. }
  386. const headerClass = ref('')
  387. onPageScroll((page) => {
  388. // console.log('滚轮事件触发了',page.scrollTop.toFixed());
  389. // console.log(page.scrollTop.toFixed(),'距离顶部的距离')
  390. Scroll_X.value = Number(page.scrollTop.toFixed())
  391. if (page.scrollTop >= 76 ) {
  392. headerClass.value = 'bg-white !text-gray-900'
  393. } else {
  394. headerClass.value = ''
  395. }
  396. })
  397. const changeSku = ref(false)
  398. const openTestLog = ()=>{
  399. console.log('测试点击sku,多规模');
  400. changeSku.value = true
  401. }
  402. const closeTestLog = ()=>{
  403. console.log('测试点击sku,多规模');
  404. changeSku.value = false
  405. }
  406. </script>
  407. <template>
  408. <div v-if="changeSku" style="width: 100%; height: 100%; background-color: skyblue; margin-top: 100px;">
  409. <p>sku信息</p>
  410. <button @click="closeTestLog">关闭</button>
  411. </div>
  412. <div class="">
  413. <div
  414. v-if="hasShopping"
  415. class="bg-white h-10 fixed top-0 w-full z-1 flex justify-end "
  416. >
  417. <div class="pr-3">
  418. <FButton size="small"
  419. @click="handleManageCart"
  420. >
  421. <div>{{ state.isManage ? '管理' : '完成'}}</div>
  422. </FButton>
  423. </div>
  424. </div>
  425. <div
  426. v-if="!hasShopping"
  427. class="flex flex-col justify-center items-center bg-white rounded-lg gap-3 text-xs py-8">
  428. <div>
  429. <image :src="gouwucheImage" mode="widthFix" class="w-20 h-20"></image>
  430. </div>
  431. <div>
  432. 暂无商品,去添加喜欢的商品
  433. </div>
  434. </div>
  435. <div v-else class="mt-10">
  436. <div
  437. v-if="shopping && shopping.list"
  438. class="flex flex-col gap-4 p-3"
  439. >
  440. <div
  441. v-for="(shopItem, index) in shopping.list"
  442. :key="index"
  443. class="bg-white rounded-lg "
  444. >
  445. <div
  446. class="f-hairline-bottom flex items-center font-bold p-3"
  447. >
  448. <div @tap.stop="handleShopTitleClick(shopItem)">
  449. <nut-checkbox v-model="shopItem.allCheck"
  450. @change="(checked) => shopCheck( shopItem)"
  451. label="全选"
  452. class="!text-primary"
  453. >
  454. {{ shopItem.mer_name }}
  455. </nut-checkbox>
  456. </div>
  457. </div>
  458. <div v-for="(goodItem, goodIndex) in shopItem.list"
  459. :key="goodIndex"
  460. class="flex f-hairline-bottom p-3 gap-2"
  461. >
  462. <div class="flex">
  463. <nut-checkbox v-model="goodItem.check"
  464. @change="handleGoodsItemCheck"
  465. label="单选"
  466. class="!text-primary"
  467. ></nut-checkbox>
  468. <image
  469. @click="handleProductItemClick(goodItem)"
  470. :src="goodItem.product.image"
  471. mode="aspectFill" class="w-18 h-18 rounded"
  472. ></image>
  473. </div>
  474. <div class="flex flex-col gap-1 w-full">
  475. <div
  476. @click="handleProductItemClick(goodItem)"
  477. class="text-overflow line-clamp-2 text-xs">{{ goodItem.product.store_name }}</div>
  478. <div class="flex flex-col justify-start gap-1">
  479. <div
  480. class="text-[10px] text-gray min-w-5 p-1 items-center flex" @click="openTestLog">
  481. {{ goodItem.productAttr.sku }}
  482. </div>
  483. <div class="flex">
  484. <CXBYaojinTag :amount="goodItem.yanglao"/>
  485. </div>
  486. </div>
  487. <div class="flex justify-between ">
  488. <FPrice :price="goodItem.productAttr.price"
  489. ex-class="font-bold text-dark"
  490. />
  491. <nut-input-number v-model="goodItem.cart_num" @change="(num) => handleNumberChange(num, goodItem)"/>
  492. </div>
  493. </div>
  494. </div>
  495. </div>
  496. </div>
  497. </div>
  498. <CXBBackTop :Scroll_X="Scroll_X"/>
  499. <div class="pb-12">
  500. <div class="flex flex-row justify-center items-center gap-3 font-bold text-sm p-3 ">
  501. <image :src="like_adorn_220628Image" mode="widthFix" class="w-6 h-6"></image>
  502. <div>
  503. 猜你喜欢
  504. </div>
  505. <image :src="like_adorn_220628Image" mode="widthFix" class="w-6 h-6"></image>
  506. </div>
  507. <div class="pb-3 px-3" v-if="state.recommendList">
  508. <grid-view type="masonry" cross-axis-count="2" cross-axis-gap="10px" main-axis-gap="10px">
  509. <div v-for="(item, index) in state.recommendList"
  510. :key="index"
  511. @click="handleProductItemClick(item)"
  512. >
  513. <MerchantProductCard :item="item" />
  514. </div>
  515. </grid-view>
  516. <div class=" flex justify-center items-center text-[12px] text-gray-500"
  517. >
  518. <div v-if="state.status === 'loading'">
  519. 加载中...
  520. </div>
  521. <div v-if="state.status === 'noMore'">
  522. 没有更多了~
  523. </div>
  524. </div>
  525. </div>
  526. </div>
  527. </div>
  528. <div v-if="hasShopping"
  529. class="fixed bottom-0 w-full z-3">
  530. <div class="bg-white h-10 flex justify-between" v-if="shopping && shopping.list">
  531. <div class="flex justify-center items-center gap-2 pl-3" @tap.stop="handleSelectAll">
  532. <nut-checkbox v-model="isAllSelect"
  533. label="全选"
  534. class="!text-primary"
  535. >全选
  536. </nut-checkbox>
  537. <div class="text-xs text-gray">共 {{ state.totalCartCount }} 件</div>
  538. </div>
  539. <div class="flex justify-center items-center gap-2 pr-3">
  540. <div class="flex text-[12px]" v-if="state.isManage">
  541. 合计:
  542. <FPrice :price="state.totalPrice"></FPrice>
  543. <!-- {{totalCartInfo.totalPrice}}-->
  544. </div>
  545. <FButton
  546. @click="handleSubmit"
  547. size="small"
  548. :exClass="['rounded-full','!text-[14px]', 'text-white', 'bg-primary', 'w-full']"
  549. >
  550. {{ state.isManage? '去结算' : '删除'}}
  551. </FButton>
  552. </div>
  553. </div>
  554. </div>
  555. </template>
  556. <style>
  557. page {
  558. background-color: #f8f8f8;
  559. }
  560. </style>
  561. <route lang="yaml">
  562. style:
  563. navigationBarTitleText: 购物车
  564. enablePullDownRefresh: false
  565. </route>