Feat: 订单流程

This commit is contained in:
LinCyJang
2025-10-19 23:15:06 +08:00
parent 6ffe3216d8
commit 9f529e00b7
9 changed files with 1277 additions and 133 deletions
+420
View File
@@ -0,0 +1,420 @@
<template>
<view class="submit-order">
<scroll-view scroll-y class="page-scroll">
<!-- 商品卡片 -->
<view class="card">
<view class="product-card">
<image class="thumb" :src="orderInfo.travelGroupProduct.mainImage" mode="aspectFill" />
<view class="info">
<view class="title">{{ orderInfo.travelGroupProduct.name }}</view>
<view class="price-row">
<text class="label">实付</text>
<text class="price v12-primary-text"><text class="v12-font-20"></text>{{ orderInfo.priceGroup.totalPrice }}</text>
</view>
</view>
</view>
<view class="notice v12-font-28 v12-primary-text">下单成功后记得联系商家确认入住时间哦~</view>
</view>
<!-- 填写信息 -->
<view class="card form-card">
<view class="section-title">填写您的信息</view>
<view class="form-item">
<text class="form-label"> :</text>
<u-input shape="circle" placeholderStyle="font-size: 24rpx;" v-model="form.name" placeholder="请填写姓名" border="surround" />
</view>
<view class="form-item">
<text class="form-label">联系电话:</text>
<u-input shape="circle" placeholderStyle="font-size: 24rpx;" v-model="form.phone" placeholder="请填写联系电话" border="surround" />
</view>
<view class="form-item">
<text class="form-label">入住时间:</text>
<view class="date-row" @click="chooseDate">
<text class="date-val v12-primary-text">{{ dateRangeText }}</text>
<!-- <u-icon name="arrow-right" size="18" color="#999"></u-icon> -->
</view>
</view>
</view>
<!-- 支付方式 -->
<view class="card pay-card">
<view class="section-title">支付方式</view>
<view
class="payItem acea-row row-middle v12-justify-between"
style="flex-wrap: nowrap; margin-top: 20rpx"
@click="payItem('weixin')"
>
<view class="name acea-row v12-font-24 ">
<!-- <view class="iconfont icon-weixin2" :class="active === 'weixin' ? 'bounceIn' : ''"></view> -->
<image style="flex-shrink: 0;width: 32rpx;height: 32rpx;margin-right: 10rpx;" :src="webUrl+'/orderIcon/微信支付.png'" mode=""></image>
微信支付
</view>
<view class="tip"></view>
<label class="radio">
<radio style="transform: scale(0.7);" value="" :checked="active === 'weixin'" color="#C52733"/>
<text></text>
</label>
</view>
<u-divider></u-divider>
<view
class="payItem acea-row row-middle v12-justify-between"
style="flex-wrap: nowrap;"
@click="payItem('yue')"
>
<view class="name acea-row v12-font-24">
<image style="flex-shrink: 0;width: 32rpx;height: 32rpx;margin-right: 10rpx;" :src="webUrl+'/orderIcon/余额宝.png'" mode=""></image>
余额支付
</view>
<!-- <view class="tip">可用余额{{ userInfo.nowMoney ? force2Decimal(userInfo.nowMoney) : 0.00 }}</view> -->
<label class="radio">
<radio style="transform: scale(0.7);" value="" :checked="active === 'yue'" color="#C52733"/>
<text></text>
</label>
</view>
</view>
<!-- 退改规则 -->
<view class="card text-card">
<view class="section-title">退改规则</view>
<view class="plain-text v12-font-26">
根据商家政策与商家确认入住时间前可免费取消如若确认入住后需要更改入住时间可需联系客服与商家商议新的入住时间若与商家确认入住时间后因取消/退订则根据不同阶段进行退款
</view>
<view class="v12-mt-4">
<view class="section-title">预定说明</view>
<view class="plain-text">
订单生效规则订单需商家确认后方可生效确认结果将通过短信通知您请务必在订单生效后再前往商家办理入住以免影响您的行程
</view>
<view class="plain-text">
服务条款说明预订单由香道滇平台提供为保障您的权益请仔细阅读香道平台旅居预订服务规则旅居服务由对应旅居服务提供者旅居管家/旅居商家提供该业务的实际运营及相关责任由旅居商家基于签约主体公司承担
</view>
</view>
</view>
<view class="bottom-space"></view>
</scroll-view>
<!-- 底部栏 -->
<view class="bottom-bar">
<view class="total">
<text>合计</text>
<text class="highlight">
<text class="v12-font-20"></text>{{ orderInfo.priceGroup.totalPrice }}
</text>
</view>
<view class="bar-actions">
<view class="mini-btn" @click="contactMerchant">联系商家</view>
<view class="buy-btn" @click="subscribePay">立即购买</view>
</view>
</view>
<!-- 日期选择器简单占位 -->
<u-calendar v-model="showCalendar" mode="range" :min-date="minDate" @confirm="onDateConfirm" />
<passkeyborad
v-if="isShowPayPwdPop"
ref='payPwdPop'
showMoney
:money="orderInfo.priceGroup.totalPrice"
:show="isShowPayPwdPop"
@close="pwdPopClose"
@finish="pwdPopFinish"
></passkeyborad>
</view>
</template>
<script>
import { createJiaLouOrder, createJiaLouOrderPay } from '@/api/qianxian'
import buyMixins from '../mixins/buyMixins'
import blPaymentPasswordInput from '@/components/blPaymentPasswordInput.vue'
import {mapGetters} from "vuex"
import passkeyborad from '@/components/yzc-paykeyboard/yzc-paykeyboard'
export default {
name: 'SubmitOrder',
mixins: [buyMixins],
components: {
blPaymentPasswordInput,
passkeyborad
},
data() {
return {
from: this.$deviceType,
webUrl: this.$VUE_APP_RESOURCES_URL,
form: {
name: '',
phone: '',
payWay: 'wechat',
start: '2025-08-17',
end: '2025-08-23',
id: ''
},
showCalendar: false,
minDate: this.formatDate(new Date()),
orderInfo: {},
payPassword: null,
isShowPayPwdPop: false
}
},
onLoad(opts) {
const { id, orderStartDate, orderEndDate } = opts
this.form.start = orderStartDate
this.form.end = orderEndDate
this.form.id = id
this.getOrderConfim()
},
computed: {
...mapGetters(["userInfo", "storeItems"]),
dateRangeText() {
return this.formatDisplay(this.form.start) + ' ~ ' + this.formatDisplay(this.form.end)
}
},
methods: {
pwdPopClose() {
this.isShowPayPwdPop = false
},
pwdPopFinish(payPwd) {
this.payPassword = payPwd
this.createOrder(true)
},
chooseDate() { this.showCalendar = true },
onDateConfirm(e) {
const [start, end] = e;
this.form.start = start
this.form.end = end
this.showCalendar = false
},
formatDisplay(dateStr) {
if (!dateStr) return ''
const [y, m, d] = dateStr.split('-')
return `${y}${m}${d}`
},
formatDate(d) {
const y = d.getFullYear()
const m = String(d.getMonth()+1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
},
contactMerchant() {
uni.showToast({ title: '已为您接入管家', icon: 'none' })
},
submitOrder() {
if (!this.form.name || !this.form.phone) {
uni.showToast({ title: '请完整填写信息', icon: 'none' })
return
}
uni.showToast({ title: '下单成功(示意)', icon: 'success' })
},
getOrderConfim() {
createJiaLouOrder({
travelGroupProductId: this.form.id,
orderStartDate: this.form.start,
orderEndDate: this.form.end
}).then(res => {
if (res.status === 200) {
this.orderInfo = res.data
// uni.showToast({ title: '下单成功(示意)', icon: 'success' })
} else {
// uni.showToast({ title: res.msg || '下单失败', icon: 'none' })
}
})
},
createOrder(isyue) {
if (!this.active) {
uni.showToast({
title: "请选择支付方式",
icon: "none",
duration: 2000
})
return
}
if (!/^1(3|4|5|7|8|9|6)\d{9}$/.test(this.form.phone)) {
uni.showToast({
title: "请填写正确的手机号",
icon: "none",
duration: 2000
})
return;
}
if (!/^[\u4e00-\u9fa5\w]{2,16}$/.test(this.form.name)) {
uni.showToast({
title: "请填写您的真实姓名",
icon: "none",
duration: 2000
})
return
}
// 判断如果是余额支付,先要输入支付密码
if (this.active == 'yue' && !isyue) {
// 先判断用户是否绑定过手机
if (this.userInfo.phone) {
// 再判断用户是否设置过支付密码
if (this.userInfo.hasPwdPay) {
// 显示输入支付密码
this.isShowPayPwdPop = true
} else {
// 设置支付密码
this.$yrouter.push("/pkg_user/views/payPassword?isSetMode=true")
}
} else {
// 跳转到绑定手机
this.$yrouter.push("/pkg_user/views/bindPhone")
}
return
}
uni.showLoading({
title: "生成订单中"
})
let from = {}
if (this.$deviceType == "app") {
from.from = "app"
}
const params = {
key: this.orderInfo.orderKey,
realName: this.form.name,
phone: this.form.phone,
from: this.from,
payType: this.active,
passwordPay: this.payPassword
// ...from
}
//余额支付的支付密码
if (this.active == 'yue') {
params.passwordPay = this.payPassword
}
var that = this
createJiaLouOrderPay(params).then(res => {
uni.hideLoading()
const data = res.data
switch (data.status) {
case "ORDER_EXIST":
case "EXTEND_ORDER":
uni.showToast({
title: res.msg,
icon: "none",
duration: 2000
})
this.$yrouter.replace({
path: "/pages/order/OrderDetails/index?isGroup=1",
query: {
id: data.result.orderId
}
})
break;
case "PAY_DEFICIENCY":
break;
case "PAY_ERROR":
uni.showToast({
title: res.msg,
icon: "none",
duration: 2000
})
this.$yrouter.replace({
path: "/pages/order/OrderDetails/index?isGroup=1",
query: {
id: data.result.orderId
}
});
break;
case "SUCCESS":
uni.showToast({
title: res.msg,
icon: "none",
duration: 2000
})
this.$yrouter.replace({
path: "/pages/order/OrderDetails/index?isGroup=1",
query: {
id: data.result.orderId
}
})
break;
case "WECHAT_H5_PAY":
// H5支付
this.$yrouter.replace({
path: "/pages/order/OrderDetails/index?isGroup=1",
query: {
id: data.result.orderId
}
})
break;
case "WECHAT_PAY":
// 小程序支付
weappPay(data.result.jsConfig).finally(() => {
this.$yrouter.replace({
path: "/pages/order/OrderDetails/index?isGroup=1",
query: {
id: data.result.orderId
}
})
})
break;
case "WECHAT_APP_PAY":
// APP支付
weappPay(data.result.jsConfig).finally(() => {
this.$yrouter.replace({
path: "/pages/order/OrderDetails/index?isGroup=1",
query: {
id: data.result.orderId
}
});
})
break;
}
}).catch(err => {
uni.hideLoading()
uni.showToast({
title: err.msg ||
err.response.data.msg ||
err.response.data.message ||
"创建订单失败",
icon: "none",
duration: 2000
})
}).finally(function () {
that.isShowPayPwdPop = false
that.$refs.payPwdPop.clear()
that.$refs.payPwdPop.close()
})
},
subscribePay() {
uni.requestSubscribeMessage({
tmplIds: [
'7O3wKw7_D4t7yfSOlvecKuOQP8QEPY88uBx2FJg43HE',
'TSmTnGibZ8IxWCiRWOvLxha6-0u7tE-V1-WbDCiPkKU',
'9Q6xLHe6HyjkU5Zn5k_2zxYPf2y4MxVyUbOSW8pcZRU'
],
complete: () => this.createOrder(false)
})
},
}
}
</script>
<style lang="less" scoped>
.submit-order { min-height: 100vh; }
.page-scroll { height: calc(100vh - 120rpx); }
.card { background: #fff; border-radius: 24rpx; margin: 24rpx; padding: 24rpx; }
.product-card { display: flex; }
.thumb { width: 160rpx; height: 160rpx; border-radius: 16rpx; }
.info { flex: 1; margin-left: 20rpx; }
.title { font-size: 28rpx; color: #333; line-height: 40rpx; font-weight: 600; }
.price-row { margin-top: 8rpx; display: flex; align-items: baseline; }
.label { font-size: 24rpx; color: #666; }
.price { color: #E53935; font-size: 34rpx; font-weight: 700; }
.notice { margin-top: 12rpx; font-size: 22rpx; color: #999; }
.section-title { font-size: 28rpx; color: #111; font-weight: 600; margin-bottom: 12rpx; }
.form-item { margin-bottom: 20rpx; display: flex; align-items: center; }
.form-label { width: 120rpx; display: block; font-size: 24rpx; color: #666; margin-bottom: 0; }
.date-row { display: flex; align-items: center; justify-content: space-between; background: #fff; border-radius: 16rpx; padding: 20rpx; }
.date-val { font-size: 26rpx; color: #333; }
.radio-item { margin-bottom: 16rpx; }
.text-card .plain-text { font-size: 26rpx; color: #666; line-height: 40rpx; letter-spacing: 2px;}
.bottom-space { height: 140rpx; }
.bottom-bar { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; border-top: 1rpx solid #eee; display: flex; align-items: center; justify-content: space-between; padding: 16rpx 24rpx; }
.total { font-size: 28rpx; color: #111; font-weight: 700; }
.total .highlight { color: #C52733; font-weight: 700; }
.bar-actions { display: flex; gap: 16rpx; }
.mini-btn { padding: 16rpx 22rpx; border: 1rpx solid #ccc; border-radius: 32rpx; font-size: 26rpx; color: #333; }
.buy-btn { padding: 16rpx 28rpx; border-radius: 32rpx; background: #C52733; color: #fff; font-size: 26rpx; }
</style>