Files
soulspace/pages/wallet/recharge.vue
2025-05-06 15:22:09 +08:00

811 lines
18 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 class="commonPageBox">
<z-nav-bar title="充值" :homeState="options.source == 'order' ? 1000 : 2000"
:backState="options.source == 'order' ? 2000 : 1000"></z-nav-bar>
<view>
<view class="cha_jine">
<view class="cj_title PM_font">充值金额</view>
<view class="cj_xiang">
<view v-for="(item, index) in cjList" @click="chosPric(item)" :class="
stepsCj.priceTypeId == item.priceTypeId
? 'Tab_cj cj_price'
: 'cj_price'
">
<view class="pr_jg">{{ item.realMoney }}</view>
<view class="pr_yl">{{ item.money }} 天医币</view>
<view class="pr_lj">限时特惠</view>
</view>
<br clear="both" />
</view>
</view>
<view class="cha_fangsh">
<view class="cf_title PM_font">支付方式</view>
<view class="cf_radio">
<u-radio-group v-model="payType">
<view style="width: 100%" v-if="isAndroid">
<view v-for="(item, index) in paylist" @click="choseType(item.id)"
:class="payType == item.id ? 'Tab_xf cf_xuanx' : 'cf_xuanx'">
<image class="pay_item_img" :src="item.imgUrl" mode="aspectFil">
</image>
{{ item.title }}
<u-radio :key="index" activeColor="#7dc1f0" :name="item.id"
style="float: right; margin-top: 5rpx"></u-radio>
</view>
</view>
<view style="width: 100%" v-else>
<view v-for="(item, index) in iosPaylist" @click="choseType(item.id)"
:class="payType == item.id ? 'Tab_xf cf_xuanx' : 'cf_xuanx'">
<image class="pay_item_img" :src="item.imgUrl" mode="aspectFil">
</image>
{{ item.title }}
<u-radio :key="index" activeColor="#7dc1f0" :name="item.id"
style="float: right; margin-top: 5rpx"></u-radio>
</view>
</view>
</u-radio-group>
</view>
</view>
<view class="agree_wo flexbox" style="float: left; display: flex">
<radio-group class="agree">
<view v-for="(item, index) in argee" :key="index">
<radio class="agreeRadio" :value="item.id" :checked="item.id == radioValue" color="#7dc1f0"
@click="radioCheck(index)"></radio>
</view>
</radio-group>
<view>* 我已阅读并同意<span class="highlight" @click="showXieyi">增值服务协议</span></view>
</view>
<view class="char_btn">
<view @click="goToPay">立即充值</view>
</view>
</view>
<!-- 充值协议 -->
<u-popup :show="xieyiShow" :round="10" @close="xieyiShow = false">
<view class="tanchu">
<view class="dp_title">{{ xieyi.title }}</view>
<view style="max-height: 1000rpx; overflow-y: scroll">
<view v-html="xieyi.content"></view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import $http from "@/config/requestConfig.js";
import { checkIapOrder } from "@/store/modules/common.js";
import {
mapState,
mapMutations
} from "vuex";
import {
setPay,
setPayAssign,
setWXPay
} from "@/config/utils";
export default {
data() {
return {
playData: {},
options: {},
xieyi: {
title: "",
content: "",
},
chargeOrderSn: "", // 通过query传过来的orderSN二次支付情况
xieyiShow: false,
stepsCj: {},
cjList: [],
argee: [{value: false, id: "1"}], // 同意权限
radioValue: "",
orderSn: "", // 订单sn
productid: "",
isAndroid: true, // 是否为安卓环境
payType: null,
paylist: [{
title: "支付宝",
id: 2,
imgUrl: require("@/static/icon/pay_1.png"),
},
{
title: "微信",
id: 1,
imgUrl: require("@/static/icon/pay_2.png"),
},
],
iosPaylist: [{
title: "IAP 支付",
id: 3,
imgUrl: require("@/static/icon/pay_2.png"),
}, ],
transaction: {
// 成功回调
},
urlList: {
list: "common/bookBuyConfig/getBookBuyConfigList",
},
};
},
//第一次加载
onLoad(options) {
this.options = options;
if (this.$platform == "ios") {
this.payType = 3;
} else {
this.payType = 1;
}
this.chargeOrderSn = options.orderSn;
this.getDevName();
},
//页面显示
onShow() {
},
computed: {
...mapState(["userInfo"]),
},
//方法
methods: {
...mapMutations(["setUserInfo"]),
// 关闭交易订单
finishTransaction(trans) {
this.iapChannel.finishTransaction(
trans,
(success) => {
console.log("关闭订单成功");
this.setUserInfo({
restoreFlag: false,
});
},
(fail) => {
console.log("关闭订单失败");
}
);
},
async showXieyi() {
var data = await this.$commonJS.getAgreement(110);
if (data.content) {
data.content = data.content.replace(
/<h5>/g,
'<view style="font-weight: bold;font-size: 32rpx;margin-top: 20rpx;margin-bottom: 20rpx;">'
);
data.content = data.content.replace(/<\/h5>/g, "</view>");
}
this.xieyi = data;
this.xieyiShow = true;
},
radioCheck(index) {
// 勾选用户协议
this.argee.forEach((item) => {
item.isCheck = false;
});
if (this.radioValue == this.argee[index].id) {
this.radioValue = null;
} else {
this.radioValue = this.argee[index].id;
}
},
getProvider() {
return new Promise((resolve, reject) => {
uni.getProvider({
service: 'payment',
success: (res) => {
const iapChannel = res.providers.find((channel) => {
return (channel.id === 'appleiap')
})
resolve(iapChannel);
// 如果 iapChannel 为 null说明当前包没有包含iap支付模块。注意HBuilder基座不包含 iap 通道
}
});
})
},
requestPayment(orderInfo) {
let that = this
return new Promise((resolve, reject) => {
uni.requestPayment({
provider: 'appleiap',
orderInfo: orderInfo,
success: (res) => {
that.iapCheck(res);
resolve(res);
},
fail: (err) => {
uni.hideLoading()
that.restoreComplateRequest()
if (err.code == 2) {
uni.showToast({
title: '取消支付,内购订单即将关闭',
icon: 'none'
})
} else {
uni.showToast({
title: '支付失败,内购订单即将关闭',
icon: 'none'
})
}
reject(err);
}
});
})
},
// 查询未关闭iap订单
async restoreComplateRequest() {
let that = this;
await this.iapChannel.restoreCompletedTransactions({
manualFinishTransaction: true
}, function(results) {
// results 格式为数组存放恢复的IAP商品交易信息对象 IAPTransaction通用需将返回的支付凭证传给后端进行二次认证
that.ComplateRequestArr = results
console.log('未完成订单数组共有:=》', that.ComplateRequestArr.length)
if (results && results.length > 0) {
results.map((item, index) => {
// "0"为正在支付;"1"为支付成功;"2"为支付失败;"3"为支付已恢复。
// if (item.transactionState == '1') {
// // 已经支付,但是没有走逻辑的内购订单 就发给后台做验证
// that.iapCheck('未完成订单的验证', item, index)
// // that.finishTransaction(item)
// } else if (item.transactionState != '1' || item.transactionState != '0') {
// // 不是正在支付订单,也不是已经支付订单就关闭掉
// // 其他状态的内购订单
// }
that.finishTransaction(item);
});
}
});
},
async iphonepay() {
const that = this;
uni.showLoading({
title: "检测支付环境"
})
this.iapChannel = await this.getProvider()
if (this.iapChannel) {
await this.restoreComplateRequest();
await this.requestOrder();
} else {
uni.hideLoading()
uni.showToast({
title: '不支持内购支付',
icon: 'none'
})
}
},
requestOrder() {
uni.showLoading({
title: "获取商品信息",
mask: true,
});
const that = this;
let IAPOrders = [];
IAPOrders.push('s' + that.stepsCj.priceTypeId);
// 新建订单
uni.showLoading({
title: "正在创建订单",
mask: true,
});
that.iapChannel.requestProduct(
IAPOrders,
function(event) {
for (var index in event) {
var OrderItem = event[index];
that.topay(OrderItem.productid);
}
},
function(erroemsg) {
uni.showToast({
title: "商品获取失败",
icon: "none",
});
}
);
},
async topay(id) {
const that = this;
uni.showLoading({
title: "正在支付",
mask: true,
});
let orderInfo = {
productid: id,
username: that.orderSn, // 用户标识/订单标识
quantity: 1,
manualFinishTransaction: true, // 3.5.1+ 支持,设置此参数后需要开发者主动关闭订单,参见下面的关闭订单方法 finishTransaction()
}
that.transaction = await that.requestPayment(orderInfo)
},
iapCheck(result) {
let that = this;
let data = {
transactionId: result.transactionIdentifier, // 支付交易id
customerOid: that.userInfo.id,
productId: result.payment.productid.slice(1), // 产品id
orderId: result.payment.username, // 系统订单号
receiptData: result.transactionReceipt, // 苹果返回收据
// sandBox: true, //测试数据
// body: that.stepsCj.priceTypeId // 充值类型id
};
$http
.request({
url: "Ipa/veri",
method: "POST",
data,
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
if (res.code == 0) {
that.transaction = null
uni.hideLoading()
uni.showToast({
title: '充值成功!',
icon: 'success'
})
// 服务器验证票据有效后在客户端关闭订单 (iapChannel.finishTransaction)
//that.finishTransaction(result);
}
})
.catch((e) => {
uni.hideLoading()
uni.showModal({
title: "提示",
showCancel: false,
content: "支付验证失败请稍后重启app如不能解决您的问题可联系官方客服",
success: function(res) {
if (res.confirm) {
console.log("用户点击确定");
}
},
});
//that.finishTransaction(result);
}, )
},
getDevName() {
// 获取使用环境
if (uni.getSystemInfoSync().platform === "android") {
this.isAndroid = true;
} else {
this.isAndroid = false;
}
this.getData();
},
// 获取充值金额
getData() {
if (this.isAndroid) {
this.getAndorList();
} else {
this.getAppleList();
}
},
// 安卓充值列表
getAndorList() {
var data = {
type: "point",
qudao: "Android",
};
$http.request({
url: this.urlList.list,
method: "POST",
data,
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
this.cjList = res.bookBuyConfigList;
this.stepsCj = res.bookBuyConfigList[0];
});
},
// 苹果充值列表
getAppleList() {
var data = {
type: "point",
qudao: "IOS",
};
$http.request({
url: this.urlList.list,
method: "POST",
data,
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
this.cjList = res.bookBuyConfigList;
this.stepsCj = res.bookBuyConfigList[0];
});
},
// 点击充值金额
chosPric(e) {
this.stepsCj = e;
},
// 选择支付方式1
choseType(e) {
let that = this;
that.payType = e;
},
//ios充值
iosPay() {
// 苹果内购实现思路:
// 1.先确认支付通道是否包含苹果内购
// 2.检查一下是否存在上次未处理完的订单(主要是支付成功没有走回调的订单),异常订单直接关闭掉,成功没有走回调的提交给后台进行验证
// 3.请求并创建新的订单
this.iphonepay();
},
// 充值
goToPay() {
this.kaiChar();
},
// 正常充值
kaiChar() {
if (!this.payType) {
uni.showToast({
title: "请勾选支付方式",
icon: "none",
});
return false;
}
//常规充值
if (this.radioValue == "1") {
uni.showLoading({
title: "支付中,请勿离开",
icon: "loading",
});
let that = this;
let data = {
userId: that.userInfo.id, //下单人ID
userPhone: that.userInfo.tel, //收货人手机号
paymentMethod: that.payType, //2支付宝1微信3ios内购
orderMoney: that.stepsCj.money * 1, //订单金额
districtMoney: 0, //优惠金额
realMoney: that.stepsCj.money * 1, //实收金额
appName: "xlkj",
come: "3",
productId: that.stepsCj.priceTypeId, // 充值的类型id
};
$http.request({
url: "book/buyOrder/rechargeSave",
method: "POST",
data,
header: {
"Content-Type": "application/json",
},
})
.then((res) => {
that.orderSn = res.orderSn;
uni.hideLoading();
if (res.code == 0) {
if (that.payType == 2) {
setPay({
typePay: "alipay",
subject: "point",
totalAmount: that.stepsCj.money,
type: that.payType,
relevanceoid: res.orderSn,
body: that.stepsCj.priceTypeId,
},
(res) => {
if (res.success) {
uni.showToast({
title: "支付成功",
});
setTimeout(() => {
uni.navigateTo({
url: "/pages/wallet/account?source=recharge",
});
}, 2000);
} else {
uni.showToast({
title: "支付失败",
icon: "none"
});
}
}
);
} else if (that.payType == 1) {
// 微信支付
that.orderSn = res.orderSn;
let data1 = {
orderSn: res.orderSn,
buyOrderId: that.stepsCj.priceTypeId,
totalAmount: that.stepsCj.money,
};
setWXPay(data1, (res) => {
if (res.success) {
uni.showToast({
title: "支付成功",
});
setTimeout(() => {
uni.navigateTo({
url: "/pages/wallet/account?source=recharge",
});
}, 2000);
} else {
console.log(res);
if (res.data.errMsg.indexOf("User canceled") != -1) {
uni.showToast({
title: "用户取消支付",
icon: "none"
});
} else {
uni.showToast({
title: "支付失败",
icon: "none"
});
}
}
});
} else if (that.payType == 3) {
console.log("苹果支付");
that.iosPay();
}
}
});
} else {
uni.showToast({
title: "请勾选 已阅读增值服务协议",
icon: "none",
});
return false;
}
},
// 跳转
onPageJump(url) {
uni.navigateTo({
url: url,
});
},
},
};
</script>
<style lang="scss" scoped>
@import "@/static/mixin.scss";
.tanchu {
padding: 40rpx 30rpx 40rpx 30rpx;
position: relative;
.dp_title {
font-size: 32rpx;
margin-bottom: 50rpx;
color: #555;
text-align: center;
font-weight: bold;
}
.dp_add {
position: absolute;
top: 40rpx;
right: 30rpx;
font-size: 22rpx;
background-color: #fd6004;
color: #fff;
border-radius: 10rpx;
padding: 5rpx 10rpx;
.u-icon {
display: inline-block;
margin-right: 5rpx;
}
}
.addressItem {
border: 2px dashed #d9d9d9;
border-radius: 10rpx;
width: 100%;
display: flex;
padding: 20rpx 10rpx;
margin: 25rpx 0 0 0;
align-items: center;
background-color: #fff;
.addrContent {
margin-left: 40rpx;
flex: 1;
.addrContentTop {
display: flex;
align-items: flex-end;
margin: 0 0 15rpx 0;
position: relative;
.userName {
font-size: 35rpx;
font-weight: bold;
margin-right: 30rpx;
}
.userTel {
font-size: 25rpx;
color: #888;
}
.userMoren {
border: 1px solid #fd6004;
color: #fd6004;
padding: 3rpx 10rpx;
font-size: 22rpx;
border-radius: 10rpx;
margin: 0 0 0 20rpx;
}
.chooseCheck {
position: absolute;
top: 3rpx;
right: 6rpx;
}
}
.addrContentBottom {
font-size: 32rpx;
}
}
}
.addressItem.addItem_style {
border-color: #fd6004;
}
.youhuiItem {
border: 1px solid #d9d9d9;
border-radius: 10rpx;
width: 100%;
display: flex;
padding: 20rpx 10rpx;
margin: 25rpx 0 0 0;
align-items: center;
background-color: #fff;
font-size: 30rpx;
}
.youhuiItem>view {
float: left;
}
.youhuiItem.youItem_style {
border-color: #fd6004;
}
}
.agreeRadio {
zoom: 0.8;
}
.cha_jine {
padding: 60rpx 30rpx 40rpx;
.cj_title {
font-size: 46rpx;
color: #294a97;
}
.cj_xiang {
margin-top: 40rpx;
.cj_price {
box-shadow: 0 0 20rpx 0 #0000001a;
float: left;
width: 47%;
margin: 0 5% 30rpx 0;
text-align: center;
padding: 20rpx;
border-radius: 15rpx;
position: relative;
color: #2d2d2d;
.pr_jg {
font-size: 45rpx;
margin: 20rpx 0 10rpx 0;
font-weight: bold;
}
.pr_yl {
font-size: 26rpx;
color: #575555;
}
.pr_lj {
background-image: linear-gradient(180deg, #7dc1f0 0%, #a7defc 100%);
color: #fff;
position: absolute;
top: -30rpx;
right: -20rpx;
font-size: 24rpx;
padding: 5rpx 10rpx;
border-top-left-radius: 20rpx;
border-bottom-right-radius: 20rpx;
}
}
.cj_price:nth-child(2n) {
margin-right: 0;
}
.Tab_cj {
box-shadow: 0px 0px 5px 0px $themeColor !important;
color: #7dc1f0;
.pr_yl{
color: #7dc1f0;
}
}
}
}
.highlight {
color: $uni-color-primary;
}
.cha_fangsh {
padding: 40rpx 30rpx;
.cf_title {
font-size: 46rpx;
color: #294a97;
}
.cf_radio {
margin-top: 20rpx;
.cf_xuanx {
font-size: 32rpx;
padding: 20rpx 0;
margin-bottom: 20rpx;
border-bottom: 1px solid #ededed;
image {
width: 40rpx;
height: 40rpx;
display: inline-block;
margin-right: 20rpx;
vertical-align: bottom;
}
}
}
}
.agree_wo {
color: #aaa;
font-size: 25rpx;
margin-top: 30rpx;
padding: 30rpx;
padding-bottom: 180rpx;
}
.char_btn {
position: fixed;
left: 0;
right: 0;
bottom: 30rpx;
view {
background: linear-gradient(90deg, #294a97 0%, #7dc1f0 90%);
color: #fff;
width: 90%;
margin: 0 auto;
text-align: center;
font-size: 30rpx;
padding: 20rpx 0;
border-radius: 50rpx;
}
}
.pay_item_img {
width: 50rpx;
height: 50rpx;
float: left;
margin-right: 20rpx;
}
.agree {
width: auto !important;
}
.commonPageBox {
background-color: #fff !important;
}
</style>