index.vue 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  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://ceres.zkthink.com/static/images/logoTop.png"
  20. ></image>
  21. <text
  22. class="btn-box "
  23. @click="showManage = !showManage"
  24. v-if="!showManage"
  25. >管理
  26. </text>
  27. <text
  28. class="btn-box"
  29. @click="showManage = !showManage"
  30. v-if="showManage"
  31. >完成
  32. </text>
  33. </view>
  34. <view>
  35. <text class="num-box u-skeleton-fillet">共
  36. <text class="num">{{ settleAccountsObj.allNum }}</text>
  37. 件宝贝
  38. </text>
  39. </view>
  40. </view>
  41. </u-sticky>
  42. <view class="cart-list-box">
  43. <view
  44. class="itemBox"
  45. v-for="(item, index) in dataList"
  46. :key="item.shopId"
  47. >
  48. <view
  49. class="item"
  50. v-if="item.skus.length >0"
  51. >
  52. <view class="shop-box">
  53. <image
  54. mode="aspectFill u-skeleton-fillet"
  55. v-if="item.selected === 1"
  56. src="https://ceres.zkthink.com/static/images/selectActive.png"
  57. class="cart-select-img"
  58. @click.stop="handleSelectShop(index,0)"
  59. ></image>
  60. <image
  61. mode="aspectFill u-skeleton-fillet"
  62. v-else
  63. src="https://ceres.zkthink.com/static/images/selectEmpty.png"
  64. class="cart-select-img"
  65. @click.stop="handleSelectShop(index,1)"
  66. ></image>
  67. <view
  68. class="shop-name-box u-skeleton-fillet"
  69. @click="$jump(`${jumpObj.store}?storeId=${item.shopId}`)"
  70. >
  71. <image
  72. src="https://ceres.zkthink.com/static/images/orderStoreIcon.png"
  73. class="shop-img"
  74. ></image>
  75. <text class="shop-name">{{ item.shopName }}</text>
  76. <image
  77. src="https://ceres.zkthink.com/static/images/arrowRight.png"
  78. class="arrow-right-img"
  79. ></image>
  80. </view>
  81. </view>
  82. <view
  83. class="rulesBox flex-items"
  84. v-if="item.currentRules && item.currentRules.number"
  85. >
  86. <image
  87. class="mar-right-20"
  88. src="https://ceres.zkthink.com/static/images/zuheIcon.png"
  89. ></image>
  90. <view class="fs24 font-color-C83732">
  91. 已满足【{{ item.currentRules.price }}元任选{{ item.currentRules.number }}件】!
  92. </view>
  93. </view>
  94. <view
  95. v-for="(skuItem, cIndex) in dataList[index].skus"
  96. class="product-list-box "
  97. >
  98. <view
  99. class="pro-item"
  100. @click="$jump(`${jumpObj.detail}?shopId=${item.shopId}&productId=${skuItem.productId}&skuId=${skuItem.skuId}`)"
  101. >
  102. <image
  103. mode="aspectFill u-skeleton-fillet"
  104. v-if="skuItem.selected == 1"
  105. src="https://ceres.zkthink.com/static/images/selectActive.png"
  106. @click.stop="handleSelectSku(index,cIndex,0)"
  107. class="cart-select-img"
  108. ></image>
  109. <image
  110. mode="aspectFill u-skeleton-fillet"
  111. v-else
  112. src="https://ceres.zkthink.com/static/images/selectEmpty.png"
  113. @click.stop="handleSelectSku(index,cIndex,1)"
  114. class="cart-select-img"
  115. ></image>
  116. <view class="pro-r">
  117. <image
  118. :src="skuItem.image"
  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 v-if="!loading" />
  225. <view style="width: 100%;height: 120rpx;background-color:#fff;"></view>
  226. <!-- 删除确认弹窗 -->
  227. <DeleteModal
  228. v-model="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. console.log(this.dataList)
  295. if (this.dataList.length === 0) {
  296. this.isEmpty = true
  297. uni.setStorageSync('allCartNum', 0)
  298. uni.removeTabBarBadge({
  299. index: 2
  300. })
  301. }
  302. this.dataList.forEach((shopObj, shopIndex) => {
  303. shopObj['currentIds'] = []
  304. shopObj['priceNumber'] = 0
  305. shopObj['rules'] = []
  306. shopObj['currentRules'] = {}
  307. shopObj['ids'] = 0
  308. // 处理下架商品
  309. for (let i = shopObj.skus.length - 1; i >= 0; i--) {
  310. // shelveState是否上架
  311. if (shopObj.skus[i].shelveState === 0) {
  312. // 删掉下架商品
  313. shopObj.skus.splice(i, 1)
  314. continue
  315. }
  316. if (shopObj.skus[i].activityType === 6 && shopObj.skus[i].selected === 1) {
  317. shopObj.currentIds.push(shopObj.skus[i].priceId)
  318. shopObj.priceNumber += shopObj.skus[i].number
  319. }
  320. }
  321. console.log(shopObj.skus.length)
  322. this.isEmpty = shopObj.skus.length !== 0? false :true
  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. })
  335. this.handleRenderCart()
  336. // 数据回来就直接关闭骨架屏
  337. this.loading = false
  338. this.isFirstComeIn = false
  339. await this.handleUpdateMoneyAndNum()
  340. } finally {
  341. uni.hideLoading()
  342. }
  343. },500),
  344. /**
  345. * 获取组合定价
  346. * @param item
  347. * @return {Promise<unknown>}
  348. */
  349. getData(item) {
  350. return new Promise(((resolve, reject) => {
  351. if (item.ids) {
  352. NET.request(api.getPrices, {
  353. shopId: item.shopId,
  354. ids: item.ids,
  355. page: 1,
  356. pageSize: 10
  357. }, 'GET').then(res => {
  358. resolve(res)
  359. }).catch(e => {
  360. reject(e)
  361. })
  362. } else {
  363. resolve([])
  364. }
  365. }))
  366. },
  367. /**
  368. * 单个SKU数量减
  369. * @param shopIndex 店铺索引
  370. * @param skuIndex index店铺下sku商品索引
  371. */
  372. async handleSubSkuNumber(shopIndex, skuIndex) {
  373. const selectSku = this.dataList[shopIndex].skus[skuIndex]
  374. if (selectSku.number <= 1) {
  375. return uni.showToast({
  376. title: '亲!至少一件哦!',
  377. icon: "none"
  378. })
  379. }
  380. --selectSku.number
  381. await this.handleUpdateCart(selectSku.skuId, selectSku.number)
  382. setTimeout(async ()=>{
  383. await this.getDataList()
  384. },500)
  385. },
  386. /**
  387. * 单个SKU数量加
  388. * @param shopIndex 店铺索引
  389. * @param skuIndex index店铺下sku商品索引
  390. */
  391. async handleAddSkuNumber(shopIndex, skuIndex) {
  392. const selectSku = this.dataList[shopIndex].skus[skuIndex]
  393. if (selectSku.number >= selectSku.stockNumber) {
  394. selectSku.number = selectSku.stockNumber
  395. return uni.showToast({
  396. title: '库存不足!',
  397. icon: 'none'
  398. })
  399. }
  400. if (selectSku.number < selectSku.stockNumber) {
  401. ++selectSku.number
  402. await this.handleUpdateCart(selectSku.skuId, selectSku.number)
  403. setTimeout(async ()=>{
  404. await this.getDataList()
  405. },500)
  406. }
  407. },
  408. /**
  409. * 更新总价和总数(底部结算栏,头部总数)
  410. * @return {Promise<void>}
  411. */
  412. async handleUpdateMoneyAndNum() {
  413. const {allNumber, checkNumber, isAllCheck} = await getCartNumberBySelect(this.dataList)
  414. const {money} = await getPriceBySelect(this.dataList)
  415. this.settleAccountsObj.checkMoney = money
  416. this.settleAccountsObj.isAllCheck = isAllCheck
  417. this.settleAccountsObj.allNum = allNumber
  418. this.settleAccountsObj.checkNum = checkNumber
  419. },
  420. /**
  421. * 请求服务端更新购物车数量
  422. * @param skuId :需要更新的skuId
  423. * @param number: 数量
  424. */
  425. handleUpdateCart:lodash.debounce(async function(skuId, number) {
  426. // 重新算钱和数量
  427. await NET.request(API.UpdateNumberCart, {
  428. skuId: skuId,
  429. number: number
  430. }, 'POST')
  431. },500),
  432. /**
  433. * 选中店铺
  434. * @param shopIndex 店铺索引
  435. * @param type 0否1是
  436. */
  437. handleSelectShop(shopIndex, type) {
  438. const shopObj = this.dataList[shopIndex]
  439. const shopCarts = [{
  440. shopId: shopObj.shopId,
  441. skus: []
  442. }]
  443. shopObj.selected = type
  444. // 设置当前店铺下的所有sku
  445. shopObj.skus.forEach(skuObj => {
  446. skuObj.selected = type
  447. shopCarts[0].skus.push({
  448. skuId: skuObj.skuId,
  449. selected: skuObj.selected
  450. })
  451. })
  452. this.handleSetGroupGood(shopIndex)
  453. this.handleUpdateSelected(shopCarts)
  454. }
  455. ,
  456. /**
  457. * 商品单选
  458. * @param shopIndex 店铺索引dataList
  459. * @param skuIndex sku索引dataList[index].skus
  460. * @param type 是否选中 0否1是
  461. */
  462. handleSelectSku(shopIndex, skuIndex, type) {
  463. const shopObj = this.dataList[shopIndex]
  464. const skuObj = this.dataList[shopIndex].skus[skuIndex]
  465. skuObj.selected = type
  466. let shopCarts = [{
  467. shopId: shopObj.shopId,
  468. skus: [{
  469. skuId: skuObj.skuId,
  470. selected: skuObj.selected,
  471. }]
  472. }]
  473. if (type === 1) {
  474. // 过滤店铺内未选择的sku
  475. const noSelectSkuList = shopObj.skus.filter(sku => sku.selected === 0);
  476. if (noSelectSkuList.length >= 0) {
  477. shopObj.selected = 0
  478. } else {
  479. shopObj.selected = 1
  480. }
  481. } else {
  482. shopObj.selected = type
  483. }
  484. // 渲染组合商品
  485. this.handleSetGroupGood(shopIndex)
  486. this.handleUpdateSelected(shopCarts)
  487. }
  488. ,
  489. /**
  490. * 全选
  491. * @param type 是否选中 0否1是
  492. */
  493. handleSelectAll(type) {
  494. this.dataList.forEach((shopObj, shopIndex) => {
  495. // 组合支付商品数量
  496. const goodsOfJointNumber = shopObj.skus.reduce((prev, skuObj) => {
  497. skuObj.selected = type
  498. // 如果是组合支付
  499. if (skuObj.selected === 1 && skuObj.activityType === 6) {
  500. return prev + skuObj.number
  501. }
  502. }, 0)
  503. shopObj.selected = type
  504. shopObj.priceNumber = goodsOfJointNumber
  505. shopObj.currentRules = {}
  506. // 处理选中的组合商品
  507. if (type === 1) {
  508. this.handleSetGroupGood(shopIndex)
  509. }
  510. })
  511. this.handleUpdateSelected([])
  512. }
  513. ,
  514. /**
  515. * 处理组合商品(设置currentRules渲染横幅)
  516. * @param shopIndex
  517. */
  518. handleSetGroupGood(shopIndex) {
  519. const shopObj = this.dataList[shopIndex]
  520. shopObj.currentRules = {}
  521. shopObj.priceNumber = 0
  522. shopObj.skus.forEach((skuObj) => {
  523. if (skuObj.activityType === 6 && skuObj.selected === 1) {
  524. shopObj.priceNumber += skuObj.number
  525. }
  526. })
  527. const shopRules = this.dataList[shopIndex].rules
  528. for (let i = 0; i < shopRules.length; i++) {
  529. if (shopRules[i].number === shopObj.priceNumber) {
  530. shopObj.currentRules = shopRules[i]
  531. break
  532. } else if (shopRules[shopRules.length - 1].number < shopObj.priceNumber) {
  533. shopObj.currentRules = shopRules[shopRules.length - 1]
  534. break
  535. }
  536. }
  537. }
  538. ,
  539. /**
  540. * 更新缓存sku勾选和价格、数量显示
  541. * @param shopCarts:{shopId:number,skus:{skuId:number,select:number}}[] 只有一个对象(店铺)全选传空数组
  542. */
  543. handleUpdateSelected(shopCarts) {
  544. this.handleSetCache(shopCarts)
  545. this.handleUpdateMoneyAndNum()
  546. }
  547. ,
  548. /**
  549. * 设置购物车本地缓存(先存入本地缓存,再调用handleRenderCart根据本地缓存渲染)
  550. * @param shopCarts:{shopId:number,skus:{skuId:number,select:number}}[] 只有一个对象(店铺)全选传空数组
  551. */
  552. handleSetCache(shopCarts) {
  553. let cartInfo = uni.getStorageSync(cacheKey);
  554. if (cartInfo === '') {
  555. // 全选
  556. if (shopCarts.length <= 0) {
  557. // 全选直接缓存整个列表
  558. uni.setStorageSync(cacheKey, JSON.stringify(this.dataList))
  559. // 渲染视图
  560. this.handleRenderCart()
  561. return
  562. }
  563. // 无购物车信息
  564. cartInfo = shopCarts
  565. uni.setStorageSync(cacheKey, JSON.stringify(cartInfo))
  566. } else {
  567. cartInfo = JSON.parse(cartInfo)
  568. // 全选
  569. if (shopCarts.length <= 0) {
  570. // 全选直接缓存整个列表
  571. uni.setStorageSync(cacheKey, JSON.stringify(this.dataList))
  572. // 渲染视图
  573. this.handleRenderCart()
  574. return
  575. }
  576. // 看了代码逻辑结构,一次只会传一个商铺过来,大胆取0
  577. const shopItem = shopCarts[0]
  578. const cacheHaveInfo = cartInfo.findIndex(item => item.shopId === shopItem.shopId)
  579. if (cacheHaveInfo < 0) {
  580. // 如果缓存中不存在当前商店信息,写入缓存
  581. cartInfo.push(shopItem)
  582. } else {
  583. // 获取到缓存项
  584. const cacheShopItem = cartInfo[cacheHaveInfo]
  585. // 判断传入的sku大小,sku length为1就是点单项,sku length>1就是点击了整个店铺
  586. if (shopItem.skus.length > 1) {
  587. // 点击整个店铺,直接赋值
  588. cartInfo[cacheHaveInfo] = shopItem
  589. } else {
  590. // 点击单项sku,获取到sku // 数据结构只会传入一项
  591. const shopItemSkuItem = shopItem.skus[0];
  592. // 在缓存中寻找
  593. const cacheShopItemSkuItemIndex = cacheShopItem.skus.findIndex(item => item.skuId === shopItemSkuItem.skuId);
  594. cacheShopItemSkuItemIndex >= 0 ? cacheShopItem.skus[cacheShopItemSkuItemIndex] = shopItemSkuItem : cacheShopItem.skus.push(shopItemSkuItem)
  595. }
  596. }
  597. // 逻辑处理完毕更新缓存
  598. uni.setStorageSync(cacheKey, JSON.stringify(cartInfo))
  599. // 渲染视图
  600. this.handleRenderCart()
  601. }
  602. }
  603. ,
  604. /**
  605. * 根据本地缓存渲染购物车勾选
  606. * @constructor
  607. */
  608. handleRenderCart() {
  609. // 取消所有勾选
  610. this.dataList.forEach(shop => {
  611. shop.selected = 0
  612. shop.skus.forEach(sku => {
  613. sku.selected = 0
  614. })
  615. })
  616. // 校验缓存中的数据是否存在于购物车中
  617. this.handleCheckCacheAndUpdate()
  618. // 缓存内购物车信息
  619. let cartInfo = uni.getStorageSync(cacheKey);
  620. if (cartInfo === '') return
  621. cartInfo = JSON.parse(cartInfo)
  622. // 遍历购物车信息,寻找缓存比对
  623. this.dataList.forEach(nowCartShopItem => {
  624. let shopSelect = 1
  625. const cacheCartShopItem = cartInfo.find(item => item.shopId === nowCartShopItem.shopId);
  626. if (cacheCartShopItem) {
  627. // 如果缓存中有当前店铺,遍历当前购物车sku
  628. nowCartShopItem.skus.forEach(nowCartSkuItem => {
  629. const cacheCartSkuItem = cacheCartShopItem.skus.find(item => item.skuId === nowCartSkuItem.skuId);
  630. if (cacheCartSkuItem) {
  631. // 如果有一个未选中当前店铺就不能全选
  632. !cacheCartSkuItem.selected ? shopSelect = 0 : ''
  633. nowCartSkuItem.selected = cacheCartSkuItem.selected
  634. } else {
  635. shopSelect = 0
  636. }
  637. })
  638. } else {
  639. shopSelect = 0
  640. }
  641. nowCartShopItem.selected = shopSelect
  642. })
  643. }
  644. ,
  645. /**
  646. * 比较缓存内数据和后端数据是否一致,并且更新缓存
  647. * @constructor
  648. */
  649. handleCheckCacheAndUpdate() {
  650. // 缓存内购物车信息
  651. let cartInfo = uni.getStorageSync(cacheKey);
  652. if (cartInfo === '') return
  653. cartInfo = JSON.parse(cartInfo)
  654. // 校验缓存中的数据是否存在于购物车中
  655. cartInfo.forEach((cacheCartShopItem, cacheCartShopIndex) => {
  656. const nowCartShopItem = this.dataList.find(item => item.shopId === cacheCartShopItem.shopId);
  657. if (!nowCartShopItem) {
  658. cartInfo.splice(cacheCartShopIndex, 1)
  659. } else {
  660. // 存在就校验缓存中的sku在不在后端返回的列表内
  661. cacheCartShopItem.skus.forEach((cacheCartSkuItem, cacheCartSkuIndex) => {
  662. const nowCartSkuItem = nowCartShopItem.skus.find(item => item.skuId === cacheCartSkuItem.skuId)
  663. if (!nowCartSkuItem) {
  664. cacheCartShopItem.skus.splice(cacheCartSkuIndex, 1)
  665. }
  666. })
  667. }
  668. })
  669. uni.setStorageSync(cacheKey, JSON.stringify(cartInfo))
  670. }
  671. ,
  672. /**
  673. * 打开删除弹窗
  674. */
  675. handleOpenDelete() {
  676. if (!this.settleAccountsObj.checkNum) return uni.showToast({
  677. title: '请先选择对应商品',
  678. icon: 'none'
  679. })
  680. this.showDeleteModal = true
  681. }
  682. ,
  683. /**
  684. * 执行删除
  685. * @return {Promise<void>}
  686. */
  687. async handleDoDelete() {
  688. let ids = []
  689. for (const shopObj of this.dataList) {
  690. ids = [...ids, ...shopObj.skus.filter(sku => (sku.selected === 1 || sku.selected === true)).map(sku => sku.skuId)]
  691. }
  692. await NET.request(API.DeleteCart, {ids}, 'POST')
  693. this.showDeleteModal = false
  694. await this.getDataList()
  695. }
  696. ,
  697. /**
  698. * 结算购物车
  699. * @return {Promise<void>}
  700. */
  701. async settlementTap() {
  702. const {shopList} = await getPriceBySelect(this.dataList)
  703. uni.setStorageSync('skuItemDTOList', shopList)
  704. this.$jump('/pages_category_page1/orderModule/orderConfirm?type=2')
  705. }
  706. }
  707. }
  708. </script>
  709. <style
  710. lang="scss"
  711. scoped
  712. >
  713. .content {
  714. //overflow: hidden;
  715. //opacity: 0;
  716. .cart-bg {
  717. width: 100%;
  718. height: 180rpx;
  719. background-color: #fff;
  720. .cart-num-box {
  721. display: flex;
  722. flex-direction: row;
  723. align-items: center;
  724. justify-content: space-between;
  725. image {
  726. width: 286rpx;
  727. height: 72rpx;
  728. }
  729. .btn-box {
  730. font-size: 30rpx;
  731. color: #333333;
  732. padding: 30rpx;
  733. box-sizing: border-box;
  734. display: inline-block;
  735. }
  736. }
  737. .num-box {
  738. padding: 30rpx 0 30rpx 30rpx;
  739. box-sizing: border-box;
  740. font-size: 30rpx;
  741. color: #C5CACF;
  742. }
  743. }
  744. .cart-list-box {
  745. box-sizing: border-box;
  746. .itemBox {
  747. .item {
  748. background: #fff;
  749. border-bottom: 16rpx solid #F8F9FA;
  750. .shop-box {
  751. margin-top: 5rpx;
  752. display: flex;
  753. flex-direction: row;
  754. align-items: center;
  755. border-bottom: 1px solid #eee;
  756. position: relative;
  757. .cart-select-img {
  758. width: 40rpx;
  759. height: 40rpx;
  760. margin: 30rpx;
  761. box-sizing: border-box;
  762. }
  763. .shop-name-box {
  764. display: flex;
  765. flex-direction: row;
  766. align-items: center;
  767. .shop-img {
  768. width: 36rpx;
  769. height: 36rpx;
  770. margin-right: 10rpx;
  771. }
  772. .shop-name {
  773. font-size: 30rpx;
  774. color: #333;
  775. font-weight: bold;
  776. display: inline-block;
  777. margin-left: 10rpx;
  778. }
  779. .arrow-right-img {
  780. width: 30rpx;
  781. height: 30rpx;
  782. box-sizing: border-box;
  783. margin-left: 30rpx;
  784. position: absolute;
  785. right: 30rpx;
  786. }
  787. }
  788. }
  789. .rulesBox {
  790. height: 86rpx;
  791. background: #F9F6F1;
  792. padding: 0 20rpx;
  793. image {
  794. width: 126rpx;
  795. height: 46rpx;
  796. }
  797. }
  798. .product-list-box {
  799. margin: 8rpx 0;
  800. .pro-item {
  801. display: flex;
  802. flex-direction: row;
  803. align-items: center;
  804. .cart-select-img {
  805. width: 40rpx;
  806. height: 40rpx;
  807. margin: 30rpx;
  808. box-sizing: border-box;
  809. }
  810. .pro-r {
  811. flex: 1;
  812. border-bottom: 1px solid #eee;
  813. display: flex;
  814. flex-direction: row;
  815. padding: 30rpx 30rpx 30rpx 0;
  816. box-sizing: border-box;
  817. overflow: hidden;
  818. .pro-img {
  819. width: 180rpx;
  820. height: 180rpx;
  821. border-radius: 10rpx;
  822. margin-right: 30rpx;
  823. }
  824. .pro-r-r {
  825. flex: 1;
  826. font-size: 26rpx;
  827. color: #333;
  828. overflow: hidden;
  829. display: flex;
  830. flex-direction: column;
  831. justify-content: space-between;
  832. .pro-name {
  833. height: 66rpx;
  834. line-height: 33rpx;
  835. display: -webkit-box;
  836. overflow: hidden;
  837. text-overflow: ellipsis;
  838. word-break: break-all;
  839. -webkit-box-orient: vertical;
  840. -webkit-line-clamp: 2;
  841. }
  842. .sku-box {
  843. width: auto;
  844. display: inline;
  845. height: 40rpx;
  846. border-radius: 4rpx;
  847. padding: 0 0 0 10rpx;
  848. box-sizing: border-box;
  849. font-size: 24rpx;
  850. color: #999;
  851. text {
  852. border: 2rpx solid #E4E5E6;
  853. padding: 2rpx 10rpx;
  854. }
  855. }
  856. .pro-price-num-box {
  857. display: flex;
  858. flex-direction: row;
  859. align-items: center;
  860. justify-content: space-between;
  861. .pro-price-box {
  862. font-size: 36rpx;
  863. color: #333333;
  864. font-weight: 400;
  865. .fuhao {
  866. font-size: 24rpx;
  867. }
  868. }
  869. .pro-num-box {
  870. width: 140rpx;
  871. height: 40rpx;
  872. border: 1px solid #ddd;
  873. border-radius: 4rpx;
  874. display: flex;
  875. flex-direction: row;
  876. justify-content: space-between;
  877. overflow: hidden;
  878. .num-btn {
  879. font-size: 34rpx;
  880. color: #999999;
  881. display: inline-block;
  882. width: 40rpx;
  883. text-align: center;
  884. line-height: 32rpx;
  885. height: 40rpx;
  886. }
  887. .num-btn.r {
  888. border-right: 1px solid #ddd;
  889. }
  890. .num-btn.l {
  891. border-left: 1px solid #ddd;
  892. }
  893. .num {
  894. font-size: 26rpx;
  895. color: #333;
  896. }
  897. }
  898. }
  899. }
  900. }
  901. }
  902. .pro-item:last-of-type .pro-r {
  903. border-bottom: none;
  904. }
  905. }
  906. }
  907. }
  908. .itemBox:first-child {
  909. .shop-box {
  910. border-top: 2rpx solid #eee;
  911. }
  912. }
  913. .itemBox:last-child {
  914. .item {
  915. border-bottom: none;
  916. }
  917. }
  918. }
  919. .emptyCart-box {
  920. margin: 100rpx 0;
  921. .emptyCart-img {
  922. width: 216rpx;
  923. height: 156rpx;
  924. }
  925. .goToShopping {
  926. width: 282rpx;
  927. height: 84rpx;
  928. line-height: 84rpx;
  929. text-align: center;
  930. background: #333333;
  931. margin-top: 40rpx;
  932. color: #FFEBC4;
  933. font-size: 28rpx;
  934. }
  935. }
  936. .cart-bottom-box-h5 {
  937. position: fixed;
  938. bottom: 80rpx;
  939. width: 100%;
  940. z-index: 99;
  941. }
  942. .cart-bottom-box-app {
  943. position: fixed;
  944. bottom: 0rpx;
  945. width: 100%;
  946. z-index: 99;
  947. }
  948. .cart-bottom {
  949. height: 120rpx;
  950. background: #fff;
  951. display: flex;
  952. flex-direction: row;
  953. align-items: center;
  954. justify-content: space-between;
  955. border-top: 1rpx solid #eee;
  956. }
  957. .left {
  958. display: flex;
  959. flex-direction: row;
  960. align-items: center;
  961. font-size: 28rpx;
  962. color: #666;
  963. .cart-select-img {
  964. width: 40rpx;
  965. height: 40rpx;
  966. margin: 30rpx;
  967. box-sizing: border-box;
  968. }
  969. }
  970. .right {
  971. display: flex;
  972. flex-direction: row;
  973. align-items: center;
  974. box-sizing: border-box;
  975. .price-box {
  976. font-size: 30rpx;
  977. color: #333;
  978. .price {
  979. font-size: 40rpx;
  980. color: #C83732;
  981. font-weight: bold;
  982. }
  983. }
  984. .btn-confirm {
  985. width: 232rpx;
  986. height: 120rpx;
  987. background: #333333;
  988. margin-left: 18rpx;
  989. text-align: center;
  990. line-height: 120rpx;
  991. font-size: 28rpx;
  992. color: #FFEBC4;
  993. }
  994. .btn-delete {
  995. width: 232rpx;
  996. height: 120rpx;
  997. line-height: 120rpx;
  998. text-align: center;
  999. font-size: 28rpx;
  1000. color: #FFFFFF;
  1001. background: #C83732;
  1002. }
  1003. }
  1004. }
  1005. </style>