index.vue 26 KB

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