Kaynağa Gözat

支付宝网页支付

WuJunFeng 4 yıl önce
ebeveyn
işleme
c56d870899

+ 7 - 1
.umirc.js

@@ -10,6 +10,11 @@ export default {
       name: '支付',
       routes: [
         {
+          path: '/recharge/home', 
+          name: '支付',
+          component: '../pages/Recharge/Recharge'
+        },
+        {
           path: '/recharge/callback', 
           name: '回调页面',
           routes: [
@@ -22,6 +27,7 @@ export default {
         }
       ]
     },
+    { path: '/', redirect: '/recharge/home' },
     {
       path: '/',
       component: '../layouts/BlankLayout',
@@ -33,7 +39,7 @@ export default {
   plugins: [
     // ref: https://umijs.org/plugin/umi-plugin-react.html
     ['umi-plugin-react', {
-      antd: false,
+      antd: true,
       dva: false,
       dynamicImport: false, // { webpackChunkName: true },
       title: 'xk-umi',

BIN
public/banner-bg.png


BIN
src/assets/icon_coner.png


BIN
src/assets/icon_default_avatar.png


BIN
src/assets/icon_gold.png


+ 3 - 0
src/global.css

@@ -16,3 +16,6 @@ body {
 a {
   text-decoration: none;
 }
+a:hover {
+  color: inherit;
+}

+ 8 - 1
src/pages/AlipayCallback/AlipayCallback.jsx

@@ -3,11 +3,18 @@
  * 支付宝支付成功回调页面
  */
 import React, { Component } from 'react'
+import styles from './AlipayCallback.less'
+
 class AlipayCallback extends Component {
+  componentDidMount() {
+    const { out_trade_no, total_amount } = this.props.location.query
+    location.href = '/recharge/home?res=1' + '&no=' + out_trade_no + '&amount=' + total_amount
+  }
+
   render () {
     return (
       <div>
-        kdleels
+        <h3 className={styles['pay-success']}>正在获取支付结果...</h3>
       </div>
     )
   }

+ 5 - 0
src/pages/AlipayCallback/AlipayCallback.less

@@ -0,0 +1,5 @@
+.pay-success {
+  text-align: center;
+  padding: 40px;
+  font-size: 30px;
+}

+ 59 - 0
src/pages/Recharge/Login.jsx

@@ -0,0 +1,59 @@
+import React, { Component } from 'react'
+import { Modal, Input, notification } from 'antd'
+import styles from './Login.less'
+import { getUserByUserNoOrNiceNo } from '@/services/common'
+
+class Login extends Component {
+  constructor (props) {
+    super(props)
+    this.state = {
+      userNo: ''
+    }
+  }
+  onLogin = async (e) => {
+    e.preventDefault()
+    const { userNo } = this.state
+    if (!userNo) {
+      return
+    }
+    const { code, data } = await getUserByUserNoOrNiceNo({ params: userNo })
+    if (code === 'OK' && data) {
+      const { onOk } = this.props 
+      onOk && onOk(data)
+    } else {
+      notification.error({ message: '用户不存在' })
+    }
+  }
+
+  onUserNoChange = (e) => {
+    const { value } = e.target
+    this.setState({ userNo: value })
+  }
+  render () {
+    const { userNo } = this.state
+    return (
+      <Modal 
+        {...this.props}
+        footer={null}
+        width={700}
+        title='登录'
+      >
+        <div>
+          <h3 className={styles['modal-title']}>请登录您的星芽账号</h3>
+          <p className={styles['input-title']}>请输入您的星芽ID或靓号ID</p>
+          <div className={styles['input-wrap']}>
+            <Input 
+              placeholder='请输入您的星芽ID或靓号ID'
+              value={userNo}
+              onChange={this.onUserNoChange}
+            />
+          </div>
+          <div className={styles['recharge-btn-wrap']}>
+            <a href="#" onClick={this.onLogin} className={styles['recharge-btn']}>登录</a>
+          </div>
+        </div>
+      </Modal>
+    )
+  }
+}
+export default Login

+ 34 - 0
src/pages/Recharge/Login.less

@@ -0,0 +1,34 @@
+.modal-title {
+  color: #303133;
+  font-size: 34px;
+  margin-bottom: 14px;
+}
+.input-title {
+  margin-bottom: 80px;
+  color: #606266;
+  font-size: 24px;
+}
+.input-wrap {
+  margin-bottom: 42px;
+}
+:global(.ant-modal-body) {
+  padding: 40px 66px;
+}
+
+.recharge-btn-wrap {
+  padding: 20px 0;
+}
+.recharge-btn {
+  display: block;
+  width: 220px;
+  height: 46px;
+  background: linear-gradient(90deg, #FF7559 0%, #FF4D79 100%);
+  border-radius: 23px;
+
+  font-size: 22px;
+  font-weight: 500;
+  color: #FFFFFF;
+  line-height: 46px;
+  text-align: center;
+  margin: 0 auto;
+}

+ 180 - 0
src/pages/Recharge/Recharge.jsx

@@ -0,0 +1,180 @@
+import React, { Component } from 'react'
+import { getCoinRechargeItemsGuest, addCoinRechargeOrderGuest, addPayOrderGuest } from '@/services/common'
+import styles from './Recharge.less'
+import iconGold from '@/assets/icon_gold.png'
+import iconDefaultAvatar from '@/assets/icon_default_avatar.png'
+import { notification, Modal } from 'antd'
+import Login from './Login'
+
+class Recharge extends Component {
+  constructor (props) {
+    super(props)
+    this.state = {
+      choosenItem: {},
+      visible: false,
+      userInfo: {},
+    }
+  }
+  componentDidMount () {
+    const userString = localStorage.userInfo
+    const { no, amount, res } = this.props.location.query
+    if (userString) {
+      const json = JSON.parse(userString)
+      this.setState({ userInfo: json })
+    }
+    
+    if (res === '1') {
+      notification.success({
+        message: '充值成功',
+        description: <div><p>订单号: {no}</p><p>支付金额: {amount}</p> </div>,
+        duration: 0
+      })
+    }
+    this.getCoinRechargeItemsGuest()
+  }
+
+  // 获取充值项目
+  getCoinRechargeItemsGuest = async () => {
+    const _state = {}
+    try {
+      const { code, data } = await getCoinRechargeItemsGuest()
+      if (code === 'OK' && data) {
+        const { list } = data
+        const payAliPc = list && list.find(item => item.payWay === 204)
+        _state.payAliPc = (payAliPc && payAliPc.items) || []
+      } 
+    } catch (e) {
+      console.log(e)
+    }
+    this.setState(_state)
+  }
+
+  onChoose = (item) => () => {
+    this.setState({ choosenItem: item })
+  }
+
+  // 充值
+  onRecharge = async (e) => {
+    e.preventDefault()
+    const { choosenItem, userInfo } = this.state
+    if (!choosenItem || !choosenItem.itemId) {
+      notification.error({message: '请选择充值金额'})
+      return
+    }
+    if (!userInfo || !userInfo.userId) {
+      notification.error({ message: '请先登录' })
+      return
+    }
+    if (this.state.uploading) {
+      return
+    }
+    this.setState({ uploading: true })
+    // 创建金币充值订单
+    const { code, data } = await addCoinRechargeOrderGuest({
+      itemId: choosenItem.itemId, userId: userInfo.userId
+    })
+    if (code === 'OK' && data) {
+      const { orderId } = data
+      this.addPayOrderGuest(orderId)
+    }
+  }
+  addPayOrderGuest = async (orderId) => {
+    const { code, data } = await addPayOrderGuest({ orderId })
+    if (code === 'OK' && data) {
+      const { payParams } = data
+      const node = document.createElement('div')
+      node.innerHTML = payParams
+      document.body.appendChild(node)
+      
+      if (document.forms[0]) {
+        document.forms[0].submit();
+      }
+      
+    }
+    this.setState({ uploading: false })
+  }
+
+  // 登录
+  onLogin = () => {
+    this.setState({ visible: true })
+  }
+  onModalCancel = () => {
+    this.setState({ visible: false })
+  }
+
+  // 登录成功
+  onLoginOk = (data) => {
+    localStorage.userInfo = JSON.stringify(data)
+    this.setState({ visible: false, userInfo: data })
+  }
+  render () {
+    const { payAliPc, choosenItem, visible, userInfo, uploading, payParams } = this.state
+    return (
+      <div className={styles['wrap']}>
+        <div className={styles['header-wrap']}>
+          <div className={styles['user-default-info']} onClick={this.onLogin} hidden={userInfo && userInfo.userId}>
+            <img src={iconDefaultAvatar} alt=""/>
+            <span>登录</span>
+          </div>
+          <div className={styles['user-info']} hidden={!userInfo || !userInfo.userId}>
+            <img src={userInfo.userAvatar} alt=""/>
+            <div className={styles['user-name']}>
+              <h4>{userInfo.userName}</h4>
+              <p>ID:{userInfo.userId}</p>
+            </div>
+          </div>
+        </div>
+        <div className={styles['content-wrap']}>
+          <div className={styles['banner-bg']}></div>
+          <div className={styles['main-content-wrap']}>
+            <div className={styles['list-wrap']}>
+              {
+                payAliPc && payAliPc.map((item) => (
+                  <div 
+                    key={item.itemId} 
+                    className={styles['list-item-wrap']}
+                  >
+                    <div 
+                      className={
+                        `${styles['list-item']} ${choosenItem && choosenItem.itemId === item.itemId ? styles['list-item-active'] : ''}`
+                      } 
+                      onClick={this.onChoose(item)}
+                    >
+                      <div className={styles['item-top']}>
+                        <img src={iconGold} alt=""/>
+                        <span>{item.itemCoin}</span>
+                      </div>
+                      
+                      <div className={styles['item-price']}>¥ {item.itemPrice}</div>
+                    </div>
+                  </div>
+                ))
+              }
+            </div>
+
+            <div className={styles['recharge-btn-wrap']}>
+              <a 
+                href="#" 
+                className={`${styles['recharge-btn']} ${uploading?styles['recharge-btn-loading']:''}`} 
+                onClick={this.onRecharge}
+              >充值</a>
+            </div>
+          </div>
+        </div>
+        <Login 
+          visible={visible}
+          onCancel={this.onModalCancel}
+          onOk={this.onLoginOk}
+        />
+        {/* <Modal
+          footer={false}
+          visible={!!payParams}
+          width={700}
+        >
+          <div dangerouslySetInnerHTML={{__html: payParams}} />
+        </Modal> */}
+      </div>
+    )
+  }
+}
+export default Recharge

+ 145 - 0
src/pages/Recharge/Recharge.less

@@ -0,0 +1,145 @@
+.wrap {
+  height: 100vh;
+}
+
+.header-wrap {
+  height: 112px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 1200px;
+  margin: 0 auto;
+}
+
+.user-info {
+  display: flex;
+  align-items: center;
+
+  & > img {
+    width: 70px;
+    height: 70px;
+    display: block;
+    border-radius: 50%;
+  }
+  & > span {
+    color: #303133;
+    font-size: 30px;
+    margin-left: 10px;
+  }
+
+  .user-name {
+    margin-left: 10px;
+  }
+}
+.user-default-info {
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+
+  & > img {
+    width: 70px;
+    height: 70px;
+    display: block;
+    border-radius: 50%;
+  }
+  & > span {
+    color: #303133;
+    font-size: 30px;
+    margin-left: 10px;
+  }
+}
+
+.content-wrap {
+  position: relative;
+  background: #F9FAFB;
+  height: calc(100% - 112px);
+}
+
+.banner-bg {
+  height: 660px;
+  max-width: 1920px;
+  min-width: 1260px;
+  margin: 0 auto;
+  background: url(/banner-bg.png) no-repeat center;
+  background-size: 100% 100%;
+}
+
+.main-content-wrap {
+  position: absolute;
+  width: 1200px;
+  min-height: 600px;
+  top: 200px;
+  left: 50%;
+  transform: translate(-50%, 0);
+  background: #fff;
+  box-shadow: 0px 2px 6px 2px rgba(241, 241, 241, 0.5);
+  border-radius: 8px;
+}
+.list-wrap {
+  display: flex;
+  justify-content: flex-start;
+  flex-wrap: wrap;
+  padding: 50px 20px 0;
+
+  .list-item-wrap {
+    width: 25%;
+    padding: 0 20px;
+    box-sizing: border-box;
+    margin-bottom: 40px 
+  }
+  .list-item {
+    padding: 30px 20px;
+    background: #FFFFFF;
+    
+    border-radius: 6px;
+    border: 2px solid #E6E6E6;
+    cursor: pointer;
+  }
+  .item-top {
+    border-bottom: 1px dashed #CACACA;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    color: #E85F68;
+    font-size: 26px;
+    padding-bottom: 14px;
+    margin-bottom: 14px;
+  }
+  .item-top img {
+    width: 24px;
+    height: 24px;
+    display: block;
+    margin-right: 10px;
+  }
+  .list-item-active {
+    border-color: #E85F68;
+    box-shadow: 0px 0px 4px 1px rgba(232, 95, 104, 0.28);
+  }
+  .item-price {
+    color: #606266;
+    font-size: 22px;
+    text-align: center;
+  }
+}
+
+.recharge-btn-wrap {
+  padding: 20px 0;
+}
+.recharge-btn {
+  display: block;
+  width: 220px;
+  height: 46px;
+  background: linear-gradient(90deg, #FF7559 0%, #FF4D79 100%);
+  border-radius: 23px;
+
+  font-size: 22px;
+  font-weight: 500;
+  color: #FFFFFF;
+  line-height: 46px;
+  text-align: center;
+  margin: 0 auto;
+}
+
+.recharge-btn-loading {
+  opacity: 0.3;
+}

+ 26 - 0
src/services/common.js

@@ -5,3 +5,29 @@ import request from '@/utils/request';
 export async function getCurrentTime() {
   return request('/api-common/v1/data/getCurrentTime')
 }
+
+//查询用户
+export async function getUserByUserNoOrNiceNo(params) {
+  return request(`/api-app/v1/user/getUserByUserNoOrNiceNo?${stringify(params)}`);
+}
+
+// 创建金币充值订单
+export async function addCoinRechargeOrderGuest(params) {
+  return request('/api-app/v1/recharge/addCoinRechargeOrderGuest', {
+    method: 'POST',
+    body: params,
+  });
+}
+
+// 创建支付订单
+export async function addPayOrderGuest(params) {
+  return request('/api-app/v1/pay/addPayOrderGuest', {
+    method: 'POST',
+    body: params,
+  });
+}
+
+// 获取金币充值项目
+export async function getCoinRechargeItemsGuest(params) {
+  return request(`/api-app/v1/recharge/getCoinRechargeItemsGuest?${stringify(params)}`);
+}

+ 1 - 1
src/utils/request.js

@@ -68,7 +68,7 @@ const getHeader = () => {
     a: 11,
     av: '1.0.0',
     c: 4,
-    ci: '0',
+    ci: '1',
     di: '1a00bf0e978c458f7620b390714b26cc',
     lat: '',
     lng: '',