chshPay/pages/index/index.vue

619 lines
15 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>
<!-- 店铺扫码支付页 -->
<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>