619 lines
15 KiB
Vue
619 lines
15 KiB
Vue
<template>
|
||
<view>
|
||
<!-- 店铺扫码支付页 -->
|
||
<view class="content">
|
||
<view class="main">
|
||
<view class="title">
|
||
<image class="shop-images" src="https://img.agrimedia.cn/APP-ZhiFuBusiness/shop.png"></image>
|
||
<view class="name">{{form.name? form.name : '--'}}</view>
|
||
</view>
|
||
<view class="money" @click="inputClick()">
|
||
<view class="input">
|
||
<text class="txt">消费金额</text>
|
||
<view class="flex wrap">
|
||
<input class="num" type="text" v-model="money" disabled="true" />
|
||
<text class="line" v-if="!money">|</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="container">
|
||
<view class="list-item" @click="rateTypeClick(2)">
|
||
<text class="titles">抵用券抵扣</text>
|
||
<view class="right-section">
|
||
<text>{{(Number(broker) + Number(vouchers)).toFixed(2) == 0? '0.00' : (Number(broker) + Number(vouchers)).toFixed(2)}}</text>
|
||
<view class="wx_flex wx_flex-items-center">
|
||
<image style="width: 31rpx;height: 31rpx; margin-top: 10rpx"
|
||
:src="couponUsed==1?'https://imgs.agrimedia.cn/shop/select_icon.png':'https://imgs.agrimedia.cn/shop/unselect_icon.png'"
|
||
mode=""></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 实际支付 -->
|
||
<view class="payment-section">
|
||
<text class="titles">实际支付</text>
|
||
<text class="payment-amount">¥{{actualPayment}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="pay-btn" @click="keyConfirm">
|
||
去支付
|
||
</view>
|
||
|
||
<!-- <monokeyboard
|
||
ref="mono"
|
||
:value="money"
|
||
:show="keyshow"
|
||
@confirm="keyConfirm"
|
||
@change="keyChange"
|
||
:isPay="a">
|
||
</monokeyboard> -->
|
||
|
||
<!-- <view class="shadow" v-if="loading"></view> -->
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
HTTP_REQUEST_URL
|
||
} from '@/config/app';
|
||
import monokeyboard from '@/components/mono-keyboard/mono-keyboard.vue';
|
||
import OnlineShop from '@/components/OnlineShop.vue';
|
||
|
||
import UrlUtils from '@/utils/urlUtils.js';
|
||
import getUrlParam from '@/utils/utils.js';
|
||
import {
|
||
middleLogin,
|
||
computedOrder,
|
||
gzhcomputedOrder,
|
||
getMerchantInfo,
|
||
doOrder,
|
||
dogzhOrder,
|
||
cancelPay,
|
||
|
||
preDetail,
|
||
prePay
|
||
} from '@/api/index';
|
||
|
||
export default {
|
||
components: {
|
||
monokeyboard,
|
||
OnlineShop
|
||
},
|
||
data() {
|
||
return {
|
||
authKey: '',
|
||
bindPhone: '',
|
||
keyshow: true,
|
||
token: '',
|
||
|
||
qrcode: '',
|
||
merchant_id: '', //下单店铺id
|
||
ID: '',
|
||
form: {},
|
||
money: '', // 手动输入
|
||
couponUsed: false, // 抵用券使用状态
|
||
commissionUsed: false, // 佣金使用状态
|
||
vouchers: '',
|
||
broker: '',
|
||
actualPayment: '', // 实际支付金额
|
||
a: false,
|
||
hasAssigned: false, // 标志变量
|
||
loading: true,
|
||
amountInfo: {},
|
||
|
||
dikou: 0,
|
||
isAllApi: '',
|
||
|
||
order_id: '', // 查询订单号
|
||
dat: '', // 直接支付的参数
|
||
tabIndex: '', // 支付结束的tab选项
|
||
orderData: {}, // 显示的价格 { price: '100' }
|
||
orderSn: ''
|
||
}
|
||
},
|
||
|
||
watch: {
|
||
money: {
|
||
handler: function(newV, oldV) {
|
||
this.getTotal()
|
||
},
|
||
deep: true
|
||
}
|
||
},
|
||
|
||
onLoad() {
|
||
const url = window.location.href;
|
||
const cleanUrl = this.cleanUrl(url);
|
||
|
||
const token = getUrlParam('token') || this.$store.state.app.token;
|
||
if (token) {
|
||
this.$store.commit('UPDATE_LOGIN', token);
|
||
this.money = getUrlParam('price') || 0;
|
||
|
||
// 查询苗迈云订单
|
||
if (getUrlParam('order_sn')) {
|
||
this.orderSn = getUrlParam('order_sn');
|
||
try {
|
||
preDetail({ order_sn: this.orderSn }).then(res => {
|
||
console.log(res, '123')
|
||
this.money = res.data.real_pay;
|
||
this.getData(res.data.mid);
|
||
})
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: error,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: 'order_sn为空',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} else {
|
||
// 没有token,拼接当前url跳转到登录页
|
||
console.log(encodeURIComponent(cleanUrl), '跳转');
|
||
window.location.replace(`${HTTP_REQUEST_URL}/api/v2/routine/gzhLogin?back_url=${encodeURIComponent(cleanUrl)}`);
|
||
}
|
||
|
||
// 支付方式: 0 1
|
||
const urlParam = getUrlParam('is_all_api');
|
||
const storedValue = this.$store.state.app.ISPAY;
|
||
|
||
// 如果URL有is_all_api参数(不管是0还是1)
|
||
if (urlParam !== null && urlParam !== undefined && urlParam !== '') {
|
||
console.log(urlParam, '从URL获取参数');
|
||
this.$store.commit('SETALL_PAT', urlParam);
|
||
this.isAllApi = urlParam;
|
||
} else if (storedValue !== null && storedValue !== undefined && storedValue !== '') {
|
||
console.log(storedValue, '从本地存储读取');
|
||
this.isAllApi = storedValue;
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// 清理URL格式,处理多个问号的情况 将多个连续的?替换为单个&
|
||
cleanUrl(url) {
|
||
let cleanUrl = url.replace(/\?+/g, '?');
|
||
const firstQuestionMarkIndex = cleanUrl.indexOf('?');
|
||
if (firstQuestionMarkIndex !== -1) {
|
||
const beforeParams = cleanUrl.substring(0, firstQuestionMarkIndex + 1);
|
||
const afterParams = cleanUrl.substring(firstQuestionMarkIndex + 1).replace(/\?/g, '&');
|
||
cleanUrl = beforeParams + afterParams;
|
||
}
|
||
return cleanUrl;
|
||
},
|
||
|
||
// ID获取店铺
|
||
getData(id) {
|
||
getMerchantInfo({
|
||
id: id
|
||
}).then(res => {
|
||
this.form = res.data;
|
||
this.merchant_id = res.data.merchant_id
|
||
this.a = true;
|
||
this.loading = false;
|
||
// 获取商户信息后,初始化抵用券信息
|
||
this.calculatePayment();
|
||
}).catch(error => {
|
||
uni.showToast({
|
||
title: error,
|
||
icon: 'none'
|
||
})
|
||
this.loading = false
|
||
})
|
||
},
|
||
|
||
// 抵用券状态变化
|
||
rateTypeClick(val) {
|
||
if (this.money > 0 || this.money !== '') {
|
||
if (val == 1) {
|
||
this.commissionUsed = !this.commissionUsed;
|
||
this.couponUsed = !this.couponUsed
|
||
} else {
|
||
this.couponUsed = !this.couponUsed
|
||
this.commissionUsed = !this.commissionUsed;
|
||
}
|
||
this.getTotal();
|
||
} else {
|
||
uni.showToast({
|
||
title: '请输入金额',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
|
||
// 实际支付展示
|
||
getTotal() {
|
||
if (Number(this.amountInfo.broker_balance) + Number(this.amountInfo.coin_balance) >= Number(this.money) &&
|
||
Number(this.money) && this.couponUsed) {
|
||
this.actualPayment = 0.01
|
||
this.dikou = (Number(this.money) - (Number(this.amountInfo.broker_balance) + Number(this.amountInfo
|
||
.coin_balance))).toFixed(2);
|
||
} else if (Number(this.money) && this.couponUsed) {
|
||
this.actualPayment = (Number(this.money) - (Number(this.amountInfo.broker_balance) + Number(this
|
||
.amountInfo.coin_balance))).toFixed(2);
|
||
this.dikou = (Number(this.amountInfo.broker_balance) + Number(this.amountInfo.coin_balance)).toFixed(
|
||
2);
|
||
} else {
|
||
this.actualPayment = this.money;
|
||
}
|
||
},
|
||
|
||
// 查询抵用券余额
|
||
async calculatePayment() {
|
||
const params = {
|
||
pay_price: this.money || 0,
|
||
use_coin: this.couponUsed ? 1 : 0,
|
||
use_broker: this.commissionUsed ? 1 : 0
|
||
};
|
||
|
||
try {
|
||
const apiCall = Number(this.isAllApi) === 1 ? computedOrder : gzhcomputedOrder;
|
||
const res = await apiCall(params);
|
||
|
||
this.actualPayment = res.data.real_pay_price;
|
||
this.amountInfo = res.data;
|
||
|
||
if (!this.hasAssigned) {
|
||
this.hasAssigned = true;
|
||
this.vouchers = res.data.coin_balance;
|
||
this.broker = res.data.broker_balance;
|
||
}
|
||
} catch (error) {
|
||
console.error('获取抵用券余额失败:', error.msg);
|
||
uni.showToast({
|
||
title: error.msg,
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
|
||
|
||
// 支付
|
||
keyConfirm(e) {
|
||
prePay({
|
||
order_sn: this.orderSn,
|
||
use_coin: this.couponUsed ? 1 : 0,
|
||
use_broker: this.commissionUsed ? 1 : 0
|
||
}).then(res => {
|
||
uni.showLoading({
|
||
title: "正在跳转中",
|
||
mask: true
|
||
});
|
||
|
||
try {
|
||
const jsConfig = res.data.prePay;
|
||
|
||
// 检查环境
|
||
const ua = window.navigator.userAgent.toLowerCase();
|
||
const isWechat = ua.includes('micromessenger');
|
||
const isH5 = typeof window !== 'undefined';
|
||
|
||
if (!isH5 || !isWechat) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '请在微信浏览器中使用微信支付功能',
|
||
icon: 'none',
|
||
duration: 3000
|
||
});
|
||
this.cancelVideo();
|
||
return;
|
||
}
|
||
|
||
// 微信支付处理
|
||
if (!jsConfig) {
|
||
uni.showToast({
|
||
title: '支付参数错误',
|
||
icon: 'none'
|
||
});
|
||
uni.hideLoading();
|
||
return;
|
||
}
|
||
|
||
const onBridgeReady = () => {
|
||
window.WeixinJSBridge.invoke(
|
||
'getBrandWCPayRequest', {
|
||
'appId': jsConfig.appId,
|
||
'timeStamp': jsConfig.timeStamp,
|
||
'nonceStr': jsConfig.nonceStr,
|
||
'package': jsConfig.package,
|
||
'signType': jsConfig.signType,
|
||
'paySign': jsConfig.paySign
|
||
}, (res) => {
|
||
const isSuccess = res.err_msg === 'get_brand_wcpay_request:ok';
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: isSuccess ? "支付完成" : "取消支付",
|
||
icon: isSuccess ? 'success' : 'none',
|
||
duration: 2000,
|
||
});
|
||
|
||
this.clearPaymentData();
|
||
if (!isSuccess) this.cancelVideo();
|
||
|
||
setTimeout(() => {
|
||
const url =
|
||
`/pages/Paysuccessful/jxPaysuccessful?merchant_name=${this.form.name}&order_sn=${this.orderSn}&Status=${isSuccess ? 1 : 2}&isAllApi=${this.isAllApi}`;
|
||
uni.redirectTo({
|
||
url
|
||
});
|
||
}, 2000);
|
||
}
|
||
);
|
||
};
|
||
|
||
if (typeof window.WeixinJSBridge === "undefined") {
|
||
if (document.addEventListener) {
|
||
document.addEventListener('WeixinJSBridgeReady', onBridgeReady.bind(this), false);
|
||
} else if (document.attachEvent) {
|
||
document.attachEvent('WeixinJSBridgeReady', onBridgeReady.bind(this));
|
||
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady.bind(this));
|
||
}
|
||
} else {
|
||
onBridgeReady.call(this);
|
||
}
|
||
} catch (err) {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: err.msg || err.message || err.data.message || '支付处理失败',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
}
|
||
})
|
||
|
||
return
|
||
|
||
|
||
|
||
},
|
||
|
||
keyChange(e) {
|
||
if (this.isTwoDecimalPlaces(e)) {
|
||
console.log(e, '123')
|
||
this.money = e
|
||
}
|
||
},
|
||
|
||
inputClick() {
|
||
uni.showToast({
|
||
title: '使用键盘输入',
|
||
icon: 'none'
|
||
})
|
||
},
|
||
|
||
isTwoDecimalPlaces(num) {
|
||
const numStr = num.toString();
|
||
const decimalIndex = numStr.indexOf('.');
|
||
|
||
// 如果没有小数点,或者小数点后的位数不超过 2 位
|
||
if (decimalIndex === -1 || numStr.length - decimalIndex - 1 <= 2) {
|
||
return true; // 输入到了小数点后两位
|
||
} else {
|
||
return false; // 没有输入到小数点后两位
|
||
}
|
||
},
|
||
|
||
|
||
// 清理支付数据
|
||
clearPaymentData() {
|
||
this.money = '';
|
||
this.actualPayment = '';
|
||
this.couponUsed = false;
|
||
this.commissionUsed = false;
|
||
if (this.$refs.mono) {
|
||
this.$refs.mono.money = '';
|
||
}
|
||
},
|
||
|
||
// 取消发声
|
||
cancelVideo() {
|
||
cancelPay({
|
||
merchant_id: this.merchant_id
|
||
}).then(res => {
|
||
console.log(res)
|
||
}).catch(error => {
|
||
console.error('取消支付播报失败:', error);
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.content {
|
||
min-height: 100vh;
|
||
background: linear-gradient(180deg, #f5f5f5 0%, #ffffff 100%);
|
||
padding: 40rpx 30rpx;
|
||
box-sizing: border-box;
|
||
|
||
.main {
|
||
background-color: #ffffff;
|
||
border-radius: 24rpx;
|
||
padding: 0;
|
||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
|
||
overflow: hidden;
|
||
|
||
.title {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 50rpx 30rpx 40rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
|
||
.shop-images {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
margin-right: 16rpx;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.name {
|
||
font-size: 34rpx;
|
||
font-weight: 500;
|
||
color: #333333;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
max-width: 500rpx;
|
||
}
|
||
}
|
||
|
||
.money {
|
||
padding: 50rpx 40rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
|
||
.input {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.txt {
|
||
font-size: 28rpx;
|
||
color: #999999;
|
||
font-weight: 400;
|
||
white-space: nowrap;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.num {
|
||
flex: 1;
|
||
font-weight: 600;
|
||
text-align: right;
|
||
font-size: 56rpx;
|
||
color: #333333;
|
||
letter-spacing: 2rpx;
|
||
}
|
||
|
||
.wrap {
|
||
flex: 1;
|
||
position: relative;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
|
||
.line {
|
||
position: absolute;
|
||
right: 0;
|
||
animation: blink 1s infinite;
|
||
color: #07c160;
|
||
font-size: 56rpx;
|
||
font-weight: 600;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.container {
|
||
.list-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 36rpx 40rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
transition: background-color 0.2s;
|
||
|
||
&:active {
|
||
background-color: #fff;
|
||
}
|
||
|
||
.titles {
|
||
font-size: 32rpx;
|
||
color: #333333;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.right-section {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
|
||
text {
|
||
font-size: 32rpx;
|
||
color: #333333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
image {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
margin-top: 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
.payment-section {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 50rpx 40rpx;
|
||
|
||
.titles {
|
||
font-size: 32rpx;
|
||
color: #666666;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.payment-amount {
|
||
color: #07c160;
|
||
font-size: 48rpx;
|
||
font-weight: 600;
|
||
letter-spacing: 1rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.pay-btn {
|
||
background: linear-gradient(135deg, #07c160 0%, #06ad56 100%);
|
||
width: 100%;
|
||
max-width: 690rpx;
|
||
margin: 60rpx auto 0;
|
||
text-align: center;
|
||
padding: 28rpx 0;
|
||
color: #ffffff;
|
||
border-radius: 12rpx;
|
||
font-size: 36rpx;
|
||
font-weight: 500;
|
||
box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
|
||
transition: all 0.3s;
|
||
letter-spacing: 2rpx;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
box-shadow: 0 4rpx 12rpx rgba(7, 193, 96, 0.25);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 光标闪烁动画 */
|
||
@keyframes blink {
|
||
0%, 100% {
|
||
opacity: 1;
|
||
}
|
||
50% {
|
||
opacity: 0;
|
||
}
|
||
}
|
||
|
||
.shadow {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
width: 100%;
|
||
height: 100vh;
|
||
z-index: 999999;
|
||
}
|
||
</style> |