Files
messi 4810dc79e3 fix
2024-08-19 17:17:46 +08:00

605 lines
21 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container p-bottom" :style="appThemeStyle">
<view v-if="order.goodsList.length">
<!-- 实物订单选择配送方式 -->
<block v-if="order.orderType == OrderTypeEnum.PHYSICAL.value">
<!-- 配送方式选项卡 -->
<view v-if="isShowTab" class="swiper-tab dis-flex flex-y-center flex-x-around">
<view class="swiper-tab-item" :class="{ on: curDelivery == DeliveryTypeEnum.EXPRESS.value }"
@click="handleSwichDelivery(DeliveryTypeEnum.EXPRESS.value)">
<text>快递配送</text>
</view>
<view class="swiper-tab-item" :class="{ on: curDelivery == DeliveryTypeEnum.EXTRACT.value }"
@click="handleSwichDelivery(DeliveryTypeEnum.EXTRACT.value)">
<text>上门自提</text>
</view>
</view>
<!-- 快递配送配送地址 -->
<view v-if="curDelivery == DeliveryTypeEnum.EXPRESS.value" @click="onSelectAddress" class="flow-delivery">
<view class="flow-delivery__detail dis-flex flex-y-center">
<view class="detail-location dis-flex">
<text class="iconfont icon-dingwei"></text>
</view>
<view class="detail-content flex-box">
<block v-if="order.address">
<view class="detail-content__title dis-flex">
<text class="f-30">{{ order.address.name }}</text>
<text class="detail-content__title-phone f-28">{{ order.address.phone }}</text>
</view>
<view class="address detail-content__describe">
<text class="region" v-for="(region, idx) in order.address.region" :key="idx">{{ region }}</text>
<text class="detail">{{ order.address.detail }}</text>
</view>
</block>
<block v-else>
<view class="detail-content__describe dis-flex">
<text class="col-6">请选择配送地址</text>
</view>
</block>
</view>
<view class="detail-arrow dis-flex">
<text class="iconfont icon-arrow-right"></text>
</view>
</view>
</view>
<!-- 上门自提自提门店 -->
<block v-if="curDelivery == DeliveryTypeEnum.EXTRACT.value">
<view class="flow-delivery" @click="onSelectExtractPoint()">
<view class="flow-delivery__detail dis-flex flex-y-center">
<view class="detail-location dis-flex">
<text class="iconfont icon-dingwei"></text>
</view>
<view class="detail-content flex-box">
<block v-if="order.extractShop.shop_id">
<view class="detail-content__title dis-flex">
<text class="f-30">{{ order.extractShop.shop_name }}</text>
</view>
<view class="detail-content__describe">
<text class="col-7">{{ order.extractShop.region.province }} {{ order.extractShop.region.city }}</text>
<text class="col-7">{{ order.extractShop.region.region }} {{ order.extractShop.address }}</text>
</view>
</block>
<block v-else>
<view class="detail-content__describe dis-flex">
<text class="col-6">请选择自提点</text>
</view>
</block>
</view>
<view class="detail-arrow dis-flex">
<text class="iconfont icon-arrow-right user-orderJtou"></text>
</view>
</view>
</view>
<!-- 自提联系方式 -->
<view class="flow-extract-contact b-f">
<view class="contact-item dis-flex">
<view class="item_label dis-flex flex-x-end flex-y-center">
<text>联系人</text>
</view>
<view class="item_ipt flex-box dis-flex flex-y-center">
<input placeholder="请填写联系人姓名" v-model="linkman"></input>
</view>
</view>
<view class="contact-item dis-flex">
<view class="item_label dis-flex flex-x-end flex-y-center">
<text>联系电话</text>
</view>
<view class="item_ipt flex-box dis-flex flex-y-center">
<input placeholder="请填写联系电话" v-model="phone"></input>
</view>
</view>
</view>
</block>
</block>
<!-- 商品列表 -->
<view class="checkout_list" v-for="(item, index) in order.goodsList" :key="index">
<view class="flow-shopList dis-flex" data-index="index" @click="onTargetGoods(item.goods_id)">
<!-- 商品图片 -->
<view class="flow-list-left">
<image mode="scaleToFill" :src="item.goods_image"></image>
</view>
<view class="flow-list-right flex-box">
<!-- 商品名称 -->
<text class="goods-name twoline-hide">{{ item.goods_name }}</text>
<!-- 商品规格 -->
<view class="goods-props clearfix">
<view class="goods-props-item" v-for="(props, idx) in item.skuInfo.goods_props" :key="idx">
<text class="group-name">{{ props.group.name }}: </text>
<text>{{ props.value.name }}</text>
</view>
</view>
<!-- 商品数量和单价 -->
<view class="flow-list-cont dis-flex flex-x-between flex-y-center">
<text class="small">×{{ item.total_num }}</text>
<text class="flow-cont" :class="[item.is_user_grade ? 'price-delete' : '']">{{ item.goods_price }}</text>
</view>
<!-- 会员折扣价 -->
<view v-if="item.is_user_grade" class="grade-price">
<text>会员折扣价{{ item.grade_goods_price }}</text>
</view>
</view>
</view>
</view>
<view class="flow-num-box b-f">
<!-- <text>{{ order.orderTotalNum }}件商品合计</text>
<text class="flow-money col-m">{{ order.orderTotalPrice }}</text> -->
<text>{{ order.orderTotalNum }}件商品</text>
</view>
<!-- 商品金额 -->
<view class="flow-all-money b-f m-top20">
<view class="flow-all-list dis-flex">
<text class="flex-five">订单总金额</text>
<view class="flex-five t-r">
<text class="col-m">{{ order.orderTotalPrice }}</text>
</view>
</view>
<!-- 优惠券 -->
<view class="flow-all-list dis-flex">
<text class="flex-five">优惠券</text>
<view class="flex-five t-r">
<view v-if="order.couponList.length > 0" @click="handleShowPopup()">
<text class="col-m" v-if="order.couponId > 0">-{{ order.couponMoney }}</text>
<text class="col-m" v-else>{{ order.couponList.length }}张优惠券</text>
<text class="right-arrow iconfont icon-arrow-right"></text>
</view>
<text v-else class="">无优惠券可用</text>
</view>
</view>
<!-- 积分抵扣 -->
<view v-if="order.isAllowPoints" class="points flow-all-list dis-flex flex-y-center">
<view class="block-left flex-five" @click="handleShowPoints()">
<text class="title">可用{{ setting.points_name }}抵扣</text>
<text class="iconfont icon-help"></text>
</view>
<view class="flex-five dis-flex flex-x-end flex-y-center">
<text class="points-money col-m">-{{ order.pointsMoney }}</text>
<u-switch v-model="isUsePoints" size="48" active-color="#07c160" @change="getOrderData()"></u-switch>
</view>
</view>
<!-- 配送费用 -->
<view v-if="curDelivery == DeliveryTypeEnum.EXPRESS.value" class="dis-flex flow-all-list">
<text class="flex-five">配送费用</text>
<view class="flex-five t-r">
<view v-if="order.address">
<text class="col-m" v-if="order.isIntraRegion">+{{ order.expressPrice }}</text>
<text v-else>不在配送范围</text>
</view>
<view v-else>
<text class="col-7">请先选择配送地址</text>
</view>
</view>
</view>
</view>
<!-- 买家留言 -->
<view class="flow-all-money b-f m-top20">
<view class="ipt-wrapper dis-flex flow-all-list">
<input v-model="remark" placeholder="选填买家留言50字以内"></input>
</view>
</view>
<!-- 提交订单 -->
<view class="flow-fixed-footer b-f m-top10">
<view class="dis-flex chackout-box">
<view class="chackout-left pl-12">实付款
<text class="col-m">{{ order.orderPayPrice }}</text>
</view>
<view class="chackout-right" @click="onSubmitOrder()">
<view class="flow-btn f-32" :class="{ disabled }">提交订单</view>
</view>
</view>
</view>
<!-- 积分说明弹窗 -->
<u-modal v-model="showPoints" :title="`${setting.points_name}说明`">
<scroll-view class="points-content" :scroll-y="true">
<text>{{ setting.points_describe }}</text>
</scroll-view>
</u-modal>
<!-- 优惠券弹出框 -->
<u-popup v-model="showPopup" mode="bottom">
<view class="popup__coupon">
<view class="coupon__title f-30">选择优惠券</view>
<!-- 优惠券列表 -->
<view class="coupon-list">
<scroll-view :scroll-y="true" style="height: 565rpx;">
<view class="coupon-item" v-for="(item, index) in order.couponList" :key="index">
<view class="item-wrapper" :class="[item.is_apply ? 'color-' + CouponColors[index % CouponColors.length] : 'color-gray']"
@click="handleSelectCoupon(index)">
<view class="coupon-type">{{ CouponTypeEnum[item.coupon_type].name }}</view>
<view class="tip dis-flex flex-dir-column flex-x-center">
<view v-if="item.coupon_type == CouponTypeEnum.FULL_DISCOUNT.value">
<text class="f-30"></text>
<text class="money">{{ item.reduce_price }}</text>
</view>
<text class="money" v-if="item.coupon_type == CouponTypeEnum.DISCOUNT.value">{{ item.discount }}</text>
<text class="pay-line">{{ item.min_price }}元可用</text>
</view>
<view class="split-line"></view>
<view class="content dis-flex flex-dir-column flex-x-between">
<view class="title">{{ item.name }}</view>
<view class="bottom dis-flex flex-y-center">
<view class="time flex-box">
<block v-if="item.start_time === item.end_time">{{ item.start_time }} 当天有效</block>
<block v-else>{{ item.start_time }}~{{ item.end_time }}</block>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 不使用优惠券 -->
<view class="coupon__do_not dis-flex flex-y-center flex-x-center">
<view class="control dis-flex flex-y-center flex-x-center" @click="handleNotUseCoupon()">
<text class="f-26">不使用优惠券</text>
</view>
</view>
</view>
</u-popup>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import * as Verify from '@/utils/verify'
import * as CheckoutApi from '@/api/checkout'
import * as SharpCheckoutApi from '@/api/sharp/checkout'
import * as BargainCheckoutApi from '@/api/bargain/checkout'
import * as GrouponCheckoutApi from '@/api/groupon/checkout'
import { CouponTypeEnum } from '@/common/enum/coupon'
import { OrderTypeEnum, DeliveryTypeEnum } from '@/common/enum/order'
const CouponColors = ['red', 'blue', 'violet', 'yellow']
// 根据指定mode获取对应的api类
const getCheckoutApi = (mode) => {
const apiEnum = {
buyNow: CheckoutApi,
cart: CheckoutApi,
bargain: BargainCheckoutApi,
sharp: SharpCheckoutApi,
groupon: GrouponCheckoutApi
}
return apiEnum[mode]
}
// 根据指定mode获取param
const getModeParam = (mode, options) => {
const param = {}
// 结算模式: 立即购买
if (mode === 'buyNow') {
param.goodsId = options.goodsId
param.goodsNum = options.goodsNum
param.goodsSkuId = options.goodsSkuId
}
// 结算模式: 购物车
if (mode === 'cart') {
param.cartIds = options.cartIds
}
// 结算模式: 砍价活动
if (mode === 'bargain') {
param.taskId = options.taskId
param.goodsSkuId = options.goodsSkuId
}
// 结算模式: 整点秒杀
if (mode === 'sharp') {
param.activeTimeId = options.activeTimeId
param.sharpGoodsId = options.sharpGoodsId
param.goodsSkuId = options.goodsSkuId
param.goodsNum = options.goodsNum
}
// 结算模式: 多人拼团
if (mode === 'groupon') {
param.grouponGoodsId = options.grouponGoodsId
param.taskId = options.taskId
param.goodsSkuId = options.goodsSkuId
param.goodsNum = options.goodsNum
param.stepPeople = options.stepPeople
}
return param
}
export default {
data() {
return {
// 枚举类
OrderTypeEnum,
DeliveryTypeEnum,
CouponTypeEnum,
// 当前页面参数
options: {},
// 配送方式
isShowTab: false,
DeliveryTypeEnum,
curDelivery: null,
// 自提信息
selectedShopId: 0, // 选择的门店ID
linkman: '', // 自提联系人
phone: '', // 自提联系电话
// 优惠券颜色组
CouponColors,
// 选择的优惠券
selectCouponId: 0,
// 是否使用积分抵扣
isUsePoints: false,
// 买家留言
remark: '',
// 禁用submit按钮
disabled: false,
// 是否显示积分说明
showPoints: false,
// 是否显示优惠券弹窗
showPopup: false,
// 订单信息 (从后端api中获取)
order: {
// 商品列表
goodsList: [],
// 优惠券列表
couponList: [],
// 是否存在收货地址
existAddress: false,
// 默认收货地址
address: null,
// 是否存在收货地址
existAddress: false,
// 当前用户收货城市是否存在配送规则中
isIntraRegion: true,
// 是否存在错误
hasError: false,
// 错误信息
errorMsg: '',
},
// 个人信息
personal: {},
// 商城设置
setting: {}
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.options = options
// 注册全局事件订阅: 选择自提门店
uni.$on('syncSelectedId', selectedId => {
this.selectedShopId = selectedId
})
},
/**
* 生命周期函数--监听页面的卸载
*/
onUnload() {
// 卸载全局事件订阅: 选择自提门店
uni.$off('syncSelectedId')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
// 获取当前订单信息
this.getOrderData()
},
methods: {
// 获取订单数据
getOrderData() {
const app = this
const { options: { mode } } = app
// 请求的参数
const params = app.getRequestParam()
// 请求api
getCheckoutApi(mode)
.order(mode, params)
.then(result => app.initData(result.data))
.catch(err => err)
},
// 初始化数据
initData({ order, setting, personal }) {
const app = this
app.order = order
app.personal = personal
app.setting = setting
// 显示错误信息
if (order.hasError) {
app.showToast(order.errorMsg, 3000)
}
// 当前选择的配送方式
app.curDelivery = order.delivery
// 如果只有一种配送方式则不显示选项卡
app.isShowTab = setting.deliveryType.length > 1
// 上门自提联系信息
if (app.linkman === '') {
app.linkman = order.lastExtract.linkman
}
if (app.phone === '') {
app.phone = order.lastExtract.phone
}
},
// 获取api请求的参数
getRequestParam() {
const app = this
const { options } = app
// 结算模式的固定参数
const modeParam = getModeParam(options.mode, options)
// 订单结算参数(用户选择)
const orderParam = {
delivery: app.curDelivery || 0,
shopId: app.selectedShopId || 0,
couponId: app.selectCouponId || 0,
isUsePoints: app.isUsePoints ? 1 : 0,
}
return { ...orderParam, ...modeParam }
},
// 切换配送方式
handleSwichDelivery(key) {
this.curDelivery = key
this.getOrderData()
},
// 显示积分说明
handleShowPoints() {
this.showPoints = true
},
// 显示优惠券弹窗
handleShowPopup() {
this.showPopup = true
},
// 选择优惠券
handleSelectCoupon(index) {
const app = this
const { couponList } = app.order
// 当前选择的优惠券
const couponItem = couponList[index]
// 判断是否在适用范围
if (!couponItem.is_apply) {
app.showToast(couponItem.not_apply_info)
return
}
// 记录选中的优惠券id
app.selectCouponId = couponItem.user_coupon_id
// 重新获取订单信息
app.getOrderData()
// 隐藏优惠券弹层
app.showPopup = false
},
// 不使用优惠券
handleNotUseCoupon() {
const app = this
app.selectCouponId = 0
// 重新获取订单信息
app.getOrderData()
// 隐藏优惠券弹层
app.showPopup = false
},
// 快递配送:选择收货地址
onSelectAddress() {
this.$navTo('pages/address/index', { from: 'checkout' })
},
// 上门自提:选择自提点
onSelectExtractPoint() {
this.$navTo('pages/shop/extract', { selectedId: this.selectedShopId })
},
// 跳转到商品详情页
onTargetGoods(goodsId) {
this.$navTo('pages/goods/detail', { goodsId })
},
// 订单提交
onSubmitOrder() {
const app = this
if (app.disabled) {
return false
}
// 表单验证
if (!app.onVerifyFrom()) {
return false
}
// 按钮禁用
app.disabled = true
// 请求api
getCheckoutApi(app.options.mode)
.submit(app.options.mode, app.getFormData())
.then(result => {
// 订单创建成功: 跳转到订单支付页
const orderId = result.data.orderId
setTimeout(() => {
this.$navTo('pages/checkout/cashier/index', { orderId }, 'redirectTo')
}, 100)
})
.catch(res => app.showToast(res.errMsg, 3000))
.finally(() => setTimeout(() => app.disabled = false, 800))
},
// 跳转到我的订单(等待1秒)
navToMyOrder() {
setTimeout(() => {
this.$navTo('pages/order/index', {}, 'redirectTo')
}, 1000)
},
// 表单提交的数据
getFormData() {
const app = this
const { options } = app
// 表单数据
const form = {
delivery: app.curDelivery,
couponId: app.selectCouponId || 0,
shopId: app.selectedShopId || 0,
linkman: app.linkman,
phone: app.phone,
isUsePoints: app.isUsePoints ? 1 : 0,
remark: app.remark || '',
}
// 获取不同模式的参数
const modeParam = getModeParam(options.mode, options)
return { ...form, ...modeParam }
},
// 表单验证
onVerifyFrom() {
const app = this
if (app.hasError) {
app.showToast(app.errorMsg, 3000)
return false
}
// 验证自提填写的联系方式
if (app.curDelivery == DeliveryTypeEnum.EXTRACT.value) {
app.linkman = app.linkman.trim()
app.phone = app.phone.trim()
if (app.selectedShopId <= 0) {
app.showToast('请选择自提的门店')
return false
}
if (Verify.isEmpty(app.linkman)) {
app.showToast('请填写自提联系人')
return false
}
if (Verify.isEmpty(app.phone)) {
app.showToast('请填写自提联系电话')
return false
}
if (!Verify.isPhone(app.phone)) {
app.showToast('请输入正确的联系电话')
return false
}
}
return true
},
// 显示toast信息
showToast(title, duration = 2000) {
this.$refs.uToast.show({ title, duration })
}
}
}
</script>
<style lang="scss" scoped>
@import "./style.scss";
</style>