index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. <template>
  2. <view class="app-container" :class="isNoticebar ? 'hasNoticebar':''">
  3. <view class="noticebar" v-if="isNoticebar">
  4. <uni-notice-bar v-if="noticeContent" scrollable="true" single="true" showClose="true" :text="noticeContent" background-color="#f6e6e7" color="#de3749" @close="closeNoticebar"></uni-notice-bar>
  5. </view>
  6. <view class="top" :class="isNoticebar ? 'hasNoticebar':''">
  7. <view class="total">共{{totalNum}}件商品</view>
  8. <view v-if="!isEditor" @tap="isEditor = !isEditor">编辑</view>
  9. <view v-else @tap="isEditor = !isEditor">完成</view>
  10. </view>
  11. <view class="list">
  12. <block v-for="(item, index) in goodsList" :key='index'>
  13. <view class="item">
  14. <view class="check" v-if="item.selected" @tap="selectList(index)"><image src="@/static/icon/select_1.png" mode=""></image></view>
  15. <view class="check" v-else @tap="selectList(index)"><image src="@/static/icon/select_0.png" mode=""></view>
  16. <image :src="item.goodsImg" mode="aspectFill" class="img"></image>
  17. <view class="right">
  18. <view class="title ellipsis-2">{{item.goodsName}}</view>
  19. <view class="des ellipsis">{{item.specValue}}</view>
  20. <view class="last">
  21. <view class="price">
  22. <view class="price-1">¥{{item.price | numToFixed}}</view>
  23. <view class="price-2">¥{{item.orgPrice | numToFixed}}</view>
  24. </view>
  25. <u-number-box
  26. @tap.stop
  27. v-model="item.num"
  28. :min="1"
  29. :buttonSize="26"
  30. iconStyle="font-size: 12px;"
  31. @change="changeCount($event, index)">
  32. </u-number-box>
  33. </view>
  34. </view>
  35. </view>
  36. </block>
  37. </view>
  38. <no-data v-if="!goodsList.length" :showText="'购物车暂无商品'"></no-data>
  39. <view class="bottom">
  40. <view class="check" @tap="selectAll">
  41. <image src="@/static/icon/select_1.png" mode="" v-if="selectAllStatus">
  42. <image src="@/static/icon/select_0.png" mode="" v-else>
  43. <text class="text">全选</text>
  44. </view>
  45. <view class="right" v-if="!isEditor">
  46. <view class="price">
  47. <view class="price-1">合计:<text>¥{{totalPrice}}</text></view>
  48. <view class="price-2">不含运费</view>
  49. </view>
  50. <view class="button"><button @tap="toOrder">去结算</button></view>
  51. </view>
  52. <view class="right" v-else>
  53. <button class="delete" @tap="clickDelete">删除</button>
  54. </view>
  55. </view>
  56. <modal-dialog showText="确定要删除选中的商品吗?" :isShowDialog="isDialog" @cancel="isDialog = false" @confirm="confirmDelete"></modal-dialog>
  57. </view>
  58. </template>
  59. <script>
  60. import {mapState} from 'vuex';
  61. import modalDialog from '@/components/modalDialog.vue';
  62. export default {
  63. components:{
  64. modalDialog
  65. },
  66. data() {
  67. return {
  68. goodsList: [],
  69. totalPrice: 0, // 总价,初始为0
  70. totalNum: 0,
  71. selectAllStatus: true, // 全选状态,默认全选
  72. isEditor: false, // 是否编辑
  73. isDialog: false, // 是否显示删除弹窗
  74. isNoticebar: false, // 是否显示通告栏
  75. noticeContent: '', // 公告内容
  76. }
  77. },
  78. computed:{
  79. ...mapState(['userInfo', 'isLogin', 'userId'])
  80. },
  81. onShow() {
  82. this.getGoodsList();
  83. },
  84. onLoad() {
  85. this.getNoticebar();
  86. },
  87. methods: {
  88. // 获取公告栏
  89. getNoticebar() {
  90. this.$axios({
  91. url: '/shpping/cart/notice',
  92. method: 'get',
  93. params: {
  94. userId: this.userId
  95. }
  96. }).then(res => {
  97. this.noticeContent = res.data;
  98. this.isNoticebar = res.data ? true : false;
  99. })
  100. },
  101. // 获取商品列表
  102. getGoodsList() {
  103. this.$axios({
  104. url: '/shpping/cart/list',
  105. method: 'get',
  106. params: {
  107. userId: this.userId
  108. }
  109. }).then(res => {
  110. this.goodsList = res.data.shoppingCartLists;
  111. this.totalNum = res.data.totalNum;
  112. this.goodsList.forEach((item, index) => {
  113. item.selected = true;
  114. })
  115. this.selectAllStatus = true;
  116. this.getTotalPrice();
  117. })
  118. },
  119. // 统计总价
  120. getTotalPrice() {
  121. // 获取购物车列表
  122. let goodsList = this.goodsList;
  123. let total = 0;
  124. // 循环列表
  125. for(let i = 0; i<goodsList.length; i++) {
  126. // 判断选中才会计算价格
  127. if(goodsList[i].selected) {
  128. // 所有价格加起来
  129. total += goodsList[i].num * goodsList[i].price;
  130. }
  131. }
  132. // 赋值到data中渲染到页面
  133. this.goodsList = goodsList;
  134. this.totalPrice = total.toFixed(2);
  135. },
  136. // 选择事件
  137. selectList(index) {
  138. // 获取购物车列表
  139. let goodsList = this.goodsList;
  140. // 获取当前商品的选中状态
  141. let selected = goodsList[index].selected;
  142. // 改变状态
  143. goodsList[index].selected = !selected;
  144. this.goodsList = goodsList;
  145. // 改变全选状态
  146. for (var i=0; i<this.goodsList.length; i++){
  147. // 当状态为全选时,每个元素其中有一个为false,则取消全选
  148. // 当状态为非全选时,每个元素都为true,则全选
  149. if(this.selectAllStatus){
  150. if(!this.goodsList[i].selected){
  151. this.selectAllStatus = false;
  152. break;
  153. }
  154. }else {
  155. if(this.goodsList[i].selected){
  156. this.selectAllStatus = true;
  157. }else {
  158. this.selectAllStatus = false;
  159. break;
  160. }
  161. }
  162. }
  163. // 重新获取总价
  164. this.getTotalPrice();
  165. },
  166. // 全选事件
  167. selectAll(e) {
  168. // 是否全选状态
  169. let selectAllStatus = this.selectAllStatus;
  170. selectAllStatus = !selectAllStatus;
  171. let goodsList = this.goodsList;
  172. for (let i = 0; i < goodsList.length; i++) {
  173. // 改变所有商品状态
  174. goodsList[i].selected = selectAllStatus;
  175. }
  176. this.selectAllStatus = selectAllStatus;
  177. this.goodsList = goodsList;
  178. // 重新获取总价
  179. this.getTotalPrice();
  180. },
  181. // 更改数量
  182. changeCount(e, index) {
  183. this.goodsList[index].num = e.value;
  184. this.initCart();
  185. },
  186. // 修改数量后更新购物车数据
  187. initCart() {
  188. let buyGoods = [];
  189. this.goodsList.forEach((item, index)=> {
  190. let goodsItem = {
  191. goodsId: item.goodsId,
  192. goodsSpecId: item.goodsSpecId,
  193. num: item.num,
  194. shoppingCartId: item.shoppingCartId,
  195. secKillId: item.secKillId || '',
  196. promotionGroupId: item.promotionGroupId || '',
  197. };
  198. buyGoods.push(goodsItem);
  199. })
  200. this.$axios({
  201. url: '/shpping/cart/add',
  202. type: 'application/json',
  203. params: {
  204. userId: this.userId,
  205. buyGoods: buyGoods,
  206. },
  207. }).then(res => {
  208. this.totalNum = res.data.totalNum;
  209. this.getTotalPrice();
  210. })
  211. },
  212. // 点击删除
  213. clickDelete() {
  214. let delIds = [];
  215. for(let i = 0; i < this.goodsList.length; i++) {
  216. if(this.goodsList[i].selected) {
  217. delIds.push(this.goodsList[i].shoppingCartId)
  218. }
  219. }
  220. if(delIds.length < 1) {
  221. return this.$toast('至少选择一件商品');
  222. }
  223. this.isDialog = true;
  224. },
  225. // 确认删除
  226. confirmDelete() {
  227. let delIds = [];
  228. for(let i = 0; i < this.goodsList.length; i++) {
  229. if(this.goodsList[i].selected) {
  230. delIds.push(this.goodsList[i].shoppingCartId)
  231. }
  232. }
  233. this.$axios({
  234. url: '/shpping/cart/remove',
  235. params: {
  236. shoppingCartIds: delIds,
  237. userId: this.userId
  238. }
  239. }).then(res => {
  240. this.isDialog = false;
  241. this.isEditor = false;
  242. this.$successToast('删除成功');
  243. this.getGoodsList();
  244. })
  245. },
  246. // 去结算
  247. toOrder() {
  248. let buyList = [];
  249. this.goodsList.forEach((item, index)=> {
  250. if(item.selected) {
  251. let goodsItem = {
  252. goodsId: item.goodsId,
  253. goodsSpecId: item.goodsSpecId,
  254. num: item.num,
  255. shoppingCartId: item.shoppingCartId,
  256. secKillId: item.secKillId || '',
  257. promotionGroupId: item.promotionGroupId || '',
  258. };
  259. buyList.push(goodsItem);
  260. }
  261. })
  262. if(buyList.length < 1) {
  263. return this.$toast('至少选择一件商品');
  264. }
  265. // 跳转结算页面
  266. uni.navigateTo({
  267. url: '/packageGoods/pages/order?buyList=' + JSON.stringify(buyList)
  268. })
  269. },
  270. // 关闭通告栏
  271. closeNoticebar() {
  272. this.isNoticebar = false;
  273. }
  274. }
  275. }
  276. </script>
  277. <style lang="scss">
  278. .app-container {
  279. background: #F4F2F2;
  280. box-sizing: border-box;
  281. }
  282. .app-container {
  283. height: auto;
  284. padding: 110rpx 0;
  285. &.hasNoticebar {
  286. padding-top: 174rpx;
  287. }
  288. .noticebar {
  289. position: fixed;
  290. top: 0;
  291. left: 0;
  292. width: 100%;
  293. z-index: 100;
  294. }
  295. .top {
  296. position: fixed;
  297. top: 0;
  298. left: 0;
  299. z-index: 99;
  300. width: 100%;
  301. padding: 0 20rpx;
  302. box-sizing: border-box;
  303. background: #FFFFFF;
  304. height: 88rpx;
  305. display: flex;
  306. justify-content: space-between;
  307. align-items: center;
  308. border-bottom: 1px solid #F4F2F2;
  309. &.hasNoticebar {
  310. top: 64rpx;
  311. }
  312. .total {
  313. font-size: 32rpx;
  314. }
  315. }
  316. .list {
  317. padding: 0 20rpx;
  318. .item {
  319. margin-bottom: 20rpx;
  320. border-radius: 10rpx;
  321. padding: 20rpx 20rpx;
  322. display: flex;
  323. align-items: center;
  324. background: #FFFFFF;
  325. .check {
  326. image {
  327. width: 32rpx;
  328. height: 32rpx;
  329. display: block;
  330. }
  331. }
  332. .img {
  333. width: 180rpx;
  334. height: 180rpx;
  335. display: block;
  336. margin: 0 20rpx;
  337. flex-shrink: 0;
  338. }
  339. .right {
  340. width: 420rpx;
  341. height: 190rpx;
  342. display: flex;
  343. justify-content: space-between;
  344. flex-direction: column;
  345. .title {
  346. font-size: 28rpx;
  347. color: #333333;
  348. line-height: 36rpx;
  349. }
  350. .des {
  351. font-size: 24rpx;
  352. color: #999999;
  353. line-height: 36rpx;
  354. }
  355. .last {
  356. display: flex;
  357. justify-content: space-between;
  358. align-items: center;
  359. .price {
  360. display: flex;
  361. flex-direction: column;
  362. }
  363. .price-1 {
  364. font-size: 32rpx;
  365. color: #FF3F42;
  366. line-height: 36rpx;
  367. }
  368. .price-2 {
  369. font-size: 26rpx;
  370. color: #666666;
  371. line-height: 30rpx;
  372. text-decoration: line-through;
  373. }
  374. }
  375. }
  376. }
  377. }
  378. .bottom {
  379. position: fixed;
  380. left: 0;
  381. bottom: 0;
  382. z-index: 99;
  383. width: 100%;
  384. box-sizing: border-box;
  385. background: #FFFFFF;
  386. height: 100rpx;
  387. display: flex;
  388. align-items: center;
  389. justify-content: space-between;
  390. padding: 0 20rpx;
  391. border-top: 1px solid #F4F2F2;
  392. .check {
  393. display: flex;
  394. align-items: center;
  395. image {
  396. width: 32rpx;
  397. height: 32rpx;
  398. display: block;
  399. margin-right: 20rpx;
  400. }
  401. }
  402. .right {
  403. display: flex;
  404. align-items: center;
  405. .price {
  406. display: flex;
  407. flex-direction: column;
  408. margin-right: 20rpx;
  409. }
  410. .price-1 {
  411. font-size: 28rpx;
  412. line-height: 36rpx;
  413. text {
  414. color: #FF3F42;
  415. }
  416. }
  417. .price-2 {
  418. font-size: 24rpx;
  419. color: #999999;
  420. line-height: 30rpx;
  421. text-align: right;
  422. }
  423. .button {
  424. button {
  425. height: 80rpx;
  426. line-height: 80rpx;
  427. padding: 0;
  428. border-radius: 80rpx;
  429. font-size: 30rpx;
  430. color: #fff;
  431. background: linear-gradient(-90deg,#ff3f42 0%, #fe781f 100%);
  432. padding: 0 40rpx;
  433. }
  434. }
  435. .delete {
  436. width: 170rpx;
  437. height: 80rpx;
  438. line-height: 80rpx;
  439. text-align: center;
  440. padding: 0;
  441. border-radius: 80rpx;
  442. font-size: 30rpx;
  443. color: #FF3F42;
  444. border: 1px solid #FF3F42;
  445. }
  446. }
  447. }
  448. }
  449. </style>