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

1083 lines
32 KiB

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