import React, { Component } from "react" import { Checkbox, Flex, List, Radio, Toast, WhiteSpace, WingBlank, } from "antd-mobile" import { browser, getParam, http } from "src/utils" import { HeaderBar } from "src/common/index" import VlistBase from "src/common/v-list-base" import "./index.scss" import { WithFullSize } from "src/HOCs" import { Link } from "react-router-dom" const RadioItem = Radio.RadioItem const Item = Flex.Item function OrderList({ courses, toggleSelectedCourse }) { return ( <Flex wrap={"wrap"}> {courses.length && courses.map((course) => { const { image_name: img, course_id, coupon_desc, coupon_num } = course const info = ( <div className="info"> <div className="title">{course.course_title}</div> <div className="des"> <div className={"deposit-discount"}> 定金折扣: <span className={"price"}>-¥{course.deduction_amount}</span> </div> { // eslint-disable-next-line eqeqeq course.coupon_amount != 0 && ( <div className={"coupon-amount"}> 使用优惠券: <span className={"price"}>-¥{course.coupon_amount}</span> </div> ) } </div> <div className="prices"> <span className={"sale-price price"}>¥{course.sale_price}</span> <span className={"former-price"}>¥{course.price1}</span> </div> </div> ) return ( <React.Fragment key={course.course_id}> <Item className={"order-item"}> <Flex className="select-bar" justify={"between"}> <Item> <Checkbox defaultChecked onChange={() => { toggleSelectedCourse(course) }} /> </Item> <Item className={"final-payment-hint"}>待付尾款</Item> </Flex> <VlistBase img={img} handleClick={() => {}} info={info} /> </Item> <div className="order-prefer"> <List key={course_id}> <List.Item arrow="horizontal" onClick={() => {}}> <Link to={{ pathname: `/coupons`, search: `?id=${course_id}`, state: { from: "/order", }, }} > <Flex justify="between"> <span style={{ color: "#333", fontSize: "15px", }} > 优惠券 </span> <span style={{ fontSize: "14px", color: "#999999", }} > {!coupon_desc ? coupon_num === 0 ? "无" : `${coupon_num}张可用` : coupon_desc} </span> </Flex> </Link> </List.Item> </List> </div> </React.Fragment> ) })} </Flex> ) } let mockData if (browser.isWeixin) { mockData = [{ value: 1, label: "微信支付", icon: "iconweixinzhifu" }] } else { mockData = [ { value: 1, label: "微信支付", icon: "iconweixinzhifu" }, { value: 0, label: "支付宝", icon: "iconalipay" }, ] } class FinalDepositOrder extends Component { constructor(props) { super(props) this.state = { pay_amount: 0, payType: 1, stageNumber: 0, orderId: getParam("oid"), categoryList: [], selectedCourses: [], salePrice: "", user_account: "", useBalance: false, info: false, order_id: "", moneyOffRules: [], finalEndTime: "", offset: 0, appliedMoneyOffRule: {}, } } onChange = (value) => { this.setState({ payType: value, checkPeriod: false, }) if (value === 2) { this.setState({ huabei: true, }) } } // 确定购买 pay = () => { const { payType, order_id } = this.state if (payType === 0) { this.alipayPay(order_id) } else if (payType === 1) { this.weixinPay(order_id) } } //提交 submit = () => { this.createOrder().then((res) => { if (res.data.errno === 200) { this.setState( { order_id: res.data.data.order_id, }, () => { if (res.data.data.pay_jump === 1) { this.props.history.push("/purchased") } else { this.pay() } } ) } else { Toast.info(res.data.msg) } }) } //创建订单 createOrder = () => { const { selectedCourses, salePrice, useBalance, appliedMoneyOffRule, } = this.state return http.post(`${API["base-api"]}/m/deposit/final/create`, { course_ids: selectedCourses.map((item) => item.course_id), cut_amount: appliedMoneyOffRule.cut_amount || 0, pay_amount: salePrice, is_deduction: useBalance ? 1 : 0, deduction_amount: useBalance ? this.getBalanceOffset() : 0, plat_form: 5, source: getParam("source"), }) } // 微信支付 weixinPay = (orderId) => { // 微信内部-支付 if (browser.isWeixin) { 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["base-api"]}/pay/wxpay/wap_charge/oid/${orderId}`) .then((res) => { 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 _this = this let weixin_code = getParam("code") if (weixin_code) { if (getParam("oid") !== undefined) { http .get( `${API["base-api"]}/pay/wxpay/pub_charge/oid/${getParam( "oid" )}/code/${weixin_code}` ) .then((res) => { if (res.data.errno === 0) { let data = res.data.data function onBridgeReady() { /* eslint-disable-next-line no-undef */ 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") { Toast.info("支付成功", 2) _this.intervalPayStatus = setInterval(function () { http .get( `${API["base-api"]}/m/orderState/oid/${getParam( "oid" )}` ) .then((res) => { if (res.data.errno === 401) { clearInterval(_this.intervalPayStatus) _this.intervalPayStatus = null _this.props.history.replace( `/expand/callback?order_id=${getParam("oid")}` ) } }) }, 1000) } else { alert("支付失败") } } ) } if (typeof WeixinJSBridge == "undefined") { if (document.addEventListener) { document.addEventListener( "WeixinJSBridgeReady", onBridgeReady, false ) } else if (document.attachEvent) { document.attachEvent("WeixinJSBridgeReady", onBridgeReady) document.attachEvent("onWeixinJSBridgeReady", onBridgeReady) } } else { onBridgeReady() } } else { Toast.info(res.data.msg, 2) } }) } } } // 支付完成之后获取状态 payCallback = () => { const _this = this // 支付回调 // 定时器轮训获取订单状态 _this.intervalPayStatus = setInterval(function () { http .get(`${API["base-api"]}/m/orderState/oid/${getParam("oid")}`) .then((res) => { if (res.data.errno === 401) { clearInterval(_this.intervalPayStatus) _this.intervalPayStatus = null window.location.href = "/expand/callback?order_id=" + getParam("oid") } }) }, 1000) } // 支付宝支付 alipayPay = (orderId) => { http .get(`${API["base-api"]}/pay/alipay/wap_charge_new/oid/${orderId}`) .then((res) => { if (res.data.errno === 0) { this.payCallback() window.location = res.data.data.url } else { Toast.info(res.data.msg, 2) } }) } componentDidMount() { if (getParam("weixinpay")) { this.payCallback() } if (browser.isWeixin) { this.isweixinPay(getParam("oid")) } http.get(`${API["base-api"]}/m/deposit/final/preorder`).then((res) => { const { data } = res if (data.errno === 200) { this.setState({ categoryList: [...data.data.courses], salePrice: this.getTotalPrice({ courses: [...data.data.courses], moneyOffRules: data.data["full_rule"], }), selectedCourses: [...data.data.courses], user_account: data.data.user_account, moneyOffRules: data.data["full_rule"], finalEndTime: data.data["final_end_time"], }) } else { Toast.info(data.msg) } }) } // 展示余额抵扣规则 showInfo = () => { this.setState((prevState) => ({ info: !prevState.info, })) } toggleSelectedCourse = (course) => { this.setState((prevState) => { const { selectedCourses } = prevState let index = prevState.selectedCourses.findIndex( (item) => item.course_id === course.course_id ) if (index === -1) { selectedCourses.push(course) } else { selectedCourses.splice(index, 1) } let totalPrice = this.getTotalPrice(selectedCourses) return { selectedCourses, salePrice: totalPrice, offset: this.getBalanceOffset(totalPrice), } }) } //获取支付价格 getTotalPrice = ({ courses = this.state.selectedCourses, useBalance = this.state.useBalance, moneyOffRules = this.state.moneyOffRules, } = {}) => { let totalPrice = this.getOriginTotalPrice({ courses }) totalPrice = this.moneyOff(totalPrice, moneyOffRules) if (useBalance) { totalPrice -= parseFloat(this.state.user_account) } return totalPrice < 0 ? 0 : totalPrice.toFixed(2) } //满减计算 moneyOff = (totalPrice, moneyOffRules = this.state.moneyOffRules) => { let rules = moneyOffRules.sort((a, b) => b.full_amount - a.full_amount) let result = parseFloat(totalPrice) for (let i = 0; i < rules.length; i++) { let rule = rules[i] if (result >= rule.full_amount) { this.setState({ appliedMoneyOffRule: rule, }) return result - parseFloat(rule.cut_amount) } } return result } //使用余额 useBalance = () => { this.setState((prevState) => { const useBalance = !prevState.useBalance let totalPrice = this.getTotalPrice({ useBalance }) return { useBalance, salePrice: totalPrice, offset: this.getBalanceOffset(totalPrice), } }) } getOriginTotalPrice = ({ courses = this.state.selectedCourses } = {}) => { return courses.reduce((accu, item) => { return accu + parseFloat(item["sale_price"]) }, 0) } getBalanceOffset = () => { let originalTotalPrice = this.getOriginTotalPrice() let currentPrice = this.moneyOff(originalTotalPrice) let offset = parseFloat(this.state.user_account) - parseFloat(currentPrice) offset = offset >= 0 ? currentPrice : this.state.user_account return offset } render() { const { salePrice, payType, categoryList, user_account, useBalance, info, finalEndTime, offset, appliedMoneyOffRule, } = this.state return ( <div className="deposit-pay-order"> <HeaderBar title="课程报名" arrow={true}></HeaderBar> <WhiteSpace size="sm" /> {/*<div className='order-number'> <WingBlank> <Flex justify='between' align='center' style={{height: '44px'}}> <span>订单号</span> <span className='number'>{orderId}</span> </Flex> </WingBlank> </div>*/} <WhiteSpace size="md" /> <div className={"order-list"}> <OrderList courses={categoryList} toggleSelectedCourse={this.toggleSelectedCourse} /> </div> <div className="order-balance"> <List> <Item className="order-prefer-text"> <Flex justify="between"> <Flex align="center"> <span>余额抵扣</span> <span className="order-balanceprice"> (余额: <i className="order-money">{`${user_account}元`}</i>) </span> <i className="iconfont iconiconfront-22 question-mark" onClick={this.showInfo} ></i> </Flex> <Flex> {useBalance ? ( <> <span style={{ color: "#FF2121", fontSize: "15px", marginRight: "6px", }} >{`-¥${offset}`}</span> <i className={`iconfont icondanseshixintubiao-5 balance-used`} onClick={this.useBalance} /> </> ) : ( <i className="circle-icon" onClick={this.useBalance}></i> )} </Flex> </Flex> </Item> </List> </div> <WhiteSpace size="md"></WhiteSpace> <div className="order-number"> <WingBlank> <Flex justify="between" align="center" style={{ height: "44px" }}> <span>支付金额</span> <span className="money">{`¥${salePrice}`}</span> </Flex> </WingBlank> </div> <WhiteSpace /> {appliedMoneyOffRule.full_amount && ( <div className="money-off"> <WingBlank> <Flex justify="end" align="center" style={{ height: "44px" }}> <span> 满{appliedMoneyOffRule.full_amount}减 {appliedMoneyOffRule.cut_amount}: </span> <span className="money">{`-¥${appliedMoneyOffRule.cut_amount}`}</span> </Flex> </WingBlank> </div> )} <WhiteSpace size="md"></WhiteSpace> <List renderHeader={() => "支付方式"} className="pay-type-list"> {mockData.map((i) => ( <RadioItem thumb={ <i className={`iconfont ${i.icon} ${ payType === i.value ? "checked" : "" }`} ></i> } key={i.value} checked={payType === i.value} onChange={() => this.onChange(i.value)} > {i.label} </RadioItem> ))} </List> <div className="pay-tip">{`${finalEndTime}结束支付尾款`}</div> <div className="pay-button" onClick={this.submit}> 确认支付 </div> {info ? ( <div style={{ position: "fixed", top: 0, left: 0, width: "100%", height: "100%", backgroundColor: "rgba(0, 0, 0, 0.8)", zIndex: "99", }} > <div style={{ padding: "20px", backgroundColor: "#FFF", width: "300px", height: "170px", margin: "0 auto", position: "absolute", left: "50%", top: "50%", transform: "translate(-50%, -50%)", }} > <Flex direction="column" justify="between" align="center" style={{ height: "100%" }} > <p style={{ fontSize: "16px", color: "#333333" }}> 余额抵扣说明 </p> <p style={{ lineHeight: "20px", fontSize: "13px", color: "#666666", }} > 分销课程或者参与七月在线的相关活动,可获得资金奖励。账户资金可直接提现,也可抵扣课程费用。 </p> <div onClick={this.showInfo} style={{ width: "260px", height: "30px", lineHeight: "30px", textAlign: "center", borderRadius: "3px", border: "1px solid #0099FF", color: "#0099FF", fontSize: "15px", }} > 知道了 </div> </Flex> </div> </div> ) : null} </div> ) } } export default WithFullSize(FinalDepositOrder)