cart.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <template>
  2. <view class="content">
  3. <!-- 商品列表 -->
  4. <view class="shopbox" v-for="(shop,idx) in carts" :key="idx">
  5. <view class="shopbox-name" v-if="shop.storeName && shop.storeName != 'null'">
  6. <label style="margin-right: 30upx;">
  7. <checkbox :value="shop.checked" :checked="shop.checked" @click="checkShopChange(shop)" />
  8. </label>
  9. <text>{{shop.storeName}}</text>
  10. </view>
  11. <view class="goods-list">
  12. <view class="item" v-for="(item,index) in shop.list" :key="index">
  13. <label style="margin-right: 30upx;">
  14. <checkbox :value="item.checked" :checked="item.checked" @click="checkChange(item,shop)" />
  15. </label>
  16. <image class="goods-img" :src="item.productAttrImage==null||item.productAttrImage==''?item.productImage:item.productAttrImage" mode="aspectFit"></image>
  17. <view class="info-box">
  18. <view>
  19. <view class="title-box">
  20. <view class="tag">{{utils.getDictLabelName("storeProductType",item.productType)}}</view>
  21. <view class="title ellipsis">{{ item.productName }}</view>
  22. </view>
  23. <view class="intro ellipsis">{{item.productAttrName}}</view>
  24. </view>
  25. <view class="price-num">
  26. <view class="price">
  27. <text class="unit">¥</text>
  28. <text class="text">{{item.price}}</text>
  29. </view>
  30. <view class="num-box">
  31. <view class="img-box" @click="delNum(item)">
  32. <image v-if="item.cartNum <= 1" src="../../static/images/jian.png" mode=""></image>
  33. <image v-else src="../../static/images/jian2.png" mode=""></image>
  34. </view>
  35. <input type="number" @change="changeNum($event,item)" :value="item.cartNum" />
  36. <view class="img-box" @click="addNum(item)">
  37. <image src="../../static/images/add.png" mode=""></image>
  38. </view>
  39. </view>
  40. </view>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. <view v-if="carts.length == 0" class="no-data-box">
  46. <image src="../../static/images/no_data.png" mode="aspectFit"></image>
  47. <view class="empty-title">暂无数据</view>
  48. </view>
  49. <!-- 猜你喜欢 -->
  50. <view class="like-product">
  51. <likeProduct ref="product" />
  52. </view>
  53. <!-- 底部按钮 -->
  54. <view class="btn-foot">
  55. <view class="left">
  56. <label>
  57. <checkbox :checked="checkAll" @click="handleCheckAll()" />
  58. </label>
  59. <text class="text">全选</text>
  60. <text class="text" @click="delCart()">删除</text>
  61. </view>
  62. <view class="right">
  63. <view class="total">
  64. <text class="label">合计:</text>
  65. <view class="price">
  66. <text class="unit">¥</text>
  67. <text class="num">{{totalMoney.toFixed(2)}}</text>
  68. </view>
  69. </view>
  70. <view class="btn" @click="submit">结算</view>
  71. </view>
  72. </view>
  73. </view>
  74. </template>
  75. <script>
  76. import {getCarts,cartNum,delCart} from '@/api/product'
  77. import likeProduct from '@/components/likeProduct.vue'
  78. export default {
  79. components: {
  80. likeProduct
  81. },
  82. data() {
  83. return {
  84. totalMoney:0.00,
  85. carts:[],
  86. checkAll:false,
  87. }
  88. },
  89. onLoad() {
  90. // this.getCarts();
  91. },
  92. onShow() {
  93. this.getCarts();
  94. },
  95. onReachBottom() {
  96. this.$refs.product.getGoodsProducts();
  97. },
  98. methods: {
  99. delCart(){
  100. var selectCarts = this.carts.flatMap(item => item.list.filter(listItem => listItem.checked === true)).map(el => el.id);
  101. if(selectCarts.length==0){
  102. uni.showToast({
  103. icon:'none',
  104. title: "请选择商品删除",
  105. });
  106. return;
  107. }
  108. let data = {ids:selectCarts};
  109. delCart(data).then(
  110. res => {
  111. if(res.code==200){
  112. uni.showToast({
  113. icon:'success',
  114. title: "操作成功",
  115. });
  116. this.getCarts()
  117. }else{
  118. uni.showToast({
  119. icon:'none',
  120. title: res.msg,
  121. });
  122. }
  123. },
  124. rej => {}
  125. );
  126. console.log(selectCarts)
  127. },
  128. computedMoney(){
  129. var money=0;
  130. var that=this;
  131. this.carts.forEach((item,index,arr)=>{
  132. item.list.forEach(it => {
  133. if(it.checked){
  134. money+=it.price*it.cartNum;
  135. }
  136. });
  137. })
  138. console.log(money);
  139. this.totalMoney=money;
  140. },
  141. handleCheckAll(){
  142. this.checkAll=!this.checkAll;
  143. var that=this;
  144. this.carts.forEach((item,index,arr)=>{
  145. item.checked=that.checkAll;
  146. item.list.forEach(it => {
  147. it.checked=that.checkAll;
  148. });
  149. })
  150. this.computedMoney();
  151. },
  152. checkShopChange(item) {
  153. item.checked = !item.checked;
  154. item.list.forEach(it => {
  155. it.checked= item.checked;
  156. });
  157. // 新增:检查所有店铺是否都勾选,同步全局状态
  158. this.checkAll = this.carts.every(item => item.checked);
  159. this.computedMoney();
  160. },
  161. checkChange(item,shop){
  162. item.checked=!item.checked;
  163. shop.checked = shop.list.every(it => it.checked);
  164. // 新增:检查所有店铺是否都勾选,同步全局状态
  165. this.checkAll = this.carts.every(shop => shop.checked);
  166. this.computedMoney();
  167. },
  168. changeNum(e,item) {
  169. item.cartNum = e.detail.value.replace(/\D/g, '')
  170. if (item.cartNum <= 1) {
  171. uni.showToast({
  172. title: "已经是底线啦!",
  173. icon: "none",
  174. duration: 2000
  175. });
  176. return;
  177. }
  178. if(item.cartNum < 1) {
  179. item.cartNum = 1
  180. }
  181. if(item.cartNum>=item.stock){
  182. item.cartNum=item.stock;
  183. }
  184. this.changeCartNum(item)
  185. },
  186. changeCartNum(item){
  187. let data = {number:item.cartNum,id:item.id};
  188. cartNum(data).then(
  189. res => {
  190. if(res.code==200){
  191. uni.showToast({
  192. icon:'none',
  193. title: "操作成功",
  194. });
  195. this.computedMoney();
  196. }else{
  197. uni.showToast({
  198. icon:'none',
  199. title: res.msg,
  200. });
  201. }
  202. },
  203. rej => {}
  204. );
  205. },
  206. getCarts(){
  207. getCarts().then(
  208. res => {
  209. if(res.code==200){
  210. this.carts=res.carts;
  211. this.carts.forEach(item => {
  212. item.checked = false;
  213. item.list.forEach(it => {
  214. it.checked = false;
  215. });
  216. });
  217. this.computedMoney();
  218. }else{
  219. uni.showToast({
  220. icon:'none',
  221. title: "请求失败",
  222. });
  223. }
  224. },
  225. rej => {}
  226. );
  227. },
  228. // 购物车减法
  229. delNum(item) {
  230. if (item.cartNum <= 1) {
  231. uni.showToast({
  232. title: "已经是底线啦!",
  233. icon: "none",
  234. duration: 2000
  235. });
  236. return;
  237. }
  238. item.cartNum --
  239. if(item.cartNum < 1) {
  240. item.cartNum = 1
  241. }
  242. this.changeCartNum(item)
  243. },
  244. // 购物车加法
  245. addNum(item) {
  246. console.log(item)
  247. item.cartNum++
  248. if(item.cartNum>=item.stock){
  249. item.cartNum=item.stock;
  250. }
  251. this.changeCartNum(item)
  252. },
  253. // 结算
  254. submit() {
  255. let selectCarts = this.carts
  256. .filter(item => item.list.some(listItem => listItem.checked === true))
  257. .map(item => ({
  258. storeId: item.storeId || "",
  259. data: {
  260. type: "cart",
  261. cartIds: item.list.filter(it=>it.checked == true).map(it => it.id).join(","),
  262. }
  263. }));
  264. if(selectCarts.length==0){
  265. uni.showToast({
  266. icon:'none',
  267. title: "请选择商品",
  268. });
  269. return;
  270. }
  271. uni.navigateTo({
  272. url: './confirmOrder?type=cart&confirmParam='+ encodeURIComponent(JSON.stringify(selectCarts))
  273. })
  274. },
  275. showProduct(item){
  276. uni.navigateTo({
  277. url: '../shopping/productDetails?productId='+item.productId
  278. })
  279. },
  280. }
  281. }
  282. </script>
  283. <style lang="scss">
  284. page {
  285. height: 100%;
  286. }
  287. .content{
  288. height: 100%;
  289. padding: 20upx;
  290. .shopbox {
  291. background: #FFFFFF;
  292. border-radius: 16rpx;
  293. margin-bottom: 20rpx;
  294. }
  295. .shopbox-name {
  296. padding: 30rpx 30rpx 0 30rpx;
  297. font-family: PingFang SC, PingFang SC;
  298. font-weight: 400;
  299. font-size: 30rpx;
  300. color: #111;
  301. overflow: hidden;
  302. white-space: nowrap;
  303. text-overflow: ellipsis;
  304. }
  305. .goods-list{
  306. .item{
  307. box-sizing: border-box;
  308. height: 221upx;
  309. background: #FFFFFF;
  310. border-radius: 16upx;
  311. margin-bottom: 20upx;
  312. padding: 30upx;
  313. display: flex;
  314. align-items: center;
  315. &:last-child{
  316. margin-bottom: 0;
  317. }
  318. .goods-img{
  319. width: 160upx;
  320. height: 160upx;
  321. background: #FFFFFF;
  322. margin-right: 30upx;
  323. flex-shrink: 0;
  324. }
  325. .info-box{
  326. height: 160upx;
  327. display: flex;
  328. flex-direction: column;
  329. justify-content: space-between;
  330. width: calc(100% - 255upx);
  331. .title-box{
  332. width: 100%;
  333. display: flex;
  334. align-items: center;
  335. .tag{
  336. padding: 0 6upx;
  337. height: 30upx;
  338. line-height: 30upx;
  339. font-size: 22upx;
  340. font-family: PingFang SC;
  341. font-weight: bold;
  342. color: #FFFFFF;
  343. background: linear-gradient(90deg, #66b2ef 0%, #0bb3f2 100%);
  344. border-radius: 4upx;
  345. margin-right: 10upx;
  346. flex-shrink: 0;
  347. }
  348. .title{
  349. flex: 1;
  350. font-size: 28upx;
  351. font-family: PingFang SC;
  352. font-weight: 500;
  353. color: #111111;
  354. line-height: 1;
  355. }
  356. }
  357. .intro{
  358. font-size: 24upx;
  359. font-family: PingFang SC;
  360. font-weight: 500;
  361. color: #999999;
  362. margin-top: 22upx;
  363. line-height: 1;
  364. }
  365. .price-num{
  366. display: flex;
  367. align-items: center;
  368. justify-content: space-between;
  369. .price{
  370. display: flex;
  371. align-items: flex-end;
  372. .unit{
  373. font-size: 24upx;
  374. font-family: PingFang SC;
  375. font-weight: 500;
  376. color: #FF6633;
  377. line-height: 1.2;
  378. margin-right: 4upx;
  379. }
  380. .text{
  381. font-size: 32upx;
  382. font-family: PingFang SC;
  383. font-weight: bold;
  384. color: #FF6633;
  385. line-height: 1;
  386. }
  387. }
  388. .num-box{
  389. display: flex;
  390. align-items: center;
  391. .img-box{
  392. width: 60upx;
  393. height: 60upx;
  394. // border-radius: 4upx;
  395. border: 1px solid #dddddd;
  396. display: flex;
  397. align-items: center;
  398. justify-content: center;
  399. image{
  400. width: 25rpx;
  401. height: 25rpx;
  402. }
  403. }
  404. input{
  405. width: 60upx;
  406. height: 60upx;
  407. line-height: 60upx;
  408. font-size: 28upx;
  409. font-family: PingFang SC;
  410. font-weight: 500;
  411. color: #111111;
  412. // border-radius: 4upx;
  413. border-top: 1px solid #dddddd;
  414. border-bottom: 1px solid #dddddd;
  415. text-align: center;
  416. // margin: 0 16upx;
  417. }
  418. }
  419. }
  420. }
  421. }
  422. }
  423. .like-product{
  424. padding-bottom: 120upx;
  425. }
  426. .btn-foot{
  427. box-sizing: border-box;
  428. width: 100%;
  429. height: 121upx;
  430. background: #FFFFFF;
  431. padding: 16upx 30upx 16upx 60upx;
  432. display: flex;
  433. align-items: center;
  434. justify-content: space-between;
  435. position: fixed;
  436. left: 0;
  437. bottom: 0;
  438. z-index: 99;
  439. .left{
  440. display: flex;
  441. align-items: center;
  442. .text{
  443. margin-left: 14upx;
  444. font-size: 28upx;
  445. font-family: PingFang SC;
  446. font-weight: 500;
  447. color: #666666;
  448. line-height: 1;
  449. }
  450. }
  451. .right{
  452. display: flex;
  453. align-items: center;
  454. .total{
  455. display: flex;
  456. align-items: flex-end;
  457. margin-right: 36upx;
  458. .label{
  459. font-size: 26upx;
  460. font-family: PingFang SC;
  461. font-weight: 500;
  462. color: #999999;
  463. line-height: 1.5;
  464. }
  465. .price{
  466. display: flex;
  467. align-items: flex-end;
  468. .unit{
  469. font-size: 32upx;
  470. font-family: PingFang SC;
  471. font-weight: bold;
  472. color: #FF6633;
  473. line-height: 1.2;
  474. margin-right: 10upx;
  475. }
  476. .num{
  477. font-size: 30upx;
  478. font-family: PingFang SC;
  479. font-weight: bold;
  480. color: #FF6633;
  481. line-height: 1;
  482. }
  483. }
  484. }
  485. .btn{
  486. width: 200upx;
  487. height: 88upx;
  488. line-height: 88upx;
  489. text-align: center;
  490. font-size: 30upx;
  491. font-family: PingFang SC;
  492. font-weight: bold;
  493. color: #FFFFFF;
  494. background: #0bb3f2;
  495. border-radius: 44upx;
  496. }
  497. }
  498. }
  499. }
  500. </style>