小程序结算页

在这里插入图片描述
商品详情
1.前页点击商品,通过 uni.navigateTo({url: “/pages/list/index?query=”+this.keyword}),api,传递商品数据,进入详情组件,依然是onLoad()接受数据,发送请求,将请求的信息渲染出来。
2.点击客服,弹出客服聊天框,这里用按钮设置open-type="contact"即可。
3.点击购物车正常思路:1:未登陆就跳到登陆。2:未登陆就将数据存到本地,到登陆时从本地读取。
4.点击加入购物车,从当前商品信息解构出商品的信息,商品id.for循环判断购物车数组是否存在该商品id.存在则商品数量加一,而且自定义状态为选择goods—checked=true, uni.setStorageSync(“carts”, this.carts);不存在就将商品信息添加进购物车数组并数量设置为1.说白了就是本地存储前判断有无该商品。
5.点击购物车,跳转到购物车页面,用uni.getStorageSync取出本地存储的商品,循环本地存储的商品列表。渲染到购物车页面,点击增减,传递购物车列表的index和step.直接改变数量,用 @blur="changecount($event, index)"监听解决。
6.并重新给商品列表索引为index的项的goods-number赋值;点击选择框,状态改变,选中框颜色也改变。通过计算属性过滤出选中的商品。
7.计算属性判断选中的和购物车列表数组长度是否相等,如果相等,则全选按钮的:color颜色为选中,全选控制单选:for循环,将商品的按钮设置为true;
8.金额计算通过计算属性,数量乘以单价。数据持久化:数量变化或者选中状态变化时,更新本地存储,重新将购物车列表存一次。
9.收货地址调用api, uni.chooseAddress({ success: (info) => {this.address = info;}, });如果成功,赋值该地址给data里的地址。渲染到地址上。
10.结算前,判断地址有无,购物车列表选中状态的数组长度不为0,登陆的token,三者缺一不可,未登陆跳到登陆页面

代码:

<template>
  <view class="wrapper" v-if="shop.length">
    <!-- 收货信息 -->
    <view class="shipment">
      <block v-if="address">
        <view class="dt">收货人: </view>
        <view class="dd meta">
          <text class="name">{{ address.userName }}</text>
          <text class="phone">{{ address.telNumber }}</text>
        </view>

        <view class="dt">收货地址:</view>
        <view class="dd">{{ detailAddress }}</view>
      </block>
      <button v-else @click="chooseAddress" type="primary">收货地址</button>
    </view>
    <!-- 购物车 -->
    <view class="carts">
      <view class="item">
        <!-- 店铺名称 -->
        <view class="shopname">阿毛购物</view>
        <view :key="index" v-for="(cart, index) in shop" class="goods">
          <!-- 商品图片 -->
          <image class="pic" :src="cart.goods_small_logo"></image>
          <!-- 商品信息 -->
          <view class="meta">
            <view class="name">{{ cart.goods_name }}</view>
            <view class="price">
              <text></text>{{ cart.goods_price }}<text>.00</text>
            </view>
            <!-- 加减 -->
            <view class="amount">
              <text class="reduce" @click="changenumber(index, -1)">-</text>
              <input
                type="number"
                pattern="[0-9]*"
                @blur="changecount($event, index)"
                :value="cart.goods_number"
                class="number"
              />
              <text class="plus" @click="changenumber(index, 1)">+</text>
            </view>
          </view>
          <!-- 选框 -->
          <view class="checkbox">
            <icon
              type="success"
              @click="toggle(index)"
              :color="cart.goods_checked ? '#ea4451' : '#ccc'"
              size="20"
            ></icon>
          </view>
        </view>
      </view>
    </view>

    <!-- 其它 -->
    <view class="extra">
      <!-- uni-app 存在 bug 属性绑定中计算属性的值获取 -->
      <label class="checkall">
        <icon
          @click="checkAll(all)"
          type="success"
          size="20"
          :color="all ? '#ea4451' : '#ccc'"
        ></icon>
        全选
      </label>
      <view class="total">
        合计: <text></text><label>{{ amount }}</label
        ><text>.00</text>
      </view>
      <view class="pay" @click="creatOrder"
        >结算({{ checkedgoods.length }})</view
      >
    </view>
  </view>
  <view class="tips" v-else>空空如也 </view>
</template>
<script>
export default {
  data() {
    return {
      shop: [],
      params: null,
      address: null,
    };
  },

  computed: {
    // 拼凑详细地址
    detailAddress() {
      return (
        this.address &&
        [
          this.address.provinceName,
          this.address.cityName,
          this.address.countyName,
          this.address.detailInfo,
        ].join("")
      );
    },
    // 选中状态的数组
    checkedgoods() {
      return this.shop.filter((goods) => {
        return goods.goods_checked;
      });
    },
    all() {
      return this.shop.length === this.checkedgoods.length;
    },
    amount() {
      let total = 0;
      this.checkedgoods.forEach((goods) => {
        total += goods.goods_price * goods.goods_number;
      });
      return total;
    },
  },
  methods: {
    // 订单结算
    async creatOrder() {
      // 地址不能为空
      if (!this.address) return uni.showToast({ title: "地址不能为空" });
      // 至少一件商品
      if (!this.checkedgoods.length)
        return uni.showToast({ title: "至少一件商品" });
      // 是否登陆
      if (!uni.getStorageSync("token"))
        return uni.navigateTo({ url: "/pages/list/login" });
      // 生成订单
      const res = await this.http({
        url: "/api/public/v1/my/orders/create",
        method: "post",
        header: { Authorization: uni.getStorageSync("token") },
        data: {
          order_price: this.amount,
          consignee_addr: this.detailAddress,
          goods: this.checkedgoods,
        },
      });
      // console.log(res);
      if (res[1].data.meta !== 999) {
        // 跳转到订单列表
        uni.navigateTo({
          // url: "/pages/list/order",
        });
      }
    },
    // 直接改变商品数量
    changecount(e, i) {
      // console.log(e, i);
      this.shop[i].goods_number = e.detail.value;
    },
    chooseAddress() {
      uni.chooseAddress({
        success: (info) => {
          // console.log(info);
          this.address = info;
        },
      });
    },
    // 反选
    checkAll(all) {
      this.shop.forEach((goods) => {
        goods.goods_checked = true;
      });
      if (all) {
        this.shop.forEach((goods) => {
          goods.goods_checked = false;
        });
      }

      uni.setStorageSync("carts", this.shop);
    },
    // 改变选中状态
    toggle(index) {
      this.shop[index].goods_checked = !this.shop[index].goods_checked;
      uni.setStorageSync("carts", this.shop);
    },
    getCates() {
      this.shop = uni.getStorageSync("carts") || [];
      // console.log(this.shop, 11);
    },
    // 改变数量
    changenumber(index, step) {
      // console.log(index, step);
      // 商品数量
      let num = this.shop[index].goods_number;
      // 检查边界
      // 最小买1件,最多不超过库存,假设库存10
      if (step === -1 && num <= 1) return;
      if (step === 1 && num >= 10) return;

      this.shop[index].goods_number += step;
      uni.setStorageSync("carts", this.shop);
    },
  },
  onLoad(e) {
    this.getCates();
  },
};
</script>
<style scoped lang="less">
.shipment {
  height: 100rpx;
  line-height: 2;
  padding: 30rpx 30rpx 40rpx 30rpx;
  font-size: 27rpx;
  color: #333;
  background-color: #fff;
  background-image: url(http://static.botue.com/ugo/images/cart_border%402x.png);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: bottom;

  .dt {
    width: 140rpx;
    float: left;
    clear: both;
  }

  .dd {
    padding-left: 160rpx;
  }

  .meta {
    padding-right: 50rpx;
  }

  text.phone {
    float: right;
  }
}

.carts {
  background-color: #f4f4f4;
  padding-bottom: 110rpx;
  overflow: hidden;

  .shopname {
    padding: 30rpx;
    margin-top: 20rpx;
    font-size: 30rpx;
    color: #333;
    background-color: #fff;
    border-top: 1rpx solid #eee;
    border-bottom: 1rpx solid #eee;
  }

  .goods {
    display: flex;
    padding: 30rpx 20rpx 30rpx 0;
    margin-left: 100rpx;
    border-bottom: 1rpx solid #eee;
    background-color: #fff;

    position: relative;

    .checkbox {
      width: 101rpx;
      height: 100%;
      background-color: #fff;

      display: flex;
      justify-content: center;
      align-items: center;

      position: absolute;
      left: -100rpx;
      top: 0;
    }

    &:last-child {
      border-bottom: none;
    }

    .pic {
      width: 200rpx;
      height: 200rpx;
      margin-right: 30rpx;
    }

    .meta {
      flex: 1;
      font-size: 27rpx;
      color: #333;
      position: relative;
    }

    .name {
      width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
    }

    .price {
      position: absolute;
      bottom: 0;

      color: #ea4451;
      font-size: 33rpx;

      text {
        font-size: 22rpx;
      }
    }

    .amount {
      position: absolute;
      bottom: 0;
      right: 20rpx;

      height: 48rpx;
      text-align: center;
      border: 1rpx solid #ddd;
      border-radius: 8rpx;

      display: flex;
      align-items: center;

      text {
        display: block;
        width: 60rpx;
        line-height: 48rpx;
        font-size: 36rpx;
        color: #ddd;
        text-align: center;
      }

      input {
        width: 60rpx;
        height: 48rpx;
        min-height: 48rpx;
        font-size: 27rpx;
        border-left: 1rpx solid #ddd;
        border-right: 1rpx solid #ddd;
      }
    }
  }
}

.extra {
  position: fixed;
  bottom: 0;
  /* #ifdef H5 */
  bottom: 50px;
  /* #endif */
  left: 0;
  z-index: 9;

  width: 750rpx;
  height: 96rpx;
  text-align: center;
  line-height: 96rpx;
  font-size: 36rpx;
  border-top: 1rpx solid #eee;
  background-color: #fff;
  color: #333;
  display: flex;

  .checkall {
    width: 140rpx;
    line-height: 1;
    margin-left: 25rpx;
    display: flex;
    align-items: center;

    icon {
      margin-right: 20rpx;
    }
  }

  .total {
    display: flex;
    justify-content: center;
    flex: 1;

    label,
    text {
      color: #ea4451;
      vertical-align: bottom;
      position: relative;
      bottom: -2rpx;
    }

    text {
      position: relative;
      bottom: -3rpx;
      font-size: 24rpx;

      &:first-child {
        margin-left: 10rpx;
      }
    }
  }

  .pay {
    width: 200rpx;
    background-color: #ea4451;
    color: #fff;
  }
}
</style>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现小程序结算页面和待付款页面,你可以按照以下步骤进行操作: 1. 创建结算页面:首先,在小程序的页面文件夹中创建一个结算页面的文件,例如`checkout.js`。在该页面中,你可以设计结算所需的表单、商品信息等。 2. 跳转到结算页面:在你的小程序中的其他页面中,添加一个按钮或其他触发事件,触发事件时跳转到结算页面。你可以使用小程序提供的`navigateTo`或`redirectTo`等跳转API实现页面跳转。 3. 返回并显示待付款页面:当用户在结算页面点击返回按钮或其他触发事件时,你可以使用小程序提供的`navigateBack` API返回上一个页面。在上一个页面中,你可以显示一个待付款状态,例如一个文字提示或一个待付款的图标。 4. 保存待付款状态:为了在返回后仍能显示待付款状态,你需要在小程序中保存这个状态。你可以使用小程序提供的全局变量或缓存接口来保存待付款状态。例如,你可以使用`wx.setStorageSync`方法将待付款状态保存到本地缓存中。 下面是一个简单的代码示例: 在结算页面 `checkout.js` 中: ```javascript // checkout.js Page({ // 结算按钮点击事件 onCheckout: function() { // 跳转到待付款页面 wx.navigateTo({ url: '/pages/pendingPayment/pendingPayment', }) } }) ``` 在待付款页面 `pendingPayment.js` 中: ```javascript // pendingPayment.js Page({ // 返回按钮点击事件 onBack: function() { // 返回上一个页面 wx.navigateBack({ delta: 1 }) } }) ``` 这只是一个简单的示例,你可以根据自己的需求进行相应的扩展和处理。同时,你可能还需要考虑支付接口的调用和支付状态的更新等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值