Commit 7a741779 by wangshuo

订单支付接口

parent 7c4e868b
......@@ -4,6 +4,7 @@ import { OrderItem } from '@/common/index';
import { Link } from 'react-router-dom';
import { http, api } from "@/utils";
import { throttle } from 'lodash';
import {HeaderBar} from '../../common';
import "./order.scss"
......@@ -85,7 +86,7 @@ class Order extends Component {
if(res.data.code !== 200) {
return;
}
console.log(res);
this.props.history.replace(`/payorder?oid=${res.data.data.oid}`);
});
}
// 使用余额
......@@ -172,14 +173,7 @@ class Order extends Component {
<div className="order-wrapper">
<Flex>
<Flex.Item>
<NavBar
style={{ "height": "44px" }}
className="order-tab"
mode="light"
icon={<i className="iconfont iconiconfront-68"></i>}
>
课程报名
</NavBar>
<HeaderBar title='课程报名' arrow={true}></HeaderBar>
{
!this.state.perfect &&
<Link to='/orderinfo' className="order-information">
......
import React, { Component } from 'react';
import { Flex, NavBar, List, InputItem, Button, WhiteSpace, WingBlank, Toast } from 'antd-mobile';
import { Formik, Field, Form, withFormik } from 'formik';
import {HeaderBar} from '../../common';
import { http, api } from "@/utils";
const InnerForm = ({
......@@ -55,25 +56,49 @@ const MyForm = withFormik({
values,
FormBag
) => {
if (!values.real_name) {
const {real_name, cellphone, qq} = values;
if (!real_name) {
Toast.info('请输入姓名!', undefined, undefined, false);
return;
}else if ((`${real_name}`).replace(/\s+/g, '').length === 0) {
Toast.info('请输入姓名!', undefined, undefined, false);
return;
}
if (!values.cellphone) {
if (!cellphone) {
Toast.info('请输入手机号!', undefined, undefined, false);
return;
} else if (!/1\d{10}/g.test(values.cellphone.replace(/\s+/g, ''))) {
} else if (!/1\d{10}/g.test((`${cellphone}`).replace(/\s+/g, ''))) {
Toast.info('请输入正确的手机号!', undefined, undefined, false);
return;
}
if (!values.qq) {
if (!qq) {
Toast.info('请输入QQ号!', undefined, undefined, false);
return;
} else if (!/\d{5,}/g.test(values.qq)) {
} else if (!/\d{5,}/g.test(qq)) {
Toast.info('请输入正确QQ号!', undefined, undefined, false);
return;
}
http.post(`${api.home}/m/order/saveUserInfo`, values).then(res=>{
let same = false;
if(FormBag.props.userInfo) {
const userInfo = FormBag.props.userInfo;
if(userInfo.real_name === real_name) {
same = true;
}
if(userInfo.cellphone === cellphone) {
same = true;
}
if(userInfo.qq === qq) {
same = true;
}
}
if(same) {
FormBag.props.history.replace({
pathname: '/order',
state: values
});
return;
}
http.post(`${api.home}/m/order/saveUserInfo`, {real_name: values.real_name, cellphone: (`${values.cellphone}`).replace(/\s+/g, ''), qq: values.qq}).then(res=>{
if(res.data.code !== 200) {
Toast.info(res.data.msg, undefined, undefined, false);
return;
......@@ -95,14 +120,7 @@ class Orderinfo extends Component {
render() {
return (
<div>
<NavBar
style={{ "height": "44px", backgroundColor: '#F7F9FC' }}
className="order-tab"
mode="light"
icon={<i className="iconfont iconiconfront-68"></i>}
>
报名信息
</NavBar>
<HeaderBar title='报名信息' arrow={true}></HeaderBar>
<MyForm history={this.props.history} userInfo={this.props.location.state}/>
</div>
)
......
import React, { Component } from 'react';
import { Flex, WingBlank, WhiteSpace, List, Radio } from 'antd-mobile';
import {api, http} from '@/utils';
import { api, http, getParam, is_weixin } from '@/utils';
import { OrderItem, HeaderBar } from '@/common/index';
import {Link} from 'react-router-dom';
import { Link } from 'react-router-dom';
import './PayOrder.scss';
import {VList} from '@/common';
import { VList } from '@/common';
const Item = List.Item;
const Brief = Item.Brief;
const RadioItem = Radio.RadioItem;
let mockData = [
{ value: 0, label: '支付宝', icon: 'iconzhifubaox-'},
{ value: 1, label: '微信支付', icon: 'iconweixinzhifu'},
{ value: 2, label: '花呗分期', icon: 'iconhuabei'},
];
let mockList = [
{
"course_id":110,
"course_title":"机器学习 第九期 [加送CPU和GPU双云平台,继续实战作业考试]",
"simpledescription":"BAT工业实战,作业、考试1V1批改",
"image_name":"https://www.julyedu.com/Public/Image/8bd265fcd8.png",
"price0":"899.00",
"price1":"469.00",
"sale_price":"469.00",
"is_coupon":1,
"coupon_num":0
},
{
"course_id":101,
"course_title":"语音识别技术的前世今生 [CMU王赟博士主讲,双旦期间1元秒杀]",
"simpledescription":"解秘历代语音识别系统背后的工作原理",
"image_name":"https://www.julyedu.com/Public/Image/80706a4749.png",
"price0":"400.00",
"price1":"99.00",
"sale_price":"99.00",
"is_coupon":1,
"coupon_num":0
}
]
{ value: 0, label: '支付宝', icon: 'iconzhifubaox-' },
{ value: 1, label: '微信支付', icon: 'iconweixinzhifu' },
// { value: 2, label: '花呗分期', icon: 'iconhuabei' },
];
export default class PayOrder extends Component {
constructor(props) {
super(props);
this.state = {
money: 1000.00,
pay_amount: 0,
payType: 0,
stageNumber: 0,
checkPeriod: false,
singleMoney: 0,
periodNumber: 0,
orderId: getParam('oid'),
huabei: false,
fenqiList: [
{ value: 'zhifubao', qishu: '3', lilv: '2.30%', everyMoney: 300, feiyong: 2.3 },
{ value: 'weixin', qishu: '6', lilv: '4.50%', everyMoney: 150, feiyong: 4.5 },
{ value: 'huabei', qishu: '9', lilv: '7.50%', everyMoney: 100, feiyong: 7.5 },
],
categoryList: [],
}
}
onChange = (value) => {
console.log(value);
this.setState({
payType: value,
checkPeriod: false,
});
if (value === 2) {
this.setState({
huabei: true,
});
}
};
checkStaging = (item) => {
console.log(item);
this.setState({
huabei: false,
checkPeriod: true,
stageNumber: item.value,
singleMoney: item.everyTotal,
periodNumber: item.stage,
checkPeriod: true,
});
}
print = (...e) => {
console.log(e);
};
// 确定购买
pay = () => {
const {payType, orderId} = this.state;
if(payType === 0) {
this.alipayPay(orderId)
} else if (payType === 1) {
this.weixinPay(orderId)
}
// else { // 花呗分期暂时不做
// this.huabeiPay(orderId)
// }
}
// 微信支付
weixinPay = (orderId) => {
// 微信内部-支付
if (is_weixin()) {
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(window.location.href + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
} else {
// 微信外部-支付
http.get(`${api['pay-api']}/pay/wxpay/wap_charge/oid/${orderId}`).then((res) => {
console.log(res);
// oid: "15605001335449291237"
// url: "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx14182145475068ae36051fed1741053900&package=2730911338"
// errno: 0
// msg: "ok"
if (res.data.errno === 0) {
window.location.href = res.data.data.url + "&redirect_url=" + encodeURIComponent(window.location.href + "&weixinpay=1").toLowerCase();
} else {
Toast.info(res.data.msg, 2)
}
})
}
}
// 微信内部支付
isweixinPay = () => {
let weixin_code = getParam('code')
if (weixin_code) {
if (getParam('oid') === undefined) {
return
} else {
http.get(`${api['pay-api']}/pay/wxpay/pub_charge/oid/${getParam('oid')}/code/${weixin_code}`).then((res) => {
if (res.data.errno === 0) {
const data = res.data.data
this.onBridgeReady(data)
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', this.onBridgeReady, false)
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', this.onBridgeReady)
document.attachEvent('onWeixinJSBridgeReady', this.onBridgeReady)
}
} else {
this.onBridgeReady()
}
} else {
Toast.info(res.data.msg, 2)
}
})
}
}
}
// 支付完成之后获取状态
payCallback = () => {
// 调到已购课程 /purchased 不需要传递任何参数
}
onBridgeReady = (data) => {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": data.appId, //公众号名称,由商户传入
"timeStamp": data.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": data.nonceStr, //随机串
"package": data.package,
"signType": data.signType, //微信签名方式:
"paySign": data.paySign //微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
this.payCallback()
} else {
alert('支付失败')
}
}
)
}
// 支付宝支付
alipayPay = (orderId) => {
http.get(`${api['pay-api']}/pay/alipay/wap_charge/oid/${orderId}`).then((res) => {
if (res.data.errno === 0) {
window.location = res.data.data.url;
} else {
Toast.info(res.data.msg, 2)
}
})
}
// 花呗分期 暂时不做
huabeiPay = (orderId) => {
const {singleMoney, periodNumber} = this.state;
console.log('花呗分期支付');
http.get(`/pay/alipay/wap_charge/oid/${orderId}/plat/{plat} /hb_num/${periodNumber}`).then(res=>{
console.log(res);
if (res.data.errno === 0) {
window.location = res.data.data.url;
} else {
Toast.info(res.data.msg, 2)
}
});
}
componentDidMount() {
http.post(`${api.home}/m/order/detail`, {order_id: ''}).then((res) => {
http.post(`${api.home}/m/order/detail`, { order_id: this.state.orderId }).then((res) => {
console.log(res);
if (res.data.code !== 200) {
return;
}
const { course, total_sale, user_account, user_info, discount } = res.data.data;
// this.setState({
// perfect: user_info,
// orderList: course,
// user_account,
// total_sale,
// discount,
// });
})
const { course, pay_amount } = res.data.data;
const fenqiList = [];
[1, 2, 3].map((item)=>{
let obj = {};
obj.value = item;
if(item === 1) {
obj.stage = 3; //期数
obj.moneyRate = '2.30%'; // 分期费率展示
obj.rate = 0.023; // 分期费率计算
obj.periodic = (pay_amount/3).toFixed(2); // 每期本金
} else if (item === 2) {
obj.stage = 6; //期数
obj.moneyRate = '4.50%'; // 分期费率展示
obj.rate = 0.045; // 分期费率计算
obj.periodic = (pay_amount/6).toFixed(2); // 每期本金
} else {
obj.stage = 12; //期数
obj.moneyRate = '7.50%'; // 分期费率展示
obj.rate = 0.075; // 分期费率计算
obj.periodic = (pay_amount/9).toFixed(2); // 每期本金
}
obj.serviceFee = ((pay_amount * obj.rate) / obj.stage).toFixed(2); // 每期的手续费 = 总金额 * 费率 / 期数
obj.everyTotal = (parseFloat(obj.periodic) + parseFloat(obj.serviceFee)).toFixed(2);// 每期总费用 = 每期本金 + 每期手续费
fenqiList.push(obj);
});
console.log(fenqiList);
// { value: 'zhifubao', qishu: '3', lilv: '2.30%', everyMoney: 300, feiyong: 2.3 },
// { value: 'weixin', qishu: '6', lilv: '4.50%', everyMoney: 150, feiyong: 4.5 },
// { value: 'huabei', qishu: '9', lilv: '7.50%', everyMoney: 100, feiyong: 7.5 },
this.setState({
pay_amount,
categoryList: course,
fenqiList,
});
});
if (getParam('is_class') === 1 || getParam('weixinpay')) {
this.payCallback()
}
if (is_weixin()) {
this.isweixinPay()
}
}
render() {
const { money, payType, checkPeriod, singleMoney, periodNumber } = this.state;
const { orderId, pay_amount, payType, checkPeriod, singleMoney, periodNumber, huabei, fenqiList, categoryList, stageNumber } = this.state;
return (
<div className='pay-order'>
<HeaderBar title='确认支付' arrow={true}></HeaderBar>
......@@ -88,13 +229,13 @@ export default class PayOrder extends Component {
<WingBlank>
<Flex justify='between' align='center' style={{ height: '44px' }}>
<span>订单号</span>
<span className='number'>20160815850565</span>
<span className='number'>{orderId}</span>
</Flex>
</WingBlank>
</div>
<WhiteSpace size='md'></WhiteSpace>
{
mockList.map((item, index) => {
categoryList.map((item, index) => {
const Info = (
<div className="order-info">
<p className='order-title text-overflow-one'>
......@@ -119,7 +260,7 @@ export default class PayOrder extends Component {
<WingBlank>
<Flex justify='between' align='center' style={{ height: '44px' }}>
<span>支付金额</span>
<span className='money'>{`¥${money}`}</span>
<span className='money'>{`¥${pay_amount}`}</span>
</Flex>
</WingBlank>
</div>
......@@ -135,17 +276,17 @@ export default class PayOrder extends Component {
{/* {i.label} */}
{
i.value === 2 ? (
<Flex direction='column' align='start' style={{width: '100%', marginTop: '6px'}}>
<Flex direction='row' justify='between' style={{width: '100%', paddingRight: '30px'}}>
<span style={{color: '#555555', fontSize: '14px'}}>{i.label}</span>
<Flex direction='column' align='start' style={{ width: '100%', marginTop: '6px' }}>
<Flex direction='row' justify='between' style={{ width: '100%', paddingRight: '30px' }}>
<span style={{ color: '#555555', fontSize: '14px' }}>{i.label}</span>
{
checkPeriod ? (
<span style={{color: '#333333', fontSize: '12px'}}>{`${singleMoney}元 × ${periodNumber}期`}</span>
<span style={{ color: '#333333', fontSize: '12px' }}>{`${singleMoney}元 × ${periodNumber}期`}</span>
) : null
}
</Flex>
<Flex justify='start'>
<span style={{color: '#999999', fontSize: '12px'}}>支付上限受限于您的花呗额度</span>
<span style={{ color: '#999999', fontSize: '12px' }}>支付上限受限于您的花呗额度</span>
</Flex>
</Flex>
) : (i.label)
......@@ -155,7 +296,26 @@ export default class PayOrder extends Component {
</List>
<div className='pay-tip'>请在24小时内完成支付,否则届时系统将关闭该订单。</div>
<div className='pay-button'>确认支付</div>
<div className='pay-button' onClick={this.pay}>确认支付</div>
{
huabei ? (
<div className='check-staging'>
<div className='container'>
<p className='check-title'>请选择分期</p>
{fenqiList.map(i => (
<RadioItem
key={i.value}
checked={stageNumber === i.value}
onChange={() => this.checkStaging(i)}>
{`${i.everyTotal}元 × ${i.stage}期`}
<List.Item.Brief>{`手续费${i.serviceFee}元/期,费率${i.moneyRate}`}</List.Item.Brief>
</RadioItem>
))}
</div>
</div>
) : null
}
</div>
)
}
......
......@@ -46,34 +46,34 @@
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #C1C1C1;
background-color: #c1c1c1;
}
.am-radio-inner:after{
.am-radio-inner:after {
display: block;
border-color: #FFF;
border-color: #fff;
top: 0;
right: 6px;
}
.am-radio.am-radio-checked .am-radio-inner{
background-color: #009AFF;
.am-radio.am-radio-checked .am-radio-inner {
background-color: #009aff;
border-radius: 50%;
width: 20px;
height: 20px;
}
.am-radio.am-radio-checked .am-radio-inner:after{
.am-radio.am-radio-checked .am-radio-inner:after {
display: block;
}
}
.pay-tip{
.pay-tip {
width: 100%;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 12px;
color: #FF3131;
background-color: #FFF4CE;
color: #ff3131;
background-color: #fff4ce;
}
.pay-button {
......@@ -89,6 +89,66 @@
z-index: 9;
}
.check-staging {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, $alpha: 0.6);
z-index: 19;
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
border-radius: 6px;
background-color: #FFF;
padding-bottom: 10px;
.check-title{
color: #333333;
font-size: 16px;
text-align: center;
width: 100%;
height: 44px;
line-height: 44px;
border-bottom: 1px solid #DDDDDD;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
}
.am-list-item .am-list-line .am-list-extra {
flex-basis: 16%;
}
.am-radio-inner {
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid #BFBFBF;
background-color: #fff;
}
.am-radio-inner:after {
display: block;
border-color: #fff;
top: 0;
right: 6px;
}
.am-radio.am-radio-checked .am-radio-inner {
background-color: #009aff;
border: 1px solid #FFF;
border-radius: 50%;
width: 20px;
height: 20px;
}
.am-radio.am-radio-checked .am-radio-inner:after {
display: block;
}
}
.order-info {
position: relative;
flex: 1;
......@@ -127,8 +187,8 @@
.v-list-item {
padding: 10px 15px;
background-color: #FFF;
border-bottom: 1px solid #E7EAF1;
background-color: #fff;
border-bottom: 1px solid #e7eaf1;
.content {
border: none;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment