Commit 7a741779 by wangshuo

订单支付接口

parent 7c4e868b
...@@ -4,6 +4,7 @@ import { OrderItem } from '@/common/index'; ...@@ -4,6 +4,7 @@ import { OrderItem } from '@/common/index';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { http, api } from "@/utils"; import { http, api } from "@/utils";
import { throttle } from 'lodash'; import { throttle } from 'lodash';
import {HeaderBar} from '../../common';
import "./order.scss" import "./order.scss"
...@@ -85,7 +86,7 @@ class Order extends Component { ...@@ -85,7 +86,7 @@ class Order extends Component {
if(res.data.code !== 200) { if(res.data.code !== 200) {
return; return;
} }
console.log(res); this.props.history.replace(`/payorder?oid=${res.data.data.oid}`);
}); });
} }
// 使用余额 // 使用余额
...@@ -172,14 +173,7 @@ class Order extends Component { ...@@ -172,14 +173,7 @@ class Order extends Component {
<div className="order-wrapper"> <div className="order-wrapper">
<Flex> <Flex>
<Flex.Item> <Flex.Item>
<NavBar <HeaderBar title='课程报名' arrow={true}></HeaderBar>
style={{ "height": "44px" }}
className="order-tab"
mode="light"
icon={<i className="iconfont iconiconfront-68"></i>}
>
课程报名
</NavBar>
{ {
!this.state.perfect && !this.state.perfect &&
<Link to='/orderinfo' className="order-information"> <Link to='/orderinfo' className="order-information">
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Flex, NavBar, List, InputItem, Button, WhiteSpace, WingBlank, Toast } from 'antd-mobile'; import { Flex, NavBar, List, InputItem, Button, WhiteSpace, WingBlank, Toast } from 'antd-mobile';
import { Formik, Field, Form, withFormik } from 'formik'; import { Formik, Field, Form, withFormik } from 'formik';
import {HeaderBar} from '../../common';
import { http, api } from "@/utils"; import { http, api } from "@/utils";
const InnerForm = ({ const InnerForm = ({
...@@ -55,25 +56,49 @@ const MyForm = withFormik({ ...@@ -55,25 +56,49 @@ const MyForm = withFormik({
values, values,
FormBag 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); Toast.info('请输入姓名!', undefined, undefined, false);
return; return;
} }
if (!values.cellphone) { if (!cellphone) {
Toast.info('请输入手机号!', undefined, undefined, false); Toast.info('请输入手机号!', undefined, undefined, false);
return; 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); Toast.info('请输入正确的手机号!', undefined, undefined, false);
return; return;
} }
if (!values.qq) { if (!qq) {
Toast.info('请输入QQ号!', undefined, undefined, false); Toast.info('请输入QQ号!', undefined, undefined, false);
return; return;
} else if (!/\d{5,}/g.test(values.qq)) { } else if (!/\d{5,}/g.test(qq)) {
Toast.info('请输入正确QQ号!', undefined, undefined, false); Toast.info('请输入正确QQ号!', undefined, undefined, false);
return; 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) { if(res.data.code !== 200) {
Toast.info(res.data.msg, undefined, undefined, false); Toast.info(res.data.msg, undefined, undefined, false);
return; return;
...@@ -95,14 +120,7 @@ class Orderinfo extends Component { ...@@ -95,14 +120,7 @@ class Orderinfo extends Component {
render() { render() {
return ( return (
<div> <div>
<NavBar <HeaderBar title='报名信息' arrow={true}></HeaderBar>
style={{ "height": "44px", backgroundColor: '#F7F9FC' }}
className="order-tab"
mode="light"
icon={<i className="iconfont iconiconfront-68"></i>}
>
报名信息
</NavBar>
<MyForm history={this.props.history} userInfo={this.props.location.state}/> <MyForm history={this.props.history} userInfo={this.props.location.state}/>
</div> </div>
) )
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Flex, WingBlank, WhiteSpace, List, Radio } from 'antd-mobile'; 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 { OrderItem, HeaderBar } from '@/common/index';
import {Link} from 'react-router-dom'; import { Link } from 'react-router-dom';
import './PayOrder.scss'; import './PayOrder.scss';
import {VList} from '@/common'; import { VList } from '@/common';
const Item = List.Item; const Item = List.Item;
const Brief = Item.Brief; const Brief = Item.Brief;
const RadioItem = Radio.RadioItem; const RadioItem = Radio.RadioItem;
let mockData = [ let mockData = [
{ value: 0, label: '支付宝', icon: 'iconzhifubaox-'}, { value: 0, label: '支付宝', icon: 'iconzhifubaox-' },
{ value: 1, label: '微信支付', icon: 'iconweixinzhifu'}, { value: 1, label: '微信支付', icon: 'iconweixinzhifu' },
{ value: 2, label: '花呗分期', icon: 'iconhuabei'}, // { 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
}
]
export default class PayOrder extends Component { export default class PayOrder extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
money: 1000.00, pay_amount: 0,
payType: 0, payType: 0,
stageNumber: 0,
checkPeriod: false, checkPeriod: false,
singleMoney: 0, singleMoney: 0,
periodNumber: 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) => { onChange = (value) => {
console.log(value);
this.setState({ this.setState({
payType: value, 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) => { print = (...e) => {
console.log(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() { 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); console.log(res);
if (res.data.code !== 200) { if (res.data.code !== 200) {
return; return;
} }
const { course, total_sale, user_account, user_info, discount } = res.data.data; const { course, pay_amount } = res.data.data;
// this.setState({ const fenqiList = [];
// perfect: user_info, [1, 2, 3].map((item)=>{
// orderList: course, let obj = {};
// user_account, obj.value = item;
// total_sale, if(item === 1) {
// discount, 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() { render() {
const { money, payType, checkPeriod, singleMoney, periodNumber } = this.state; const { orderId, pay_amount, payType, checkPeriod, singleMoney, periodNumber, huabei, fenqiList, categoryList, stageNumber } = this.state;
return ( return (
<div className='pay-order'> <div className='pay-order'>
<HeaderBar title='确认支付' arrow={true}></HeaderBar> <HeaderBar title='确认支付' arrow={true}></HeaderBar>
...@@ -88,13 +229,13 @@ export default class PayOrder extends Component { ...@@ -88,13 +229,13 @@ export default class PayOrder extends Component {
<WingBlank> <WingBlank>
<Flex justify='between' align='center' style={{ height: '44px' }}> <Flex justify='between' align='center' style={{ height: '44px' }}>
<span>订单号</span> <span>订单号</span>
<span className='number'>20160815850565</span> <span className='number'>{orderId}</span>
</Flex> </Flex>
</WingBlank> </WingBlank>
</div> </div>
<WhiteSpace size='md'></WhiteSpace> <WhiteSpace size='md'></WhiteSpace>
{ {
mockList.map((item, index) => { categoryList.map((item, index) => {
const Info = ( const Info = (
<div className="order-info"> <div className="order-info">
<p className='order-title text-overflow-one'> <p className='order-title text-overflow-one'>
...@@ -119,7 +260,7 @@ export default class PayOrder extends Component { ...@@ -119,7 +260,7 @@ export default class PayOrder extends Component {
<WingBlank> <WingBlank>
<Flex justify='between' align='center' style={{ height: '44px' }}> <Flex justify='between' align='center' style={{ height: '44px' }}>
<span>支付金额</span> <span>支付金额</span>
<span className='money'>{`¥${money}`}</span> <span className='money'>{`¥${pay_amount}`}</span>
</Flex> </Flex>
</WingBlank> </WingBlank>
</div> </div>
...@@ -135,17 +276,17 @@ export default class PayOrder extends Component { ...@@ -135,17 +276,17 @@ export default class PayOrder extends Component {
{/* {i.label} */} {/* {i.label} */}
{ {
i.value === 2 ? ( i.value === 2 ? (
<Flex direction='column' align='start' style={{width: '100%', marginTop: '6px'}}> <Flex direction='column' align='start' style={{ width: '100%', marginTop: '6px' }}>
<Flex direction='row' justify='between' style={{width: '100%', paddingRight: '30px'}}> <Flex direction='row' justify='between' style={{ width: '100%', paddingRight: '30px' }}>
<span style={{color: '#555555', fontSize: '14px'}}>{i.label}</span> <span style={{ color: '#555555', fontSize: '14px' }}>{i.label}</span>
{ {
checkPeriod ? ( checkPeriod ? (
<span style={{color: '#333333', fontSize: '12px'}}>{`${singleMoney}元 × ${periodNumber}期`}</span> <span style={{ color: '#333333', fontSize: '12px' }}>{`${singleMoney}元 × ${periodNumber}期`}</span>
) : null ) : null
} }
</Flex> </Flex>
<Flex justify='start'> <Flex justify='start'>
<span style={{color: '#999999', fontSize: '12px'}}>支付上限受限于您的花呗额度</span> <span style={{ color: '#999999', fontSize: '12px' }}>支付上限受限于您的花呗额度</span>
</Flex> </Flex>
</Flex> </Flex>
) : (i.label) ) : (i.label)
...@@ -155,7 +296,26 @@ export default class PayOrder extends Component { ...@@ -155,7 +296,26 @@ export default class PayOrder extends Component {
</List> </List>
<div className='pay-tip'>请在24小时内完成支付,否则届时系统将关闭该订单。</div> <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> </div>
) )
} }
......
...@@ -46,34 +46,34 @@ ...@@ -46,34 +46,34 @@
width: 20px; width: 20px;
height: 20px; height: 20px;
border-radius: 50%; border-radius: 50%;
background-color: #C1C1C1; background-color: #c1c1c1;
} }
.am-radio-inner:after{ .am-radio-inner:after {
display: block; display: block;
border-color: #FFF; border-color: #fff;
top: 0; top: 0;
right: 6px; right: 6px;
} }
.am-radio.am-radio-checked .am-radio-inner{ .am-radio.am-radio-checked .am-radio-inner {
background-color: #009AFF; background-color: #009aff;
border-radius: 50%; border-radius: 50%;
width: 20px; width: 20px;
height: 20px; height: 20px;
} }
.am-radio.am-radio-checked .am-radio-inner:after{ .am-radio.am-radio-checked .am-radio-inner:after {
display: block; display: block;
} }
} }
.pay-tip{ .pay-tip {
width: 100%; width: 100%;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
text-align: center; text-align: center;
font-size: 12px; font-size: 12px;
color: #FF3131; color: #ff3131;
background-color: #FFF4CE; background-color: #fff4ce;
} }
.pay-button { .pay-button {
...@@ -89,6 +89,66 @@ ...@@ -89,6 +89,66 @@
z-index: 9; 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 { .order-info {
position: relative; position: relative;
flex: 1; flex: 1;
...@@ -127,8 +187,8 @@ ...@@ -127,8 +187,8 @@
.v-list-item { .v-list-item {
padding: 10px 15px; padding: 10px 15px;
background-color: #FFF; background-color: #fff;
border-bottom: 1px solid #E7EAF1; border-bottom: 1px solid #e7eaf1;
.content { .content {
border: none; 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