多租户商城-商户小程序端
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.

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