cart.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. <template>
  2. <view >
  3. <view class="container">
  4. <!-- 空白页 -->
  5. <view v-if="!hasLogin || empty === true" class="empty">
  6. <image src="/static/error/emptyCart.png" class="emptyImg" mode="aspectFit"></image>
  7. <view v-if="hasLogin" class="empty-tips">
  8. 空空如也
  9. <navigator class="navigator" v-if="hasLogin" url="../index/index" open-type="switchTab">随便逛逛></navigator>
  10. </view>
  11. <view v-else class="empty-tips">
  12. 空空如也
  13. <view class="navigator" @click="navToLogin">去登陆></view>
  14. </view>
  15. </view>
  16. <scroll-view v-else>
  17. <!-- 列表 -->
  18. <view class="header flex1">
  19. <view class="header-1">共{{number}}件宝贝</view>
  20. <!-- <view class="header-2">管理</view> -->
  21. </view>
  22. <view class="cart-list">
  23. <view class="cart">
  24. <view class="cart-header">
  25. <view class="header-select" @click="check('all')">
  26. <view class="iconfont iconroundcheckfill checked-img" :class="{ 'checked': allChecked }"></view>
  27. <view class="word-1">全选</view>
  28. </view>
  29. <view class="clear-btn" @click="allChecked ? clearCart() : ''" :class="{ show: allChecked }"><text>清空</text></view>
  30. </view>
  31. <scroll-view v-for="(item, index) in cartList" :key="item.id">
  32. <uni-swipe-action>
  33. <uni-swipe-action-item class="cart-frame" :options="options" @click="swipeClick($event,index)">
  34. <view class="cart-item">
  35. <view class="iconfont iconroundcheckfill choose" :class="{ checked: item.checked }" @click="check('item', index)"></view>
  36. <view class="image-wrapper">
  37. <image
  38. :src="item.productInfo.image"
  39. :class="[item.loaded]"
  40. mode="aspectFill"
  41. lazy-load
  42. @load="onImageLoad('cartList', index)"
  43. @error="onImageError('cartList', index)"
  44. ></image>
  45. </view>
  46. <view class="item-right">
  47. <text class="title">{{ item.productInfo.store_name }}</text>
  48. <view class="attr">
  49. <text class="attr-text">{{ item.productInfo.attrInfo.suk }}</text>
  50. </view>
  51. <view class="row">
  52. <view >
  53. <text class="price-1">¥</text>
  54. <text class="price-2">{{ item.productInfo.price }}</text>
  55. </view>
  56. <uni-number-box
  57. class="step"
  58. :min="1"
  59. :max="item.productInfo.stock"
  60. :value="item.cart_num > item.productInfo.stock ? item.productInfo.stock : item.cart_num"
  61. :isMax="item.cart_num >= item.productInfo.stock ? true : false"
  62. :isMin="item.cart_num === 1"
  63. :index="index"
  64. @eventChange="numberChange"
  65. ></uni-number-box>
  66. </view>
  67. </view>
  68. </view>
  69. </uni-swipe-action-item>
  70. </uni-swipe-action>
  71. </scroll-view>
  72. </view>
  73. </view>
  74. </scroll-view>
  75. <!-- 底部菜单栏 -->
  76. <view class="action-section" v-if=" empty !== true">
  77. <view class="checkbox" @click="check('all')">
  78. <!-- <view class="checked-img" >
  79. <image class="img" src="https://mmz.liuniu946.com/statics/img/img09.png" v-if=""></image>
  80. <image class="img" src="../../static/img/img34.png"></image>
  81. </view> -->
  82. <view class="iconfont iconroundcheckfill checked-img" :class="{ 'checked': allChecked }"></view>
  83. <view class="checked-word" >全选</view>
  84. </view>
  85. <view class="total-box">
  86. <view >
  87. <text class="word">合计:</text>
  88. <text class="price">¥ {{ total }}</text>
  89. </view>
  90. <button type="primary" class="confirm-btn" @click="createOrder">
  91. <text >结算</text>
  92. </button>
  93. </view>
  94. </view>
  95. </view>
  96. </view>
  97. </template>
  98. <script>
  99. import { getCartList, getCartNum, cartDel } from '@/api/cart.js';
  100. import { mapState } from 'vuex';
  101. import uniNumberBox from '@/components/uni-number-box.vue';
  102. import uniSwipeAction from '@/components/uni-swipe-action/uni-swipe-action.vue'
  103. import uniSwipeActionItem from '@/components/uni-swipe-action-item/uni-swipe-action-item.vue'
  104. export default {
  105. components: {
  106. uniNumberBox,
  107. uniSwipeAction,
  108. uniSwipeActionItem
  109. },
  110. data() {
  111. return {
  112. number:0,//商品数量
  113. total: 0, //总价格
  114. allChecked: false, //全选状态 true|false
  115. empty: false, //空白页现实 true|false
  116. cartList: [],
  117. options:[
  118. // {
  119. // text: '取消',
  120. // style: {
  121. // backgroundColor: '#ff8000'
  122. // }
  123. // },
  124. {
  125. text: '删除',
  126. style: {
  127. backgroundColor: '#FC4141'
  128. }
  129. }
  130. ]
  131. };
  132. },
  133. onShow() {
  134. // 只有登录时才加载数据
  135. if (this.hasLogin) {
  136. this.loadData();
  137. }
  138. console.log(this.empty,102)
  139. },
  140. watch: {
  141. //显示空白页
  142. cartList(e) {
  143. let empty = e.length === 0 ? true : false;
  144. if (this.empty !== empty) {
  145. this.empty = empty;
  146. }
  147. }
  148. },
  149. computed: {
  150. ...mapState(['hasLogin'])
  151. },
  152. methods: {
  153. //请求数据
  154. async loadData() {
  155. let obj = this;
  156. getCartList({})
  157. .then(function(e) {
  158. console.log(e,'101');
  159. // 获取当前购物车物品增加数量
  160. let nub = obj.cartList.length;
  161. let aArray = obj.cartList.reverse();
  162. let bArray = e.data.valid.reverse();
  163. obj.cartList = bArray
  164. .map((item, ind) => {
  165. // 设置返回数据默认为勾选状态
  166. item.checked = false;
  167. // 获取相同数组之前对象的数据
  168. let carlist = obj.cartList[ind];
  169. // 判断之前是否已经加载完毕
  170. if (carlist && carlist.loaded == 'loaded') {
  171. item.loaded = 'loaded';
  172. }
  173. return item;
  174. })
  175. .reverse();
  176. obj.calcTotal(); //计算总价
  177. obj.number = obj.cartList.length;
  178. })
  179. .catch(function(e) {
  180. console.log(e);
  181. });
  182. },
  183. //监听image加载完成
  184. onImageLoad(key, index) {
  185. // 修改载入完成后图片class样式
  186. this.$set(this[key][index], 'loaded', 'loaded');
  187. },
  188. //监听image加载失败
  189. onImageError(key, index) {
  190. this[key][index].image = '/static/error/errorImage.jpg';
  191. },
  192. // 跳转到登录页
  193. navToLogin() {
  194. let url = '/pages/public/login';
  195. // #ifdef H5
  196. let weichatBrowser = uni.getStorageSync('weichatBrowser');
  197. // 判断是否为微信浏览器
  198. if (weichatBrowser) {
  199. url = '/pages/public/wxLogin';
  200. }
  201. // #endif
  202. // #ifdef MP-WEIXIN
  203. url = '/pages/public/wxLogin';
  204. // #endif
  205. uni.navigateTo({
  206. url: url
  207. });
  208. },
  209. //选中状态处理
  210. check(type, index) {
  211. if (type === 'item') {
  212. this.cartList[index].checked = !this.cartList[index].checked;
  213. } else {
  214. const checked = !this.allChecked;
  215. const list = this.cartList;
  216. list.forEach(item => {
  217. item.checked = checked;
  218. });
  219. this.allChecked = checked;
  220. }
  221. this.calcTotal(type);
  222. },
  223. //数量
  224. numberChange(data) {
  225. let arr = this.cartList[data.index];
  226. arr.cart_num = data.number;
  227. getCartNum({ id: arr.id, number: data.number });
  228. this.calcTotal();
  229. },
  230. // 滑动删除
  231. swipeClick(e, index) {
  232. let {
  233. content
  234. } = e
  235. if (content.text === '删除') {
  236. uni.showModal({
  237. title: '删除',
  238. content: '是否删除',
  239. success: (res) => {
  240. if (res.confirm) {
  241. this.deleteCartItem(index)
  242. } else if (res.cancel) {
  243. }
  244. }
  245. });
  246. }
  247. },
  248. //删除
  249. deleteCartItem(index) {
  250. let list = this.cartList;
  251. let row = list[index];
  252. let id = row.id;
  253. cartDel({
  254. ids: id
  255. });
  256. this.cartList.splice(index, 1);
  257. uni.hideLoading();
  258. this.calcTotal();
  259. },
  260. //清空
  261. clearCart() {
  262. uni.showModal({
  263. content: '清空购物车?',
  264. success: e => {
  265. if (e.confirm) {
  266. let st = this.cartList.map(e => {
  267. return e.id;
  268. });
  269. cartDel({
  270. ids: st.join(',')
  271. }).then(e => {
  272. console.log(e);
  273. });
  274. this.cartList = [];
  275. }
  276. }
  277. });
  278. },
  279. //计算总价
  280. calcTotal() {
  281. let list = this.cartList;
  282. if (list.length === 0) {
  283. this.empty = true;
  284. return;
  285. }
  286. let total = 0;
  287. let checked = true;
  288. list.forEach(item => {
  289. if (item.checked === true) {
  290. total += item.productInfo.price * item.cart_num;
  291. } else if (checked === true) {
  292. checked = false;
  293. }
  294. });
  295. this.allChecked = checked;
  296. this.total = Number(total.toFixed(2));
  297. },
  298. //创建订单
  299. createOrder() {
  300. let list = this.cartList;
  301. let goodsData = [];
  302. list.forEach(item => {
  303. if (item.checked) {
  304. goodsData.push(item.id);
  305. }
  306. });
  307. if ( this.total == 0 ) {
  308. uni.showToast({
  309. title: '请先选择需购买的商品',
  310. icon: 'none'
  311. });
  312. } else {
  313. uni.navigateTo({
  314. url: '/pages/order/createOrder?id=' + goodsData.join(',')
  315. });
  316. }
  317. }
  318. }
  319. };
  320. </script>
  321. <style lang="scss">
  322. page {
  323. min-height: 100%;
  324. }
  325. .container {
  326. padding-bottom: 134rpx;
  327. background-color: $page-color-base;
  328. height: 100%;
  329. position: relative;
  330. /* 空白页 */
  331. .empty {
  332. position: fixed;
  333. left: 0;
  334. top: 0;
  335. width: 100%;
  336. height: 100vh;
  337. padding-bottom: 100rpx;
  338. display: flex;
  339. justify-content: center;
  340. flex-direction: column;
  341. align-items: center;
  342. background: #fff;
  343. .emptyImg {
  344. width: 300rpx;
  345. height: 250rpx;
  346. margin-bottom: 30rpx;
  347. }
  348. .empty-tips {
  349. display: flex;
  350. font-size: $font-sm + 2rpx;
  351. color: $font-color-disabled;
  352. .navigator {
  353. color: $uni-color-primary;
  354. margin-left: 16rpx;
  355. }
  356. }
  357. }
  358. .header{
  359. padding: 30rpx 25rpx;
  360. background:#FFFFFF;
  361. .header-1{
  362. font-size:24rpx;
  363. font-weight:400;
  364. color:#666666;
  365. }
  366. .header-2{
  367. font-size:28rpx;
  368. font-weight:400;
  369. color:#333333;
  370. }
  371. }
  372. /* 列表 */
  373. .cart-list{
  374. width: 100%;
  375. padding: 24rpx;
  376. .cart{
  377. width: 100%;
  378. background-color: #FFFFFF;
  379. padding: 20rpx 20rpx 30rpx 30rpx;
  380. border-radius: 10rpx;
  381. .cart-header{
  382. margin-bottom: 18rpx;
  383. display: flex;
  384. align-items: center;
  385. justify-content: space-between;
  386. .header-select {
  387. display: flex;
  388. align-items: center;
  389. .checked-img{
  390. font-size: 28rpx;
  391. margin-right: 10rpx;
  392. color: $font-color-disabled;
  393. }
  394. .checked-img.checked {
  395. color: $background-color;
  396. }
  397. .word-1{
  398. font-size:30rpx;
  399. font-weight:400;
  400. color:#1d2023;
  401. }
  402. }
  403. .clear-btn {
  404. height: 52rpx;
  405. line-height: 52rpx;
  406. // padding-left: 38rpx;
  407. font-size: $font-base;
  408. border-radius: 0 50px 50px 0;
  409. opacity: 0;
  410. transition: 0.2s;
  411. &.show {
  412. opacity: 1;
  413. }
  414. }
  415. }
  416. /* 购物车列表项 */
  417. .cart-item {
  418. display: flex;
  419. position: relative;
  420. // height: 200rpx;
  421. display: flex;
  422. align-items:center;
  423. padding: 10rpx 0;
  424. .choose{
  425. font-size: 28rpx;
  426. color: $font-color-disabled;
  427. margin-right: 20rpx;
  428. }
  429. .choose.checked {
  430. color: $background-color;
  431. }
  432. .image-wrapper {
  433. width: 20%;
  434. width: 160rpx;
  435. height: 160rpx;
  436. }
  437. .item-right {
  438. overflow: hidden;
  439. width: 440rpx;
  440. // height: 160rpx;
  441. display: flex;
  442. flex-direction: column;
  443. padding-left: 30rpx;
  444. .title{
  445. font-size:26rpx;
  446. font-weight:500;
  447. color:#333333;
  448. font-weight:550;
  449. overflow : hidden;
  450. text-overflow: ellipsis;
  451. display: -webkit-box;
  452. -webkit-line-clamp: 2;
  453. -webkit-box-orient: vertical;
  454. }
  455. .attr {
  456. margin-top: 20rpx;
  457. .attr-text {
  458. display: inline-block;
  459. padding: 0 20rpx;
  460. background:#f6f6f6;
  461. border-radius:10rpx;
  462. font-size:18rpx;
  463. font-weight:400;
  464. color:#606972;
  465. line-height: 50rpx;
  466. text-align: center;
  467. }
  468. }
  469. .row{
  470. display: flex;
  471. align-items:center;
  472. justify-content: space-between;
  473. margin-top: 5px;
  474. .price-1 {
  475. font-size:24rpx;
  476. font-weight:bold;
  477. color:#fa2740;
  478. }
  479. .price-2 {
  480. font-size:30rpx;
  481. font-weight:bold;
  482. color:#fa2740;
  483. }
  484. // .step {
  485. // width: 170rpx;
  486. // height: 45rpx;
  487. // }
  488. }
  489. }
  490. }
  491. }
  492. }
  493. /* 底部栏 */
  494. .action-section {
  495. width: 100%;
  496. background:#ffffff;
  497. box-shadow:0px -3px 7px 0px #e6e6e6;
  498. padding:20rpx 35rpx;
  499. display: flex;
  500. justify-content:space-between;
  501. position: fixed;
  502. bottom: 0rpx;
  503. /* #ifdef APP-PLUS */
  504. /* #endif */
  505. .checkbox {
  506. display: flex;
  507. justify-content:space-between;
  508. align-items: center;
  509. .checked-img{
  510. font-size: 28rpx;
  511. margin-right: 10rpx;
  512. color: $font-color-disabled;
  513. }
  514. .checked-img.checked {
  515. color: $background-color;
  516. }
  517. .checked-word{
  518. font-size:30rpx;
  519. font-weight:400;
  520. color:#1d2023;
  521. }
  522. }
  523. .total-box {
  524. display: flex;
  525. justify-content:space-between;
  526. .word {
  527. font-size:26rpx;
  528. font-weight:500;
  529. color:#333333;
  530. margin-right: 16rpx;
  531. }
  532. .price {
  533. font-size:26rpx;
  534. font-weight:550;
  535. color:#FA2740;
  536. margin-right: 34rpx;
  537. }
  538. .confirm-btn{
  539. width:160rpx;
  540. height:64rpx;
  541. background:$base-color;
  542. border-radius:32rpx;
  543. display: flex;
  544. justify-content:center;
  545. align-items: center;
  546. }
  547. }
  548. }
  549. }
  550. </style>