chshPay/pages/index/index.vue

650 lines
16 KiB
Vue
Raw 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,
getMerchantInfoByCode
} 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,
order_id: '', // 查询订单号
dat: '', // 直接支付的参数
tabIndex: '', // 支付结束的tab选项
orderData: {} // 显示的价格 { price: '100' }
}
},
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('merchant_id') && !getUrlParam('from_type')) {
this.getData(getUrlParam('merchant_id'));
} else if (getUrlParam('code')) {
this.getQrData(getUrlParam('code'));
} else {
uni.showToast({
title: '店铺码为空',
icon: 'none'
});
}
} else {
// 没有token拼接当前url跳转到登录页
console.log(encodeURIComponent(cleanUrl), '跳转');
window.location.replace(`${HTTP_REQUEST_URL}/api/v2/routine/gzhLogin?back_url=${encodeURIComponent(cleanUrl)}`);
}
},
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
})
},
// CODE获取商户信息
getQrData(qrcode) {
let that = this;
this.qrcode = qrcode;
getMerchantInfoByCode({
code: qrcode
}).then(res => {
this.form = res.data.merchantInfo;
this.merchant_id = res.data.merchantInfo.merchant_id;
this.a = true;
this.loading = false;
// 获取商户信息后,初始化抵用券信息
this.calculatePayment();
}).catch(error => {
// 返回的文字判断,优先显示未绑定码牌
this.loading = false
this.showModal = true;
this.form.merchantInfo = 0;
this.form.status = 1;
})
},
// 抵用券状态变化
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'
});
}
},
async keyConfirm(e) {
// 输入验证
if (isNaN(this.money)) {
uni.showToast({
title: '请输入正常的数字',
icon: 'none'
});
return;
}
if (Number(this.money) >= 1000000) {
uni.showToast({
title: '支付金额不能大于一百万',
icon: 'none'
});
return;
}
if (Number(this.money) <= 0) {
uni.showToast({
title: '支付金额不能为0',
icon: 'none'
});
return;
}
uni.showLoading({
title: "正在跳转中",
mask: true
});
if (!this.merchant_id) {
uni.hideLoading()
uni.showToast({
title: '缺少支付信息',
icon: 'none'
});
return
};
try {
// 准备支付参数
const params = {
pay_price: Number(this.money),
use_coin: this.couponUsed ? 1 : 0,
use_broker: this.commissionUsed ? 1 : 0,
merchant_id: this.merchant_id,
code: this.qrcode,
is_middle_pay: 1
};
// 执行支付
const apiCall = Number(this.isAllApi) ? doOrder : dogzhOrder;
const res = await apiCall(params);
const jsConfig = res.data;
const order_sn = jsConfig.order_sn;
// 检查环境
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=${order_sn}&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
});
}
},
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>