UNIAPP实战项目笔记69 订单确认时显示为默认地址
思路
需要用到vuex
默认显示isDefault为1的地址
案例截图
订单结算页面
地址页面
代码
shopcart.vue
<template>
<view class="shop-cart">
<template v-if=" list.length > 0 ">
<!-- 自定义导航栏 -->
<uniNavBar
title="购物车"
:rightText=" isNavBar ? '完成' : '编辑'"
fixed="true"
statusBar="true"
@clickRight=" isNavBar = !isNavBar"
></uniNavBar>
<!-- 商品内容 -->
<view class="shop-item" v-for="(item,index) in list" :key="index">
<label for="" class="radio" @tap="selectedItem(index)">
<radio value="" color="#FF3333" :checked="item.checked" /> <text></text>
</label>
<image class="shop-img" :src="item.imgUrl" mode=""></image>
<view class="shop-text">
<view class="shop-name">
{{item.name}}
</view>
<view class="shop-color f-color">
{{item.color}}
</view>
<view class="shop-price">
<view class="">
¥{{item.pprice}}
</view>
<template v-if="!isNavBar">
<view>x {{item.num}}</view>
</template>
<template v-else>
<uniNumberBox
:value="item.num"
:min=1
@change="changeNumber($event,index,item)"
></uniNumberBox>
</template>
</view>
</view>
</view>
<!-- 底部 -->
<view class="shop-foot">
<label for="" class="radio foot-radio" @tap='checkedAllFn'>
<radio value="" color="#FF3333" :checked="checkedAll"></radio><text>全选</text>
</label>
<template v-if="!isNavBar">
<view class="foot-total">
<view class="foot-count">
合计:
<text class="f-active-color">
¥{{totalCount.pprice}}
</text>
</view>
<view class="foot-num" @tap="goConfirmOrder">
结算({{totalCount.num}})
</view>
</view>
</template>
<template v-else>
<view class="foot-total">
<view class="foot-num" style="background-color: black;">
移入收藏夹
</view>
<view class="foot-num" @tap="delGoodsFn">
删除
</view>
</view>
</template>
</view>
</template>
<template v-else>
<uniNavBar
title="购物车"
fixed="true"
statusBar="true"
></uniNavBar>
<view class="shop-else-list">
<text>囧~ 购物车还是空的~</text>
</view>
</template>
<Tabbar currentPage='shopcart'></Tabbar>
</view>
</template>
<script>
import $http from '@/common/api/request.js'
import uniNavBar from '@/components/uni/uni-nav-bar/uni-nav-bar.vue'
import uniNumberBox from '@/components/uni/uni-number-box/uni-number-box.vue'
import Tabbar from '@/components/common/Tabbar.vue';//引入
// 状态机引入
import {mapState,mapActions,mapGetters,mapMutations} from 'vuex'
export default {
data() {
return {
isNavBar:false,
}
},
computed:{
// 状态机数据处理
...mapState({
list:state=>state.cart.list,
selectedList:state=>state.cart.selectedList,
}),
...mapGetters(['checkedAll','totalCount'])
},
components:{
uniNavBar,uniNumberBox,Tabbar
},
onShow() {
this.getData();
},
methods: {
...mapActions(['checkedAllFn','delGoodsFn']),
...mapMutations(['selectedItem','initGetData']),
getData(){
$http.request({
url:'/selectCart',
method:"POST",
header:{
token:true
}
}).then((res)=>{
this.initGetData(res)
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
changeNumber(value,index,item){
if ( value == item.num ) return;
$http.request({
url:'/updateCart',
method:"POST",
header:{
token:true
},
data:{
goodsId:item.goods_id,
num:value
}
}).then((res)=>{
this.list[index].num = value;
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
// 进入确认订单
goConfirmOrder(){
if(this.selectedList.length === 0){
return uni.showToast({
title:"至少选择一件商品",
icon:"none"
})
}
uni.navigateTo({
url:`/pages/confirm-order/confirm-order?detail=${JSON.stringify(this.selectedList)}`
})
}
}
}
</script>
<style lang="scss">
.shop-list{
padding-bottom: 100rpx;
}
.shop-else-list{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: #f7f7f7;
display: flex;
align-items: center;
justify-content: center;
}
.shop-item{
display: flex;
padding: 20rpx;
align-items: center;
background-color: #f7f7f7;
margin-bottom: 10rpx;
}
.shop-img{
width: 200rpx;
height: 200rpx;
}
.shop-text{
flex: 1;
padding-left: 20rpx;
}
.shop-color{
font-size: 24rpx;
}
.shop-price{
display: flex;
justify-content: space-between;
}
.shop-foot{
border-top: 2rpx solid #f7f7f7;
background-color: #FFFFFF;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 100rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 120rpx;
}
.foot-radio{
padding-left: 20rpx;
}
.foot-total{
display: flex;
}
.foot-count{
line-height: 100rpx;
padding: 0 20rpx;
font-size: 32rpx;
}
.foot-num{
background-color: #49bdfb;
color: #FFFFFF;
padding: 0 60rpx;
line-height: 100rpx;
}
</style>
confirm-order.vue
<template>
<view class="confirm-order bg-active-color">
<Lines></Lines>
<!-- 地址 -->
<view class="order-map" @tap="goPathList">
<block v-if="path">
<view class="map-title">
<view class="map-name">收件人:{{path.name}}</view>
<view class="">{{path.tel}}</view>
</view>
<view class="map-add">
收货地址:{{path.city}} {{path.detail}}
</view>
</block>
<block v-else>
<view class="map-title">
<view class="map-name">请选择地址</view>
</view>
</block>
</view>
<!-- 商品 -->
<view class="goods-list" v-for="(item,index) in goodsList" :key="index">
<view class="goods-content bg-active-color">
<image class="goods-img" :src="item.imgUrl" mode=""></image>
<view class="goods-text">
<view class="goods-name">
{{item.name}}
</view>
<view class="goods-size f-color">
颜色分类:黑色
</view>
<view class="f-active-color">
7天无理由
</view>
</view>
<view class="">
<view class="">
¥{{item.pprice}}
</view>
<view class="goods-size">
x {{item.num}}
</view>
</view>
</view>
</view>
<!-- 底部:提交订单 -->
<view class="order-foot">
<view class="total-price">
合计: <text class="f-active-color">${{totalCount.pprice}}</text>
</view>
<view class="confirm" @tap="goPayment">
提交订单
</view>
</view>
</view>
</template>
<script>
import $http from '@/common/api/request.js'
import Lines from '@/components/common/Lines.vue'
import {mapGetters,mapState,mapMutations} from 'vuex'
export default {
data() {
return {
path:false
};
},
computed:{
...mapState({
list:state=>state.cart.list
}),
...mapGetters(['defaultPath','totalCount']),
// 根据商品列表找到对应的e.detail 数据的 id 最终返回商品数据
goodsList(){
return this.item.map(id=>{
return this.list.find(v=>v.id == id)
})
}
},
onLoad(e) {
console.log(e.detail,this.list);
// 选中的商品id集合 [1,3]
this.item = JSON.parse(e.detail);
// 如果默认地址的一个赋值
$http.request({
url:'/selectAddress',
method:"POST",
header:{
token:true
}
}).then((res)=>{
this.__initAddressList(res);
if(this.defaultPath.length){
this.path = this.defaultPath[0];
}
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
// 如果出发自定义事件,on去接收值
uni.$on('selectPathItem',(res)=>{
// console.log(res);
this.path = res;
})
},
onUnload() {
uni.$off('selectPathItem',()=>{
console.log('移除了selectPathItem');
})
},
components:{
Lines
},
methods:{
...mapMutations(['__initAddressList']),
// 跳转到地址管理页面
goPathList(){
uni.navigateTo({
url:'/pages/my-path-list/my-path-list?type=selectedPath'
})
},
// 确认支付
goPayment(){
if( this.path ){
return uni.showToast({
title:'请选择收货地址',
icon:'none'
})
}
uni.navigateTo({
url:'/pages/payment/payment'
})
}
}
}
</script>
<style lang="less">
.confirm-order{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
.order-map{
margin-bottom: 10rpx;
padding: 20rpx;
background-color: #fff;
line-height: 50rpx;
}
.map-title{
display: flex;
justify-content: space-between;
}
.map-name{
font-weight: bold;
}
.goods-list{
background-color: #fff;
padding: 10rpx 0;
}
.goods-content{
padding: 10rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.goods-text{
width: 360rpx;
padding: 0 10rpx;
font-size: 26rpx;
}
.goods-img{
width: 160rpx;
height: 160rpx;
}
.goods-size{
font-size: 24rpx;
}
.order-foot{
width: 100%;
height: 80rpx;
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
display: flex;
justify-content: flex-end;
align-items: center;
}
.confirm{
color: #fff;
background-color: #49bdfb;
padding: 10rpx 30rpx;
}
.total-price{
padding: 0 20rpx;
}
</style>
path.js
export default{
state:{
list:[
/* {
name:"张果老",
tel:"18010101919",
city:"北京市朝阳区建国路",
details:"四惠东199号",
isDefault:false
},{
name:"吕洞宾",
tel:"18010102929",
city:"北京市石景山区鲁谷",
details:"中心西街199号",
isDefault:true
} */
]
},
getters:{
defaultPath(state){
// return state.list.filter(v=>v.isDefault)
return state.list.filter(v=>{
return v.isDefault == 1
})
}
},
mutations:{
// 拿到初始化请求当前用户收货地址数据
__initAddressList(state,list){
state.list = list;
},
createPath( state, obj ){
state.list.unshift( obj );
},
updatePath( state, {index,item} ){
for(let key in item){
state.list[index][key] = item[key];
}
},
// 把之前选中默认的改完未选中
removePath(state){
state.list.forEach(v=>{
if(v.isDefault){
v.isDefault = 0;
}
})
}
},
actions:{
createPathFn({commit}, obj){
if(obj.isDefault){
commit('removePath')
}
commit('createPath', obj);
},
updatePathFn({commit}, obj){
if(obj.item.isDefault){
commit('removePath')
}
commit('updatePath', obj);
}
}
}
目录结构
前端目录结构
-
manifest.json 配置文件: appid、logo…
-
pages.json 配置文件: 导航、 tabbar、 路由
-
main.js vue初始化入口文件
-
App.vue 全局配置:样式、全局监视
-
static 静态资源:图片、字体图标
-
page 页面
- index
- index.vue
- list
- list.vue
- my
- my.vue
- my-config
- my-config.vue
- my-config
- my-config.vue
- my-add-path
- my-add-path.vue
- my-path-list
- my-path-list.vue
- search
- search.vue
- search-list
- search-list.vue
- shopcart
- shopcart.vue
- details
- details.vue
- my-order
- my-order.vue
- confirm-order
- confirm-order.vue
- payment
- payment.vue
- payment-success
- payment-success.vue
- login
- login.vue
- login-tel
login-tel.vue
- login-code
login-code.vue
- index
-
components 组件
- index
- Banner.vue
- Hot.vue
- Icons.vue
- indexSwiper.vue
- Recommend.vue
- Shop.vue
Tabbar.vue
- common
- Card.vue
- Commondity.vue
- CommondityList.vue
- Line.vue
- ShopList.vue
- order
- order-list.vue
- uni
- uni-number-box
- uni-number-box.vue
- uni-icons
- uni-icons.vue
- uni-nav-bar
- uni-nav-bar.vue
- mpvue-citypicker
- mpvueCityPicker.vue
- uni-number-box
- index
-
common 公共文件:全局css文件 || 全局js文件
- api
- request.js
- common.css
- uni.css
- api
-
store vuex状态机文件
- modules
- cart.js
- path.js
- user.js
- index.js
- modules