多租户商城-商户小程序端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1120 lines
33 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <template>
  2. <view class="content">
  3. <!-- 骨架屏 -->
  4. <u-skeleton
  5. el-color="#efefef"
  6. bg-color="#fff"
  7. :loading="loading && isFirstComeIn"
  8. :animation="true"
  9. ></u-skeleton>
  10. <global-loading />
  11. <!-- 购物车 -->
  12. <view class="u-skeleton">
  13. <view v-if="!isEmpty">
  14. <u-sticky bg-color="#fff">
  15. <view class="cart-bg u-skeleton-fillet">
  16. <view class="cart-num-box">
  17. <!-- <image
  18. class=" u-skeleton-fillet"
  19. src="https://wechat.hnthee.com/ceres-local-file/image/logo_wechat.png"
  20. ></image>-->
  21. <view>
  22. <text class="num-box u-skeleton-fillet">
  23. {{$t('common.totalitemnum',{"number":settleAccountsObj.allNum})}}
  24. </text>
  25. </view>
  26. <text
  27. class="btn-box "
  28. @click="showManage = !showManage"
  29. v-if="!showManage"
  30. >{{$t('common.manager')}}
  31. </text>
  32. <text
  33. class="btn-box"
  34. @click="showManage = !showManage"
  35. v-if="showManage"
  36. >{{$t('common.finish')}}
  37. </text>
  38. </view>
  39. </view>
  40. </u-sticky>
  41. <view class="cart-list-box">
  42. <view
  43. class="itemBox"
  44. v-for="(item, index) in dataList"
  45. :key="item.shopId"
  46. >
  47. <view
  48. class="item"
  49. v-if="item.skus.length >0"
  50. >
  51. <view class="shop-box">
  52. <image
  53. mode="aspectFill u-skeleton-fillet"
  54. v-if="item.selected === 1"
  55. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_select_active.png"
  56. class="cart-select-img"
  57. @click.stop="handleSelectShop(index,0)"
  58. ></image>
  59. <image
  60. mode="aspectFill u-skeleton-fillet"
  61. v-else
  62. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_select_normal.png"
  63. class="cart-select-img"
  64. @click.stop="handleSelectShop(index,1)"
  65. ></image>
  66. <view
  67. class="shop-name-box u-skeleton-fillet"
  68. @click="$jump(`${jumpObj.store}?storeId=${item.shopId}`)"
  69. >
  70. <image
  71. src="https://wechat.hnthee.com/ceres-local-file/image/cart_shop.png"
  72. class="shop-img"
  73. ></image>
  74. <text class="shop-name">{{ item.shopName }}</text>
  75. <image
  76. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_shop_forward.png"
  77. class="arrow-right-img"
  78. ></image>
  79. </view>
  80. </view>
  81. <view
  82. class="rulesBox flex-items"
  83. v-if="item.currentRules && item.currentRules.number"
  84. >
  85. <image
  86. class="mar-right-20"
  87. src="https://ceres.zkthink.com/static/images/zuheIcon.png"
  88. ></image>
  89. <view class="fs24 font-color-C83732">
  90. {{$t('common.cartzuhetips', {price:item.currentRules.price, number:item.currentRules.number})}}
  91. </view>
  92. </view>
  93. <view
  94. v-for="(skuItem, cIndex) in dataList[index].skus"
  95. class="product-list-box "
  96. >
  97. <view
  98. class="pro-item"
  99. @click="$jump(`${jumpObj.detail}?shopId=${item.shopId}&productId=${skuItem.productId}&skuId=${skuItem.skuId}`)"
  100. >
  101. <image
  102. mode="aspectFill u-skeleton-fillet"
  103. v-if="skuItem.selected == 1"
  104. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_select_active.png"
  105. @click.stop="handleSelectSku(index,cIndex,0)"
  106. class="cart-select-img"
  107. ></image>
  108. <image
  109. mode="aspectFill u-skeleton-fillet"
  110. v-else
  111. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_select_normal.png"
  112. @click.stop="handleSelectSku(index,cIndex,1)"
  113. class="cart-select-img"
  114. ></image>
  115. <view class="pro-r">
  116. <image
  117. :src="skuItem.image"
  118. onerror="this.src='url(https://wechat.hnthee.com/ceres-local-file/image/default.png) no-repeat center';this.οnerrοr=null"
  119. class="pro-img default-img u-skeleton-fillet"
  120. ></image>
  121. <view class="pro-r-r u-skeleton-fillet">
  122. <view class="pro-name">{{ skuItem.productName }}</view>
  123. <view class="sku-box">
  124. <text v-if="skuItem.value">{{ skuItem.value }}</text>
  125. <text v-else>默认规格</text>
  126. <!-- <text></text> -->
  127. </view>
  128. <view class="pro-price-num-box">
  129. <view class="pro-price-box">
  130. <text class="fuhao"></text>
  131. <text>{{ skuItem.price }}</text>
  132. </view>
  133. <view class="cart-operate-num-box">
  134. <image v-if="skuItem.number === 1" class="operate-img" @click.stop="handleSubSkuNumber(index,cIndex)"
  135. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_nosub.png"/>
  136. <image v-else class="operate-img" @click.stop="handleSubSkuNumber(index,cIndex)"
  137. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_sub.png"/>
  138. <text class="num">{{ skuItem.number }}</text>
  139. <image class="operate-img" @click.stop="handleAddSkuNumber(index,cIndex)"
  140. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_add.png"/>
  141. </view>
  142. </view>
  143. </view>
  144. </view>
  145. </view>
  146. </view>
  147. </view>
  148. </view>
  149. </view>
  150. <!-- #ifdef H5 -->
  151. <view class="cart-bottom-box-h5">
  152. <!-- #endif -->
  153. <!-- #ifndef H5 -->
  154. <view class="cart-bottom-box-app">
  155. <!-- #endif -->
  156. <view class="cart-bottom">
  157. <view style="display: flex;flex-direction: column">
  158. <view class="left">
  159. <image
  160. mode="aspectFill"
  161. v-if="settleAccountsObj.isAllCheck"
  162. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_select_active.png"
  163. class="cart-select-img"
  164. @click="handleSelectAll(0)"
  165. ></image>
  166. <image
  167. mode="aspectFill"
  168. v-else
  169. src="https://wechat.hnthee.com/ceres-local-file/image/icon_cart_select_normal.png"
  170. class="cart-select-img"
  171. @click="handleSelectAll(1)"
  172. ></image>
  173. <text>{{$t('common.chooseall')}}{{ settleAccountsObj.checkNum }}</text>
  174. </view>
  175. <view class="total-title">{{$t('common.total_small')}}<text class="total-content">¥{{ settleAccountsObj.checkMoney }}</text></view>
  176. </view>
  177. <view class="right">
  178. <view
  179. v-if="!showManage"
  180. class="btn-confirm"
  181. @click="settlementTap"
  182. >结算</view>
  183. <view
  184. v-if="showManage"
  185. class="btn-delete"
  186. @click="handleOpenDelete"
  187. >删除</view>
  188. </view>
  189. </view>
  190. </view>
  191. </view>
  192. </view>
  193. <!-- 购物车为空 -->
  194. <view
  195. v-if="isEmpty"
  196. class="emptyCart-box flex-items-plus flex-column"
  197. >
  198. <image
  199. class="emptyCart-img"
  200. src="https://ceres.zkthink.com/static/images/cartEmpty.png"
  201. ></image>
  202. <label class="font-color-999 fs26 mar-top-30">你的购物车还没有宝贝哦</label>
  203. <label class="font-color-999 fs26 mar-top-10">快去首页选一个吧</label>
  204. <view
  205. class="goToShopping"
  206. @click="$jumpToTabbar(jumpObj.shopping)"
  207. >去购物
  208. </view>
  209. </view>
  210. <!-- 热门推荐 -->
  211. <HotTemplate v-if="isEmpty" class="u-skeleton-fillet"/>
  212. <view style="width: 100%;height: 140rpx;background-color:#FAFAFA;"></view>
  213. <!-- 删除确认弹窗 -->
  214. <DeleteModal
  215. :showTip.sync="showDeleteModal"
  216. @confirm="handleDoDelete"
  217. ></DeleteModal>
  218. </view>
  219. </view>
  220. </template>
  221. <script>
  222. import HotTemplate from '../../../components/hoteRecommed/index.vue'
  223. import DeleteModal from "./components/DeleteModal";
  224. import api from "../../../components/canvasShow/config/api";
  225. import { defaultCartList, getCartNumberBySelect, getPriceBySelect } from "./cartUtils";
  226. import lodash from 'lodash'
  227. let cacheKey = ''
  228. const NET = require('../../../utils/request')
  229. const API = require('../../../config/api')
  230. export default {
  231. components: {
  232. HotTemplate,
  233. DeleteModal
  234. },
  235. data() {
  236. return {
  237. isFirstComeIn:true, // 是否是首次进入
  238. loading: true, // 是否在加载
  239. showManage: false, // 是否开启管理
  240. dataList: [
  241. {skus: []}
  242. ], // 购物车数据
  243. showDeleteModal: false, // 是否展示删除
  244. isEmpty: false, // 购物车是否为空
  245. userInfo: {}, // 用户信息
  246. // 跳转对象
  247. jumpObj: {
  248. store: '/pages_category_page1/store/index',
  249. detail: '/pages_category_page1/goodsModule/goodsDetails',
  250. shopping: '/pages/tabbar/index/index'
  251. },
  252. // 底部结算条对象
  253. settleAccountsObj: {
  254. allNum: 0,// 所有sku数量(头部)
  255. checkNum: 0, // 选中sku的数量
  256. checkMoney: 0, // 选中sku的总价
  257. isAllCheck: false, // 是否宣布选中
  258. }
  259. }
  260. },
  261. onShow() {
  262. this.isFirstComeIn = true
  263. this.loading = true
  264. this.userInfo = uni.getStorageSync('storage_key')
  265. cacheKey = this.userInfo.buyerUserId + "cart_info"
  266. this.dataList = defaultCartList
  267. this.isEmpty = false
  268. this.getDataList()
  269. },
  270. methods: {
  271. /**
  272. * 获取购物车列表
  273. */
  274. getDataList:lodash.debounce(async function () {
  275. this.isEmpty = false
  276. this.loading = true
  277. try {
  278. const res = await NET.request(API.ShoppingCart, {}, 'GET')
  279. this.dataList = res.data
  280. this.settleAccountsObj.allNum = this.dataList.length
  281. if (this.dataList.length === 0) {
  282. this.isEmpty = true
  283. uni.setStorageSync('allCartNum', 0)
  284. uni.removeTabBarBadge({
  285. index: 2
  286. })
  287. }
  288. // sku为空的山沟
  289. const emptySkuShopArray = []
  290. this.dataList.forEach((shopObj, shopIndex) => {
  291. shopObj['currentIds'] = []
  292. shopObj['priceNumber'] = 0
  293. shopObj['rules'] = []
  294. shopObj['currentRules'] = {}
  295. shopObj['ids'] = 0
  296. // 处理下架商品
  297. for (let i = shopObj.skus.length - 1; i >= 0; i--) {
  298. // shelveState是否上架
  299. if (shopObj.skus[i].shelveState === 0) {
  300. // 删掉下架商品
  301. // todo 失效商品
  302. shopObj.skus.splice(i, 1)
  303. continue
  304. }
  305. if (shopObj.skus[i].activityType === 6 && shopObj.skus[i].selected === 1) {
  306. shopObj.currentIds.push(shopObj.skus[i].priceId)
  307. shopObj.priceNumber += shopObj.skus[i].number
  308. }
  309. }
  310. for (let i = 0; i < shopObj.skus.length; i++) {
  311. if (shopObj.skus[i].activityType === 6) {
  312. shopObj.ids = shopObj.skus[i].priceId
  313. break
  314. }
  315. }
  316. // 根据店铺索引获取规则
  317. this.getData(shopObj).then(res => {
  318. shopObj.rules = res.data ? res.data[0].rules : {}
  319. this.handleSetGroupGood(shopIndex)
  320. })
  321. shopObj.skus.length === 0?emptySkuShopArray.push(shopObj):undefined
  322. })
  323. this.isEmpty = emptySkuShopArray.length >=this.dataList.length
  324. this.handleRenderCart()
  325. // 数据回来就直接关闭骨架屏
  326. this.loading = false
  327. this.isFirstComeIn = false
  328. await this.handleUpdateMoneyAndNum()
  329. } finally {
  330. uni.hideLoading()
  331. }
  332. },500),
  333. /**
  334. * 获取组合定价
  335. * @param item
  336. * @return {Promise<unknown>}
  337. */
  338. getData(item) {
  339. return new Promise(((resolve, reject) => {
  340. if (item.ids) {
  341. NET.request(api.getPrices, {
  342. shopId: item.shopId,
  343. ids: item.ids,
  344. page: 1,
  345. pageSize: 10
  346. }, 'GET').then(res => {
  347. resolve(res)
  348. }).catch(e => {
  349. reject(e)
  350. })
  351. } else {
  352. resolve([])
  353. }
  354. }))
  355. },
  356. /**
  357. * 单个SKU数量减
  358. * @param shopIndex 店铺索引
  359. * @param skuIndex index店铺下sku商品索引
  360. */
  361. async handleSubSkuNumber(shopIndex, skuIndex) {
  362. const selectSku = this.dataList[shopIndex].skus[skuIndex]
  363. if (selectSku.number <= 1) {
  364. return uni.showToast({
  365. title: '亲!至少一件哦!',
  366. icon: "none"
  367. })
  368. }
  369. --selectSku.number
  370. await this.handleUpdateCart(selectSku.skuId, selectSku.number)
  371. setTimeout(async ()=>{
  372. await this.getDataList()
  373. },500)
  374. },
  375. /**
  376. * 单个SKU数量加
  377. * @param shopIndex 店铺索引
  378. * @param skuIndex index店铺下sku商品索引
  379. */
  380. async handleAddSkuNumber(shopIndex, skuIndex) {
  381. const selectSku = this.dataList[shopIndex].skus[skuIndex]
  382. if (selectSku.number >= selectSku.stockNumber) {
  383. selectSku.number = selectSku.stockNumber
  384. return uni.showToast({
  385. title: $t('common.understock'),
  386. icon: 'none'
  387. })
  388. }
  389. if (selectSku.number < selectSku.stockNumber) {
  390. ++selectSku.number
  391. await this.handleUpdateCart(selectSku.skuId, selectSku.number)
  392. setTimeout(async ()=>{
  393. await this.getDataList()
  394. },500)
  395. }
  396. },
  397. /**
  398. * 更新总价和总数底部结算栏头部总数
  399. * @return {Promise<void>}
  400. */
  401. async handleUpdateMoneyAndNum() {
  402. const {allNumber, checkNumber, isAllCheck} = await getCartNumberBySelect(this.dataList)
  403. const {money} = await getPriceBySelect(this.dataList)
  404. this.settleAccountsObj.checkMoney = money
  405. this.settleAccountsObj.isAllCheck = isAllCheck
  406. this.settleAccountsObj.allNum = allNumber
  407. this.settleAccountsObj.checkNum = checkNumber
  408. },
  409. /**
  410. * 请求服务端更新购物车数量
  411. * @param skuId :需要更新的skuId
  412. * @param number: 数量
  413. */
  414. handleUpdateCart:lodash.debounce(async function(skuId, number) {
  415. // 重新算钱和数量
  416. await NET.request(API.UpdateNumberCart, {
  417. skuId: skuId,
  418. number: number
  419. }, 'POST')
  420. },500),
  421. /**
  422. * 选中店铺
  423. * @param shopIndex 店铺索引
  424. * @param type 0否1是
  425. */
  426. handleSelectShop(shopIndex, type) {
  427. const shopObj = this.dataList[shopIndex]
  428. const shopCarts = [{
  429. shopId: shopObj.shopId,
  430. skus: []
  431. }]
  432. shopObj.selected = type
  433. // 设置当前店铺下的所有sku
  434. shopObj.skus.forEach(skuObj => {
  435. skuObj.selected = type
  436. shopCarts[0].skus.push({
  437. skuId: skuObj.skuId,
  438. selected: skuObj.selected
  439. })
  440. })
  441. this.handleSetGroupGood(shopIndex)
  442. this.handleUpdateSelected(shopCarts)
  443. }
  444. ,
  445. /**
  446. * 商品单选
  447. * @param shopIndex 店铺索引dataList
  448. * @param skuIndex sku索引dataList[index].skus
  449. * @param type 是否选中 0否1是
  450. */
  451. handleSelectSku(shopIndex, skuIndex, type) {
  452. const shopObj = this.dataList[shopIndex]
  453. const skuObj = this.dataList[shopIndex].skus[skuIndex]
  454. skuObj.selected = type
  455. let shopCarts = [{
  456. shopId: shopObj.shopId,
  457. skus: [{
  458. skuId: skuObj.skuId,
  459. selected: skuObj.selected,
  460. }]
  461. }]
  462. if (type === 1) {
  463. // 过滤店铺内未选择的sku
  464. const noSelectSkuList = shopObj.skus.filter(sku => sku.selected === 0);
  465. if (noSelectSkuList.length >= 0) {
  466. shopObj.selected = 0
  467. } else {
  468. shopObj.selected = 1
  469. }
  470. } else {
  471. shopObj.selected = type
  472. }
  473. // 渲染组合商品
  474. this.handleSetGroupGood(shopIndex)
  475. this.handleUpdateSelected(shopCarts)
  476. }
  477. ,
  478. /**
  479. * 全选
  480. * @param type 是否选中 0否1是
  481. */
  482. handleSelectAll(type) {
  483. this.dataList.forEach((shopObj, shopIndex) => {
  484. // 组合支付商品数量
  485. const goodsOfJointNumber = shopObj.skus.reduce((prev, skuObj) => {
  486. skuObj.selected = type
  487. // 如果是组合支付
  488. if (skuObj.selected === 1 && skuObj.activityType === 6) {
  489. return prev + skuObj.number
  490. }
  491. }, 0)
  492. shopObj.selected = type
  493. shopObj.priceNumber = goodsOfJointNumber
  494. shopObj.currentRules = {}
  495. // 处理选中的组合商品
  496. if (type === 1) {
  497. this.handleSetGroupGood(shopIndex)
  498. }
  499. })
  500. this.handleUpdateSelected([])
  501. }
  502. ,
  503. /**
  504. * 处理组合商品(设置currentRules渲染横幅)
  505. * @param shopIndex
  506. */
  507. handleSetGroupGood(shopIndex) {
  508. const shopObj = this.dataList[shopIndex]
  509. shopObj.currentRules = {}
  510. shopObj.priceNumber = 0
  511. shopObj.skus.forEach((skuObj) => {
  512. if (skuObj.activityType === 6 && skuObj.selected === 1) {
  513. shopObj.priceNumber += skuObj.number
  514. }
  515. })
  516. const shopRules = this.dataList[shopIndex].rules
  517. for (let i = 0; i < shopRules.length; i++) {
  518. if (shopRules[i].number === shopObj.priceNumber) {
  519. shopObj.currentRules = shopRules[i]
  520. break
  521. } else if (shopRules[shopRules.length - 1].number < shopObj.priceNumber) {
  522. shopObj.currentRules = shopRules[shopRules.length - 1]
  523. break
  524. }
  525. }
  526. }
  527. ,
  528. /**
  529. * 更新缓存sku勾选和价格数量显示
  530. * @param shopCarts:{shopId:number,skus:{skuId:number,select:number}}[] 只有一个对象店铺全选传空数组
  531. */
  532. handleUpdateSelected(shopCarts) {
  533. this.handleSetCache(shopCarts)
  534. this.handleUpdateMoneyAndNum()
  535. }
  536. ,
  537. /**
  538. * 设置购物车本地缓存先存入本地缓存再调用handleRenderCart根据本地缓存渲染
  539. * @param shopCarts:{shopId:number,skus:{skuId:number,select:number}}[] 只有一个对象店铺全选传空数组
  540. */
  541. handleSetCache(shopCarts) {
  542. let cartInfo = uni.getStorageSync(cacheKey);
  543. if (cartInfo === '') {
  544. // 全选
  545. if (shopCarts.length <= 0) {
  546. // 全选直接缓存整个列表
  547. uni.setStorageSync(cacheKey, JSON.stringify(this.dataList))
  548. // 渲染视图
  549. this.handleRenderCart()
  550. return
  551. }
  552. // 无购物车信息
  553. cartInfo = shopCarts
  554. uni.setStorageSync(cacheKey, JSON.stringify(cartInfo))
  555. } else {
  556. cartInfo = JSON.parse(cartInfo)
  557. // 全选
  558. if (shopCarts.length <= 0) {
  559. // 全选直接缓存整个列表
  560. uni.setStorageSync(cacheKey, JSON.stringify(this.dataList))
  561. // 渲染视图
  562. this.handleRenderCart()
  563. return
  564. }
  565. // 看了代码逻辑结构,一次只会传一个商铺过来,大胆取0
  566. const shopItem = shopCarts[0]
  567. const cacheHaveInfo = cartInfo.findIndex(item => item.shopId === shopItem.shopId)
  568. if (cacheHaveInfo < 0) {
  569. // 如果缓存中不存在当前商店信息,写入缓存
  570. cartInfo.push(shopItem)
  571. } else {
  572. // 获取到缓存项
  573. const cacheShopItem = cartInfo[cacheHaveInfo]
  574. // 判断传入的sku大小,sku length为1就是点单项,sku length>1就是点击了整个店铺
  575. if (shopItem.skus.length > 1) {
  576. // 点击整个店铺,直接赋值
  577. cartInfo[cacheHaveInfo] = shopItem
  578. } else {
  579. // 点击单项sku,获取到sku // 数据结构只会传入一项
  580. const shopItemSkuItem = shopItem.skus[0];
  581. // 在缓存中寻找
  582. const cacheShopItemSkuItemIndex = cacheShopItem.skus.findIndex(item => item.skuId === shopItemSkuItem.skuId);
  583. cacheShopItemSkuItemIndex >= 0 ? cacheShopItem.skus[cacheShopItemSkuItemIndex] = shopItemSkuItem : cacheShopItem.skus.push(shopItemSkuItem)
  584. }
  585. }
  586. // 逻辑处理完毕更新缓存
  587. uni.setStorageSync(cacheKey, JSON.stringify(cartInfo))
  588. // 渲染视图
  589. this.handleRenderCart()
  590. }
  591. }
  592. ,
  593. /**
  594. * 根据本地缓存渲染购物车勾选
  595. * @constructor
  596. */
  597. handleRenderCart() {
  598. // 取消所有勾选
  599. this.dataList.forEach(shop => {
  600. shop.selected = 0
  601. shop.skus.forEach(sku => {
  602. sku.selected = 0
  603. })
  604. })
  605. // 校验缓存中的数据是否存在于购物车中
  606. this.handleCheckCacheAndUpdate()
  607. // 缓存内购物车信息
  608. let cartInfo = uni.getStorageSync(cacheKey);
  609. if (cartInfo === '') return
  610. cartInfo = JSON.parse(cartInfo)
  611. // 遍历购物车信息,寻找缓存比对
  612. this.dataList.forEach(nowCartShopItem => {
  613. let shopSelect = 1
  614. const cacheCartShopItem = cartInfo.find(item => item.shopId === nowCartShopItem.shopId);
  615. if (cacheCartShopItem) {
  616. // 如果缓存中有当前店铺,遍历当前购物车sku
  617. nowCartShopItem.skus.forEach(nowCartSkuItem => {
  618. const cacheCartSkuItem = cacheCartShopItem.skus.find(item => item.skuId === nowCartSkuItem.skuId);
  619. if (cacheCartSkuItem) {
  620. // 如果有一个未选中当前店铺就不能全选
  621. !cacheCartSkuItem.selected ? shopSelect = 0 : ''
  622. nowCartSkuItem.selected = cacheCartSkuItem.selected
  623. } else {
  624. shopSelect = 0
  625. }
  626. })
  627. } else {
  628. shopSelect = 0
  629. }
  630. nowCartShopItem.selected = shopSelect
  631. })
  632. }
  633. ,
  634. /**
  635. * 比较缓存内数据和后端数据是否一致,并且更新缓存
  636. * @constructor
  637. */
  638. handleCheckCacheAndUpdate() {
  639. // 缓存内购物车信息
  640. let cartInfo = uni.getStorageSync(cacheKey);
  641. if (cartInfo === '') return
  642. cartInfo = JSON.parse(cartInfo)
  643. // 校验缓存中的数据是否存在于购物车中
  644. cartInfo.forEach((cacheCartShopItem, cacheCartShopIndex) => {
  645. const nowCartShopItem = this.dataList.find(item => item.shopId === cacheCartShopItem.shopId);
  646. if (!nowCartShopItem) {
  647. cartInfo.splice(cacheCartShopIndex, 1)
  648. } else {
  649. // 存在就校验缓存中的sku在不在后端返回的列表内
  650. cacheCartShopItem.skus.forEach((cacheCartSkuItem, cacheCartSkuIndex) => {
  651. const nowCartSkuItem = nowCartShopItem.skus.find(item => item.skuId === cacheCartSkuItem.skuId)
  652. if (!nowCartSkuItem) {
  653. cacheCartShopItem.skus.splice(cacheCartSkuIndex, 1)
  654. }
  655. })
  656. }
  657. })
  658. uni.setStorageSync(cacheKey, JSON.stringify(cartInfo))
  659. }
  660. ,
  661. /**
  662. * 打开删除弹窗
  663. */
  664. handleOpenDelete() {
  665. if (!this.settleAccountsObj.checkNum) return uni.showToast({
  666. title: '请先选择对应商品',
  667. icon: 'none'
  668. })
  669. this.showDeleteModal = true
  670. }
  671. ,
  672. /**
  673. * 执行删除
  674. * @return {Promise<void>}
  675. */
  676. async handleDoDelete() {
  677. let ids = []
  678. for (const shopObj of this.dataList) {
  679. ids = [...ids, ...shopObj.skus.filter(sku => (sku.selected === 1 || sku.selected === true)).map(sku => sku.skuId)]
  680. }
  681. await NET.request(API.DeleteCart, {ids}, 'POST')
  682. this.showDeleteModal = false
  683. await this.getDataList()
  684. }
  685. ,
  686. /**
  687. * 结算购物车
  688. * @return {Promise<void>}
  689. */
  690. async settlementTap() {
  691. const {shopList} = await getPriceBySelect(this.dataList)
  692. uni.setStorageSync('skuItemDTOList', shopList)
  693. this.$jump('/pages_category_page1/orderModule/orderConfirm?type=2')
  694. }
  695. }
  696. }
  697. </script>
  698. <style
  699. lang="scss"
  700. scoped
  701. >
  702. .content {
  703. //overflow: hidden;
  704. //opacity: 0;
  705. .cart-bg {
  706. width: 100%;
  707. height: 70rpx;
  708. background-color: #fff;
  709. .cart-num-box {
  710. display: flex;
  711. flex-direction: row;
  712. align-items: center;
  713. justify-content: space-between;
  714. image {
  715. width: 286rpx;
  716. height: 72rpx;
  717. }
  718. .btn-box {
  719. font-size: 28rpx;
  720. color: #252744;
  721. border: 1rpx solid #252744;
  722. border-radius: 30rpx;
  723. padding: 6rpx 20rpx;
  724. margin-right: 30rpx;
  725. box-sizing: border-box;
  726. display: inline-block;
  727. }
  728. }
  729. .num-box {
  730. padding: 30rpx 0 30rpx 30rpx;
  731. box-sizing: border-box;
  732. font-size: 28rpx;
  733. color: #252744;
  734. }
  735. }
  736. .cart-list-box {
  737. box-sizing: border-box;
  738. .itemBox {
  739. .item {
  740. background: #ffffff;
  741. //border-bottom: 16rpx solid #F8F9FA;
  742. margin-left: 30rpx;
  743. margin-right: 30rpx;
  744. margin-top: 30rpx;
  745. border-radius: 30rpx;
  746. .shop-box {
  747. margin-top: 5rpx;
  748. display: flex;
  749. flex-direction: row;
  750. align-items: center;
  751. position: relative;
  752. .cart-select-img {
  753. width: 40rpx;
  754. height: 40rpx;
  755. margin: 30rpx;
  756. box-sizing: border-box;
  757. }
  758. .shop-name-box {
  759. display: flex;
  760. flex-direction: row;
  761. align-items: center;
  762. .shop-img {
  763. width: 36rpx;
  764. height: 36rpx;
  765. margin-right: 2rpx;
  766. }
  767. .shop-name {
  768. font-size: 28rpx;
  769. color: #252744;
  770. display: inline-block;
  771. margin-left: 10rpx;
  772. }
  773. .arrow-right-img {
  774. width: 14rpx;
  775. height: 24rpx;
  776. margin-left: 12rpx;
  777. margin-top: 4rpx;
  778. /* box-sizing: border-box;
  779. margin-left: 30rpx;
  780. position: absolute;
  781. right: 30rpx;*/
  782. }
  783. }
  784. }
  785. .rulesBox {
  786. height: 86rpx;
  787. background: #F9F6F1;
  788. padding: 0 20rpx;
  789. image {
  790. width: 126rpx;
  791. height: 46rpx;
  792. }
  793. }
  794. .product-list-box {
  795. margin: 8rpx 0;
  796. .pro-item {
  797. display: flex;
  798. flex-direction: row;
  799. align-items: center;
  800. .cart-select-img {
  801. width: 40rpx;
  802. height: 40rpx;
  803. margin: 30rpx;
  804. box-sizing: border-box;
  805. }
  806. .pro-r {
  807. flex: 1;
  808. border-bottom: 1px solid #eee;
  809. display: flex;
  810. flex-direction: row;
  811. padding: 30rpx 30rpx 30rpx 0;
  812. box-sizing: border-box;
  813. overflow: hidden;
  814. .pro-img {
  815. width: 180rpx;
  816. height: 180rpx;
  817. border-radius: 10rpx;
  818. margin-right: 30rpx;
  819. }
  820. .pro-r-r {
  821. flex: 1;
  822. font-size: 26rpx;
  823. color: #333;
  824. overflow: hidden;
  825. display: flex;
  826. flex-direction: column;
  827. justify-content: space-between;
  828. .pro-name {
  829. height: 50rpx;
  830. line-height: 33rpx;
  831. display: -webkit-box;
  832. overflow: hidden;
  833. font-size: 24rpx;
  834. color: #252744;
  835. text-overflow: ellipsis;
  836. word-break: break-all;
  837. -webkit-box-orient: vertical;
  838. -webkit-line-clamp: 2;
  839. }
  840. .sku-box {
  841. width: auto;
  842. display: inline;
  843. height: 40rpx;
  844. box-sizing: border-box;
  845. font-size: 24rpx;
  846. color: #90919C;
  847. /*text {
  848. border: 2rpx solid #E4E5E6;
  849. padding: 2rpx 10rpx;
  850. }*/
  851. }
  852. .pro-price-num-box {
  853. display: flex;
  854. flex-direction: row;
  855. align-items: center;
  856. justify-content: space-between;
  857. .pro-price-box {
  858. font-size: 26rpx;
  859. color: #90919C;
  860. font-weight: 400;
  861. .fuhao {
  862. font-size: 24rpx;
  863. }
  864. }
  865. .pro-num-box {
  866. width: 140rpx;
  867. height: 40rpx;
  868. border: 1px solid #ddd;
  869. border-radius: 4rpx;
  870. display: flex;
  871. flex-direction: row;
  872. justify-content: space-between;
  873. overflow: hidden;
  874. .num-btn {
  875. font-size: 34rpx;
  876. color: #999999;
  877. display: inline-block;
  878. width: 40rpx;
  879. text-align: center;
  880. line-height: 32rpx;
  881. height: 40rpx;
  882. }
  883. .num-btn.r {
  884. border-right: 1px solid #ddd;
  885. }
  886. .num-btn.l {
  887. border-left: 1px solid #ddd;
  888. }
  889. .num {
  890. font-size: 26rpx;
  891. color: #333;
  892. }
  893. }
  894. }
  895. }
  896. }
  897. }
  898. .pro-item:last-of-type .pro-r {
  899. border-bottom: none;
  900. }
  901. }
  902. }
  903. }
  904. .itemBox:first-child {
  905. .shop-box {
  906. //border-top: 2rpx solid #eee;
  907. }
  908. }
  909. .itemBox:last-child {
  910. .item {
  911. border-bottom: none;
  912. }
  913. }
  914. }
  915. .emptyCart-box {
  916. margin: 100rpx 0;
  917. .emptyCart-img {
  918. width: 216rpx;
  919. height: 156rpx;
  920. }
  921. .goToShopping {
  922. width: 282rpx;
  923. height: 84rpx;
  924. line-height: 84rpx;
  925. text-align: center;
  926. background: #333333;
  927. margin-top: 40rpx;
  928. color: #FFEBC4;
  929. font-size: 28rpx;
  930. }
  931. }
  932. .cart-bottom-box-h5 {
  933. position: fixed;
  934. bottom: 80rpx;
  935. width: 100%;
  936. z-index: 99;
  937. }
  938. .cart-bottom-box-app {
  939. position: fixed;
  940. bottom: 0rpx;
  941. width: 100%;
  942. z-index: 99;
  943. }
  944. .cart-bottom {
  945. height: 190rpx;
  946. background: #fff;
  947. display: flex;
  948. flex-direction: row;
  949. align-items: center;
  950. justify-content: space-between;
  951. border-top-left-radius: 30rpx;
  952. border-top-right-radius: 30rpx;
  953. //border-top: 1rpx solid #eee;
  954. }
  955. .left {
  956. display: flex;
  957. flex-direction: row;
  958. align-items: center;
  959. font-size: 28rpx;
  960. color: #252744;
  961. .cart-select-img {
  962. width: 40rpx;
  963. height: 40rpx;
  964. margin-left: 50rpx;
  965. margin-right: 15rpx;
  966. box-sizing: border-box;
  967. }
  968. }
  969. .total-title{
  970. color: #252744;
  971. font-size: 28rpx;
  972. margin-left: 50rpx;
  973. margin-top: 15rpx;
  974. }
  975. .total-content{
  976. color: #252744;
  977. font-size: 32rpx;
  978. font-weight: bold;
  979. }
  980. .right {
  981. display: flex;
  982. flex-direction: row;
  983. align-items: center;
  984. box-sizing: border-box;
  985. .price-box {
  986. font-size: 30rpx;
  987. color: #333;
  988. .price {
  989. font-size: 40rpx;
  990. color: #C83732;
  991. font-weight: bold;
  992. }
  993. }
  994. .btn-confirm {
  995. width: 280rpx;
  996. height: 98rpx;
  997. background: #252744;
  998. text-align: center;
  999. line-height: 98rpx;
  1000. font-size: 32rpx;
  1001. color: #FFFFFF;
  1002. margin-right: 50rpx;
  1003. border-radius: 50rpx;
  1004. }
  1005. .btn-delete {
  1006. width: 280rpx;
  1007. height: 98rpx;
  1008. background: #F54639;
  1009. text-align: center;
  1010. line-height: 98rpx;
  1011. font-size: 32rpx;
  1012. color: #FFFFFF;
  1013. margin-right: 50rpx;
  1014. border-radius: 50rpx;
  1015. }
  1016. }
  1017. }
  1018. .cart-operate-num-box {
  1019. width: 140rpx;
  1020. height: 40rpx;
  1021. display: flex;
  1022. flex-direction: row;
  1023. justify-content: space-between;
  1024. overflow: hidden;
  1025. .operate-img{
  1026. width: 40rpx;
  1027. height: 40rpx;
  1028. }
  1029. .num {
  1030. font-size: 26rpx;
  1031. color: #252744;
  1032. }
  1033. }
  1034. page{
  1035. background-color: #FAFAFA;
  1036. }
  1037. </style>