CartList.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. <template>
  2. <view class="div cart-list-wrapper" :style="'padding-top:'+navHeight+'px'">
  3. <checkbox-group @change="changeSingleStatu2" >
  4. <view class="div cart-list" v-for="(cartItem, i) in cartList" :key="i">
  5. <flex-line class="store-info" :show-border="true">
  6. <view class="div wrapper">
  7. <view class="div list-checkbox">
  8. <checkbox
  9. class="checkbox"
  10. :id="'store'+cartItem.store_id"
  11. :value="cartItem.store_id"
  12. :checked="cartItem.checked"
  13. :disabled="!isCheckedAll && cartItem.disabled"
  14. />
  15. <label class="label" :class="{'checked':cartItem.checked}" :for="'store'+cartItem.store_id"><text class="span iconfont">&#xe69b;</text></label>
  16. </view>
  17. <text class="span store-name">{{cartItem.store_name}}</text>
  18. </view>
  19. <text slot="right" v-if="cartItem.voucher_list && cartItem.voucher_list.length" class="span voucher" @click="goVoucher(i)">领券</text>
  20. </flex-line>
  21. <checkbox-group @change="changeSingleStatu(i,$event)" >
  22. <view class="div list" v-for="(item, index) in cartItem.goods" :key="index">
  23. <view class="div list-checkbox">
  24. <checkbox
  25. class="checkbox"
  26. :id="'store'+cartItem.store_id+'goods'+index"
  27. :value="item.goods_id"
  28. :checked="item.checked"
  29. :disabled="!isCheckedAll && item.disabled"
  30. />
  31. <label class="label" :class="{'checked':item.checked}" :for="'store'+cartItem.store_id+'goods'+index"><text class="span iconfont">&#xe69b;</text></label>
  32. </view>
  33. <view class="div list-item" @click="goDetail(item.goods_id)">
  34. <view class="div item">
  35. <view class="div ui-image">
  36. <image mode="aspectFit" class="img" :src="item.goods_image_url" />
  37. <text v-if="item.goods_storage == 0" class="span stock-info"
  38. >已售罄</text
  39. >
  40. <text v-if="item.goods_state!=1" class="span stock-info"
  41. >已下架</text>
  42. <text
  43. v-if="
  44. item.goods_state==1 && item.goods_storage > 0 && item.goods_storage <= 10
  45. "
  46. class="span stock-info"
  47. >仅剩{{ item.goods_storage }}件</text
  48. >
  49. <text
  50. class="span promos"
  51. v-if="item.xianshi_info"
  52. >促销</text
  53. >
  54. </view>
  55. <view class="div list-info">
  56. <view class="div product-header">
  57. <text
  58. class="h3 product-title"
  59. v-bind:class="{ 'disabled-list': item.disabled }"
  60. >
  61. {{ item.goods_name }}
  62. </text>
  63. </view>
  64. <text class="h3 property-info"></text>
  65. <view v-if="item.bl_id" class="div bl_goods_list">
  66. <view class="div bl_goods">+</view>
  67. <view class="div" v-for="(bl_goods,index) in item.bl_goods_list" :key="index">
  68. <view class="div bl_goods" v-if="bl_goods.goods_id!=item.goods_id"><image mode="aspectFit" class="img" :src="bl_goods.goods_image_url" /></view>
  69. </view>
  70. </view>
  71. <view class="div info-price">
  72. <view class="p"
  73. v-bind:class="{ 'disabled-list': item.disabled }"
  74. >
  75. ¥{{ item.goods_price }}
  76. </view>
  77. <view class="div ui-number" v-if="!item.disabled">
  78. <view
  79. class="div reduce ui-common"
  80. @click.stop="reduceNumber(item.cart_id, item.goods_num,i,index)"
  81. v-bind:class="{ 'reduce-opacity': item.goods_num <= 1 }"
  82. >
  83. -
  84. </view>
  85. <input
  86. type="number"
  87. min="1"
  88. class="number"
  89. value="1"
  90. v-model="item.goods_num"
  91. readonly="true"
  92. />
  93. <view
  94. class="div add ui-common"
  95. @click.stop="
  96. addNumber(
  97. item.cart_id,
  98. item.goods_num,
  99. i,
  100. index
  101. )
  102. "
  103. >
  104. +
  105. </view>
  106. </view>
  107. </view>
  108. </view>
  109. </view>
  110. </view>
  111. </view>
  112. </checkbox-group>
  113. </view>
  114. </checkbox-group>
  115. </view>
  116. </template>
  117. <script>
  118. import { urlencode } from '@/util/common'
  119. import { mapState, mapMutations } from 'vuex'
  120. import flexLine from '../../../flexLine'
  121. import {
  122. cartGet,
  123. cartDelete,
  124. cartUpdate,
  125. cartQuantity
  126. } from '../../../../api/homecart'
  127. export default {
  128. props: {
  129. isCheckedAll: {
  130. type: Boolean,
  131. default: false
  132. }
  133. },
  134. components:{flexLine},
  135. data () {
  136. return {
  137. navHeight: 0,
  138. cartList: [], // 购物车列表
  139. indicator: { spinnerType: 'fading-circle' },
  140. totalPrice: 0, // 购物车总价
  141. cartId: '', // 购物车中选中的商品
  142. totalAmount: 0, // 购物车数量
  143. promosIds: [] // 促销信息IDS
  144. }
  145. },
  146. created () {
  147. this.getCartList(true)
  148. },
  149. mounted: function() {
  150. // #ifdef MP-WEIXIN
  151. this.navHeight = uni.getMenuButtonBoundingClientRect().height
  152. // #endif
  153. },
  154. methods: {
  155. ...mapMutations({
  156. getAmount: 'calculationAmount',
  157. getPrice: 'calculationPrice',
  158. setCartNumber: 'setCartNumber',
  159. saveSelectedCartGoods: 'saveSelectedCartGoods',
  160. saveVoucher: 'saveVoucher'
  161. }),
  162. /*
  163. * getCartList: 获取购物车列表
  164. */
  165. getCartList (value) {
  166. cartGet().then(res => {
  167. if (res && res.result.cart_val.length > 0) {
  168. this.cartList = Object.assign([], res.result.cart_val)
  169. for (var i in this.cartList) {
  170. this.cartList[i].store_id = String(this.cartList[i].store_id)
  171. for(var j in this.cartList[i].goods){
  172. this.cartList[i].goods[j].goods_id = String(this.cartList[i].goods[j].goods_id)
  173. }
  174. }
  175. this.addChecked(value,this.isCheckedAll)
  176. this.renderCart()
  177. } else {
  178. this.cartList = []
  179. this.getAmount(0)
  180. this.getPrice(0.0)
  181. }
  182. uni.$emit('list-is-empty', this.cartList)
  183. })
  184. },
  185. /*
  186. * addChecked: 为每个商品添加checked 属性
  187. * @param: isSelectedall 是否选中商品 Boolean
  188. */
  189. addChecked (isSelectedall,isCheckedAll) {
  190. let temp = this.cartList
  191. let total_disabled_length = 0
  192. for (var j in temp) {
  193. let list = temp[j].goods
  194. let k = 0
  195. let disabled_length = 0
  196. for (var i in list) {
  197. if (list[i].goods_storage == 0 || list[i].goods_state != 1) {
  198. list[i].disabled = true
  199. disabled_length++
  200. }
  201. if (!isCheckedAll && list[i].disabled) {
  202. list[i].checked = false
  203. k++
  204. } else {
  205. list[i].checked = isSelectedall
  206. }
  207. }
  208. temp[j].disabled = (disabled_length == list.length)
  209. if (temp[j].disabled) {
  210. total_disabled_length++
  211. }
  212. temp[j].checked = (k == list.length) ? false : isSelectedall
  213. }
  214. this.cartList = Object.assign([], temp)
  215. if (temp.length == total_disabled_length) {
  216. uni.$emit('change-footer-status', false)
  217. uni.$emit('change-footer-disabled', true)
  218. }
  219. },
  220. /*
  221. * renderCart: 修改商品数量和点击是否选中后 重新计算商品价格和数量
  222. */
  223. renderCart () {
  224. let temp = this.cartList
  225. this.promosIds = []
  226. let cartGoods = []
  227. let totalAmount = 0
  228. let totalPrice = 0
  229. for (var j in temp) {
  230. let data = temp[j].goods
  231. for (var i in data) {
  232. if (data[i].checked) {
  233. totalAmount += parseInt(data[i].goods_num)
  234. totalPrice += parseInt(data[i].goods_num) * parseFloat(data[i].goods_price)
  235. cartGoods.push(data[i].cart_id + '|' + data[i].goods_num)
  236. }
  237. }
  238. }
  239. this.cartId = cartGoods.toString()
  240. this.totalPrice = totalPrice.toFixed(2)
  241. this.totalAmount = totalAmount
  242. uni.$emit('calcu-cart-data', { totalPrice: this.totalPrice, totalAmount: this.totalAmount, cartId: this.cartId })
  243. },
  244. /*
  245. * deleteSelected: 删除购物车数据
  246. */
  247. deleteSelected () {
  248. let temp = this.cartList
  249. let deleteGoods = []
  250. this.promosIds = []
  251. for (var j in temp) {
  252. let data = temp[j].goods
  253. for (var i in data) {
  254. if (data[i].checked) {
  255. deleteGoods.push(data[i].cart_id)
  256. }
  257. }
  258. }
  259. if (deleteGoods.length > 0) {
  260. deleteGoods = deleteGoods.toString()
  261. } else {
  262. uni.showToast({icon:'none',title: '当前没有可删除的商品'})
  263. return
  264. }
  265. uni.showLoading({ title: '加载中' })
  266. cartDelete(deleteGoods).then(res => {
  267. if (res) {
  268. this.getCartList(false)
  269. uni.hideLoading()
  270. }
  271. })
  272. },
  273. /*
  274. * changeSingleStatu: 改变单个商品是否选中的状态, 然后重新获取商品的件数和价格
  275. */
  276. changeSingleStatu (j,e) {
  277. var value=e.detail.value
  278. let data = this.cartList
  279. let length = 0
  280. let totalLength = 0
  281. let status = false
  282. let list = data[j].goods
  283. let k = 0
  284. for (var i in list) {
  285. if (value.indexOf(list[i].goods_id)>-1) {
  286. list[i].checked=true
  287. length = length + 1
  288. k++
  289. }else{
  290. list[i].checked = false
  291. }
  292. }
  293. if (k == list.length) {
  294. data[j].checked = true
  295. } else {
  296. data[j].checked = false
  297. }
  298. totalLength += list.length
  299. if (length == totalLength) {
  300. status = true
  301. } else {
  302. status = false
  303. }
  304. uni.$emit('change-footer-status', status)
  305. if (!this.isCheckedAll) {
  306. this.renderCart()
  307. }
  308. this.cartList = Object.assign([], data)
  309. },
  310. changeSingleStatu2 (e) {
  311. var value=e.detail.value
  312. let data = this.cartList
  313. let length = 0
  314. let totalLength = 0
  315. let status = false
  316. for(var j in data){
  317. let list = data[j].goods
  318. let k = 0
  319. for (var i in list) {
  320. if (!this.isCheckedAll && list[i].disabled) {
  321. list[i].checked = false
  322. data[j].checked = false
  323. k++
  324. } else {
  325. list[i].checked = value.indexOf(data[j].store_id)>-1?true:false
  326. data[j].checked = value.indexOf(data[j].store_id)>-1?true:false
  327. }
  328. }
  329. }
  330. for (var q in data) {
  331. if (value.indexOf(data[q].store_id)>-1) {
  332. length += data[q].goods.length
  333. }
  334. totalLength += data[q].goods.length
  335. }
  336. if (length == totalLength) {
  337. status = true
  338. } else {
  339. status = false
  340. }
  341. uni.$emit('change-footer-status', status)
  342. if (!this.isCheckedAll) {
  343. this.renderCart()
  344. }
  345. this.cartList = Object.assign([], data)
  346. },
  347. /*
  348. * reduceNumber: 数量减少
  349. * @param: id 当前减少的购物车id
  350. * @param: amount 数量
  351. * @param: i 当前减少的购物车组的index
  352. * @param: index 当前减少的购物车的index
  353. */
  354. reduceNumber (id, amount, i, index) {
  355. if (amount > 1) {
  356. amount--
  357. this.updateCartQuantity(id, amount, i, index)
  358. } else {
  359. uni.showToast({icon:'none',title: {
  360. message: '受不了了, 宝贝不能再少了'
  361. }})
  362. }
  363. },
  364. /*
  365. * addNumber: 数量增加
  366. * @param: id 当前增加的购物车id
  367. * @param: amount 数量
  368. * @param: i 当前增加的购物车组的index
  369. * @param: index 当前增加的购物车的index
  370. */
  371. addNumber (id, amount, i, index) {
  372. amount++
  373. this.updateCartQuantity(id, amount, i, index)
  374. },
  375. /*
  376. * updateCartQuantity: 商品数量加减更新数
  377. * @param: id 当前减少的购物车id
  378. * @param: amount 数量
  379. * @param: i 当前购物车组的index
  380. * @param: index 当前购物车的index
  381. */
  382. updateCartQuantity (id, amount, i, index) {
  383. uni.showLoading({ title: '加载中' })
  384. cartUpdate(id, amount).then(
  385. res => {
  386. if (res) {
  387. uni.hideLoading()
  388. this.cartList[i].goods[index].goods_num = amount
  389. this.cartList[i].goods[index].goods_price = res.result.goods_price
  390. this.renderCart()
  391. // this.getCartNumber()
  392. }
  393. },
  394. error => {
  395. uni.showToast({icon:'none',title: error.message})
  396. uni.hideLoading()
  397. }
  398. )
  399. },
  400. /*
  401. * getCartNumber: 获取购物车列表
  402. */
  403. getCartNumber () {
  404. cartQuantity().then(res => {
  405. if (res) {
  406. this.setCartNumber(res.quantity)
  407. }
  408. })
  409. },
  410. /*
  411. * goDetail: 跳转到详情
  412. */
  413. goDetail (id) {
  414. uni.navigateTo({ url: '/pages/home/goodsdetail/Goodsdetail'+'?'+urlencode( { goods_id: id } )})
  415. },
  416. goVoucher (index) {
  417. this.saveVoucher(this.cartList[index].voucher_list)
  418. uni.navigateTo({ url: '/pages/home/storedetail/StoreVoucher' })
  419. }
  420. }
  421. }
  422. </script>
  423. <style lang="scss" scoped>
  424. .cart-list-wrapper {
  425. overflow-y: auto;
  426. position: fixed;
  427. width: 100%;
  428. bottom: $footerHeight;
  429. padding-bottom: constant(safe-area-inset-bottom);/*兼容 IOS<11.2*/padding-bottom: env(safe-area-inset-bottom);/*兼容 IOS>11.2*/
  430. top: $headerHeight;
  431. margin-top:var(--status-bar-height);
  432. .cart-list{margin-bottom:$modelSpace;background:#fff;}
  433. .store-info{border-bottom:1px dashed #eee;display:flex;margin-left:$pageSpace;margin-right:$pageSpace;align-content: center;align-items: center;
  434. .wrapper{display: flex;align-items: center}
  435. .store-name{font-size:$h2;line-height: 2rem;flex:1;}
  436. .voucher{width:2rem;font-size:$subFontSize;color:$primaryColor;border:1px solid $primaryColor;text-align: center;border-radius:.1rem;}
  437. }
  438. .list-checkbox {
  439. width: 1rem;
  440. height: 1rem;
  441. flex-basis: 1rem;
  442. flex-shrink: 0;
  443. position: relative;
  444. margin-right:0.25rem;
  445. .label {
  446. padding:0;
  447. position: absolute;
  448. left:0;
  449. top: 0;
  450. width: 1rem;
  451. height: 1rem;
  452. display: inline-block;
  453. border-radius:50%;
  454. border:1px solid #333;
  455. box-sizing:border-box;
  456. .iconfont{display: none;line-height: 1rem;text-align: center;}
  457. &.checked{
  458. border-color:$primaryColor;
  459. background-color:$primaryColor;
  460. .iconfont{display: block;color:#fff}
  461. }
  462. }
  463. .checkbox {
  464. position: relative;
  465. width: 1rem;
  466. margin: 0;
  467. opacity: 0;
  468. background-color: #fff;
  469. }
  470. }
  471. .list {
  472. background-color: #fff;
  473. padding: 0.6rem;
  474. display: flex;
  475. align-content: center;
  476. align-items: center;
  477. .list-item {
  478. display: flex;
  479. width: 100%;
  480. flex-direction: column;
  481. .div.item {
  482. display: flex;
  483. width: 100%;
  484. .div.ui-image {
  485. flex-shrink: 0;
  486. width: 4.5rem;
  487. height: 4.5rem;
  488. flex-basis: 4.5rem;
  489. position: relative;
  490. .img {
  491. width: 100%;
  492. height: 100%;
  493. border-radius: 0.4rem;
  494. }
  495. .span.promos {
  496. position: absolute;
  497. width: 1.8rem;
  498. height: 0.95rem;
  499. color: #ffffff;
  500. font-size:$h6;
  501. top: 0;
  502. /* left: 0; */
  503. background-size: cover;
  504. font-weight: 100;
  505. line-height: 0.95rem;
  506. text-align: left;
  507. padding-left:0.25rem;
  508. }
  509. .span.stock-info {
  510. position: absolute;
  511. height: 1rem;
  512. background: rgba(243, 244, 245, 1);
  513. line-height: 1rem;
  514. text-align: center;
  515. font-size:$subFontSize;
  516. color: $primaryColor;
  517. width: 100%;
  518. bottom: 0;
  519. left: 0;
  520. }
  521. }
  522. .div.list-info {
  523. margin-left: 0.4rem;
  524. width: 100%;
  525. display: flex;
  526. flex-direction: column;
  527. align-content: center;
  528. justify-content: space-between;
  529. .product-header {
  530. display: flex;
  531. align-items: center;
  532. .promos-icon {
  533. width: 0.8rem;
  534. height: 0.8rem;
  535. margin-right: 0.2rem;
  536. }
  537. .product-title {
  538. font-size: $subFontSize;
  539. line-height:1rem;
  540. height: 2rem;
  541. padding: 0;
  542. display: -webkit-box;
  543. -webkit-box-orient: vertical;
  544. -webkit-line-clamp: 2;
  545. overflow: hidden;
  546. &.disabled-list {
  547. color: #a4aab3;
  548. }
  549. }
  550. }
  551. .h3 {
  552. font-size:$subFontSize;
  553. color: rgba(78, 84, 93, 1);
  554. padding: 0;
  555. margin: 0;
  556. display: -webkit-box;
  557. -webkit-box-orient: vertical;
  558. -webkit-line-clamp: 2;
  559. overflow: hidden;
  560. &.disabled-list {
  561. color: #a4aab3;
  562. }
  563. }
  564. .h3.property-info {
  565. font-size:$fontSize;
  566. color: #7c7f88;
  567. }
  568. .div.info-price {
  569. width: 100%;
  570. display: flex;
  571. justify-content: space-between;
  572. align-content: flex-end;
  573. align-items: flex-end;
  574. .p {
  575. font-size: $mainFontSize;
  576. color: $primaryColor;
  577. padding: 0;
  578. margin: 0;
  579. display: inline-block;
  580. &.disabled-list {
  581. color: #a4aab3;
  582. }
  583. }
  584. }
  585. .div .ui-number {
  586. height: 1.2rem;
  587. display: flex;
  588. border-radius: 0.15rem 0 0 0.15rem;
  589. input,
  590. .div {
  591. height: 1.2rem;
  592. text-align: center;
  593. color: #404245;
  594. display: inline-block;
  595. padding: 0;
  596. margin: 0;
  597. border: 0;
  598. outline-offset: 0;
  599. }
  600. .ui-common {
  601. line-height: 1.2rem;
  602. width: 1.3rem;
  603. height: 1.2rem;
  604. border: 1px solid #c7c7cd;
  605. cursor: pointer;
  606. }
  607. .reduce {
  608. border-right: 0;
  609. }
  610. .reduce-opacity {
  611. opacity: 0.4;
  612. }
  613. .add {
  614. border-left: 0;
  615. }
  616. .number {
  617. width: 1.3rem;
  618. border: 1px solid #c7c7cd;
  619. border-radius: 0;
  620. border-image-width: 0;
  621. box-shadow: 0;
  622. vertical-align: bottom;
  623. &:focus {
  624. outline: none;
  625. }
  626. }
  627. }
  628. }
  629. }
  630. .p.list-promotion-info {
  631. margin-top: 0.6rem;
  632. padding: 0.4rem 0;
  633. line-height: auto;
  634. font-size:$h6;
  635. color: #000;
  636. background: #f8f8f8;
  637. width: 100%;
  638. .span {
  639. border: 1px solid $primaryColor;
  640. padding: 1px 0.2rem;
  641. border-radius: 0.1rem;
  642. font-size:$h6;
  643. color: $primaryColor;
  644. margin: 0 0.4rem;
  645. text-align: center;
  646. }
  647. }
  648. }
  649. }
  650. }
  651. .has-bottom {
  652. bottom: 4.7rem;
  653. }
  654. .bl_goods_list{overflow: hidden;
  655. .bl_goods{float: left;height: 2rem;line-height: 2rem;
  656. .img{width:2rem;height: 2rem;margin-right: .2rem;}
  657. }
  658. }
  659. </style>