CartList.vue 20 KB

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