lex-xin пре 5 година
родитељ
комит
74678bd1f7

+ 10 - 0
package-lock.json

@@ -4208,6 +4208,11 @@
         "assert-plus": "^1.0.0"
       }
     },
+    "dayjs": {
+      "version": "1.8.29",
+      "resolved": "https://registry.npm.taobao.org/dayjs/download/dayjs-1.8.29.tgz?cache=0&sync_timestamp=1593704541274&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdayjs%2Fdownload%2Fdayjs-1.8.29.tgz",
+      "integrity": "sha1-XSPjQd5r+9IGwBE20vsPAYd4IPU="
+    },
     "de-indent": {
       "version": "1.0.2",
       "resolved": "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz",
@@ -12026,6 +12031,11 @@
         "vue-style-loader": "^4.1.0"
       }
     },
+    "vue-qr": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npm.taobao.org/vue-qr/download/vue-qr-2.2.1.tgz",
+      "integrity": "sha1-14ROddUiPvKrGSUjz4uxKdO4JIk="
+    },
     "vue-router": {
       "version": "3.3.2",
       "resolved": "https://registry.npm.taobao.org/vue-router/download/vue-router-3.3.2.tgz?cache=0&sync_timestamp=1590759571191&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-router%2Fdownload%2Fvue-router-3.3.2.tgz",

+ 2 - 0
package.json

@@ -11,6 +11,7 @@
     "browserslist": "^4.8.6",
     "caniuse-lite": "^1.0.30001027",
     "core-js": "^2.6.5",
+    "dayjs": "^1.8.29",
     "es6-promise": "^4.2.8",
     "install": "^0.13.0",
     "lodash": "^4.17.15",
@@ -20,6 +21,7 @@
     "vconsole": "^3.3.4",
     "vue": "^2.6.10",
     "vue-awesome-swiper": "^3.1.3",
+    "vue-qr": "^2.2.1",
     "vue-router": "^3.0.3",
     "vuex": "^3.0.1"
   },

+ 5 - 1
public/index.html

@@ -18,7 +18,11 @@
 
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
     <title>酷乐秀</title>
-    <style>html{color:#000;overflow-y:scroll;overflow-x:hidden;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;font-size:100px;-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch}.link,.link:hover,.link:visited,a{color:#333}body,html{font-family:"PingFang SC","Heiti SC","SF UI Text","Helvetica Neue",Roboto,"Droid Sans Fallback",arial,sans-serif;font-weight:normal}body{font-size:.12rem;line-height:1.5}*{margin:0;padding:0;outline:0;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:transparent}input,select,textarea{font-size:100%}table{border-collapse:collapse;border-spacing:0}img{border:0}del{text-decoration:line-through}.link:active,a{text-decoration:none}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-weight:500}h1{font-size:.36rem}h2{font-size:.28rem}h3{font-size:.24rem}h4{font-size:.2rem;line-height:.26rem}h5{font-size:.18rem;line-height:.24rem}h6{font-size:.16rem;line-height:.2rem}q:after,q:before{content:''}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}.link:active{color:#e61414}ins,u{text-decoration:underline;text-decoration-color:#eee}</style>
+    <style>html{color:#000;overflow-y:scroll;overflow-x:hidden;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;font-size:100px;-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch}.link,.link:hover,.link:visited,a{color:#333}body,html{font-family:"PingFang SC","Heiti SC","SF UI Text","Helvetica Neue",Roboto,"Droid Sans Fallback",arial,sans-serif;font-weight:normal}body{font-size:.12rem;line-height:1.5}*{margin:0;padding:0;outline:0;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:transparent}input,select,textarea{font-size:100%}table{border-collapse:collapse;border-spacing:0}img{border:0}del{text-decoration:line-through}.link:active,a{text-decoration:none}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-weight:500}h1{font-size:.36rem}h2{font-size:.28rem}h3{font-size:.24rem}h4{font-size:.2rem;line-height:.26rem}h5{font-size:.18rem;line-height:.24rem}h6{font-size:.16rem;line-height:.2rem}q:after,q:before{content:''}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}.link:active{color:#e61414}ins,u{text-decoration:underline;text-decoration-color:#eee}
+    @media screen and (max-width: 700px) {
+      body{ font-size: 16px !important; }
+    }
+    </style>
 
     <!-- <link rel="stylesheet" href="https://www.unpkg.com/vant@2.8.4/lib/index.css"> -->
     <script>!function(e,t){var n=t.documentElement,d=e.devicePixelRatio||1;function i(){var e=n.clientWidth/3.75;n.style.fontSize=e+"px"}if(function e(){t.body?t.body.style.fontSize="16px":t.addEventListener("DOMContentLoaded",e)}(),i(),e.addEventListener("resize",i),e.addEventListener("pageshow",function(e){e.persisted&&i()}),2<=d){var o=t.createElement("body"),a=t.createElement("div");a.style.border=".5px solid transparent",o.appendChild(a),n.appendChild(o),1===a.offsetHeight&&n.classList.add("hairlines"),n.removeChild(o)}}(window,document)</script>

BIN
src/assets/images/wx_icon.png


BIN
src/assets/images/zfb.png


+ 2 - 3
src/common/axios.js

@@ -44,7 +44,6 @@ _axios.interceptors.request.use(
     return config;
   },
   function (error) {
-    Toast.clear()
     Toast('网络错误')
     // Do something with request error
     return Promise.reject(error);
@@ -56,7 +55,7 @@ _axios.interceptors.response.use(
   function (response) {
     // Do something with response data
     if (response.data.code == 403 || response.data.code == 403) {
-      window.localStorage.removeItem('userInfo') // 删除用户信息
+      // window.localStorage.removeItem('userInfo') // 删除用户信息
       window.localStorage.removeItem('Authorization') // 删除用户信息
       if (browser().android) {
         DAYA.postMessage(JSON.stringify({
@@ -67,7 +66,7 @@ _axios.interceptors.response.use(
           api: 'login'
         }))
       } else {
-        // router.push('/login')
+        router.push('/signUpAccount')
       }
     }
     return response;

+ 219 - 0
src/components/MPayment.vue

@@ -0,0 +1,219 @@
+<template>
+    <div class="mpayment">
+        <van-popup v-model="isShow" :close-on-click-overlay="false" close-icon-position="top-left" position="bottom" round :closeOnPopstate="true" :safe-area-inset-bottom="true" :style="{ minHeight: '30%' }" >
+            <i @click="onClose" class="van-icon van-icon-cross van-popup__close-icon van-popup__close-icon--top-left"></i>
+            <div class="title van-hairline--bottom">选择支付方式</div>
+            <div class="payAmount">
+                <p>应付金额</p>
+                <div class="amount">{{ payAmount }}<span>元</span></div>
+            </div>
+
+            <van-radio-group v-model="payType">
+                <div class="payment-item van-hairline--bottom" @click="payType = 'zfb'">
+                    <div class="logo-section">
+                        <img class="logo" src="@/assets/images/zfb.png" alt="">
+                    </div>
+                    <div class="title-section">支付宝支付</div>
+                    <div class="value-section"><van-radio name="zfb"></van-radio></div>
+                </div>
+                <div class="payment-item" @click="payType = 'wx'">
+                    <div class="logo-section">
+                        <img class="logo" src="@/assets/images/wx_icon.png" alt="">
+                    </div>
+                    <div class="title-section">微信支付</div>
+                    <div class="value-section"><van-radio name="wx"></van-radio></div>
+                </div>
+            </van-radio-group>
+
+            <div class="blank"></div>
+            <van-button type="primary" block @click="onSubmit">确认支付</van-button>
+        </van-popup>
+    </div>
+</template>
+
+<script>
+import { changeTwoDecimal } from '@/utils/common'
+export default {
+    name: "mHeader",
+    props: {
+        closeStatus: { // 弹窗关闭状态
+            type: Boolean,
+            default: false
+        },
+        amount: { // 支付金额
+            type: Number,
+            default: 0
+        },
+        payment: { // 支付对象
+            type: Object
+        }
+    },
+    data() {
+        return {
+            isShow: this.closeStatus,
+            payAmount: this.amount,
+            paymentObject: this.payment, // 支付对象
+            payType: 'zfb'
+        };
+    },
+    methods: {
+        onClose() {
+            this.$dialog.confirm({
+                message: '是否放弃本次付款',
+                confirmButtonText: '继续付款',
+                cancelButtonText: '放弃'
+            }).then(() => {
+                // on confirm
+            }).catch(() => {
+                // on cancel
+                this.isShow = false
+                this.$emit("onChangeStatus", this.isShow);
+            })
+        },
+        onSubmit() { // 提交支付
+            // 支付...
+            const pt = this.payType,
+                ua = window.navigator.userAgent.toLowerCase()
+            // 判断当前浏览器
+            if (ua.match(/MicroMessenger/i) == 'micromessenger') {
+                // 微信浏览器
+                if (pt == 'zfb') {
+                    this.pay_channel = 'alipay_qr'
+                    this.getCodePay('qrCode')
+                } else if (pt == 'wx') {
+                    this.pay_channel = 'wx_pub'
+                    this.getCodePay('pay')
+                }
+            } else if (ua.match(/AlipayClient/i) == 'alipayclient') {
+                // 支付宝浏览器
+                if (pt == 'zfb') {
+                    this.pay_channel = 'alipay_wap'
+                    // 支付宝 H5 支付
+                    this.getCodePay('pay')
+                } else if (pt == 'wx') {
+                    this.pay_channel = 'wx_pub'
+                    this.getCodePay('qrCode')
+                }
+            } else {
+                if (pt == 'zfb') {
+                    this.pay_channel = 'alipay_qr'
+                } else if (pt == 'wx') {
+                    this.pay_channel = 'wx_pub'
+                }
+                this.getCodePay('qrCode')
+            }
+        },
+        getCodePay(code) {
+            // 二维码页面, 唤起支付页面
+            const payCode = code == 'qrCode' ? '/payQRCode' : '/payResult'
+            // this.$emit('confirmPayment', payCode) //
+            this.$router.push({
+                path: payCode, // 跳转到生成二维码页面
+                query: {
+                    payType: this.pay_channel, // 支付渠道
+                    payment: JSON.stringify(this.paymentObject) // 支付对象
+                }
+            })
+        },
+    },
+    watch: {
+        closeStatus(val) {
+            this.isShow = val
+        },
+        amount(val) {
+            // 强制转换金额,显示两们小数
+            this.payAmount = changeTwoDecimal(val)
+        },
+        payment(val) { // 监听数据
+            this.paymentObject = val
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+@import url("../assets/commonLess/variable");
+/deep/.van-popup__close-icon {
+    color: #cccccc;
+    font-size: .22rem;
+}
+/deep/.van-popup--bottom.van-popup--round {
+    border-radius: .06rem .06rem 0 0;
+    // background-color: rgba(0, 0, 0, 0.06);
+}
+/deep/.van-hairline--bottom::after {
+    border-bottom-color: #F0F0F0;
+}
+.title {
+    background-color: #ffffff;
+    font-size: .16rem;
+    font-weight: 400;
+    color: #1A1A1A;
+    padding: .14rem 0 .12rem;
+    text-align: center;
+}
+.payAmount {
+    background-color: #ffffff;
+    padding: .2rem 0;
+    text-align: center;
+    p {
+        font-size: .14rem;
+        color: #666666;
+        padding-bottom: .1rem;
+    }
+    .amount {
+        font-size: .28rem;
+        color: #000000;
+        span {
+            font-size: .18rem;
+            padding-left: .03rem;
+        }
+    }
+}
+
+/deep/.van-cell {
+    padding: .12rem .16rem;
+}
+
+.payment-item {
+    background-color: #ffffff;
+    display: flex;
+    padding: .12rem 0;
+    margin: 0 .16rem;
+    align-items: center;
+
+    .logo-section {
+        width: .22rem;
+        height: .22rem;
+        .logo {
+            width: .22rem;
+            height: .22rem;
+        }
+    }
+    .title-section {
+        font-size: .16rem;
+        padding-left: .1rem;
+        flex: 1;
+    }
+    .value-section {
+        flex: 1;
+        .van-radio {
+            float: right;
+        }
+    }
+}
+.blank {
+    height: .65rem;
+    background-color: #F0F0F0;
+}
+
+/deep/.van-button--primary {
+    background-color: #14928A;
+    color: #ffffff;
+    font-size: .16rem;
+    height: .52rem;
+    line-height: .50rem;
+    border-radius: 0;
+    border-color: #14928A;
+}
+</style>

+ 1 - 1
src/components/MStep.vue

@@ -77,7 +77,7 @@ export default {
 <style lang="less" scoped>
 @import url("../assets/commonLess/variable");
 .mStep {
-    padding-bottom: 0.2rem;
+    padding-bottom: 0.15rem;
     background-color: #ffffff;
     margin-top: .12rem;
 }

+ 35 - 0
src/router/adapayRouter.js

@@ -0,0 +1,35 @@
+let adapayRouter = [{
+	path: '/payQRCode',
+	name: 'payQRCode',
+	component: () => import( /* webpackChunkName: "PayQRCode" */ '@/views/adapay/PayQRCode'),
+	meta: {
+		description: '支付扫码',
+		weight: 8 // 页面权重
+	}
+}, {
+	path: '/payResult',
+	name: 'payResult',
+	component: () => import( /* webpackChunkName: "PayResult" */ '@/views/adapay/PayResult'),
+	meta: {
+		description: '支付',
+		weight: 8 // 页面权重
+	}
+}, {
+	path: '/payDefine',
+	name: 'payDefine',
+	component: () => import( /* webpackChunkName: "PayDefine" */ '@/views/adapay/PayDefine'),
+	meta: {
+		description: '确定支付',
+		weight: 8 // 页面权重
+	}
+}, {
+	path: '/payCenter',
+	name: 'payCenter',
+	component: () => import( /* webpackChunkName: "PayCenter" */ '@/views/adapay/PayCenter'),
+	meta: {
+		description: '支付中间页',
+		weight: 8 // 页面权重
+	}
+}]
+
+export default adapayRouter

+ 3 - 1
src/router/index.js

@@ -2,6 +2,7 @@ import Vue from 'vue'
 import Router from 'vue-router'
 import LevelRouter from './levelRouter'
 import ApplyRouter from './applyRouter'
+import AdapayRouter from './adapayRouter'
 
 Vue.use(Router)
 
@@ -9,7 +10,7 @@ let defaultRouter = [
   {
     path: '/',
     redirect: {
-      name: 'levelMusic'
+      name: 'signUp'
     }
   }, {
     path: "/levelMusic",
@@ -25,6 +26,7 @@ let defaultRouter = [
 
 defaultRouter = defaultRouter.concat(LevelRouter)
                 .concat(ApplyRouter)
+                .concat(AdapayRouter)
 
 const router = new Router({
   // mode: 'history',

+ 22 - 83
src/utils/common.js

@@ -19,30 +19,6 @@ const browser = () => {
 }
 
 /**
- * 小于10的数变成 (0x)
- * @param {数值} num 
- */
-const getSTD = (num) => {
-  return Number(num) >= 10 ? num : '0' + num
-}
-
-/**
- * 获取格式化的年月日
- * @param {日期} time 
- * @param {不是IOS里使用(多用于接口参数)} noIos 
- */
-const getYMD = (time, noIos) => {
-  let tempDate = time || new Date()
-  if (typeof (tempDate) == 'string') {
-    tempDate = new Date(time.replace(/-/ig, '/'))
-  }
-  let t = noIos ? '-' : '/'
-  let month = getSTD(tempDate.getMonth() + 1)
-  let day = getSTD(tempDate.getDate())
-  return tempDate.getFullYear() + t + month + t + day
-}
-
-/**
  *
  * @param {周几的索引值} index
  */
@@ -52,74 +28,37 @@ const getWeekString = (index) => {
 }
 
 /**
- * 计算课程的结束时间
- * @param {课程组开始时间} startDate 
- * @param {购买几个月时间} buyMonths 
+ * 转换金额为保留2位小数
+ * @param x
+ * @returns 强制保留2位小数的金额
  */
-const courseExpireDateArray = (startDate, buyMonths) => {
-  let resultDate = new Date(startDate)
-  let lastDayNum = nextMonthLastDay(resultDate.getFullYear(), (resultDate.getMonth() + 1 + buyMonths))
-  if (lastDayNum[2] >= resultDate.getDate()) {
-    resultDate.setMonth(resultDate.getMonth() + buyMonths)
-  } else {
-    resultDate = new Date(lastDayNum.join('/'))
+const changeTwoDecimal = (amt) => {
+  let f_x = parseFloat(amt);
+  if (isNaN(f_x)) {
+    return "0.00";
   }
-  resultDate.setDate(resultDate.getDate() - 1)
-  return resultDate
-}
-
-const nextMonthLastDay = (year, month) => { //日期显示为次月最后一天
-  if (month > 12) {
-    month = month - 12;
-    year = year + 1;
+  f_x = Math.round(f_x * 100) / 100;
+  let s_x = f_x.toString();
+  let pos_decimal = s_x.indexOf('.');
+  if (pos_decimal < 0) {
+    pos_decimal = s_x.length;
+    s_x += '.';
   }
-  var day = nextMonthDay(year, month);
-  return [year, month, day];
-}
-
-const nextMonthDay = (year, month) => { //判断每月多少天
-  var day31 = [1, 3, 5, 7, 8, 10, 12];
-  var day30 = [4, 6, 9, 11];
-  if (day31.indexOf(month) > -1) {
-    return 31;
-  } else if (day30.indexOf(month) > -1) {
-    return 30;
-  } else {
-    if (isLeapYear(year)) {
-      return 29;
-    } else {
-      return 28;
-    }
+  while (s_x.length <= pos_decimal + 2) {
+    s_x += '0';
   }
+  return s_x;
 }
 
-/**
- * 判断是否为闰年
- */
-const isLeapYear = (year) => {
-  return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
-}
-
-/**
- * 检测是否为手机号
- * @param {手机号} phoneNumber 
- */
-const checkPhone = (phoneNumber) => {
-  let result = true
-  if (!(/^1(3|4|5|6|7|8|9)\d{9}$/.test(phoneNumber))) {
-    result = false
-  }
-  return result
+// 获取授权的code码
+/* eslint-disable */
+const getUrlCode = (name) => {
+  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) || [, ''])[1].replace(/\+/g, '%20')) || null
 }
 
 export {
   browser,
-  getSTD,
-  getYMD,
   getWeekString,
-  nextMonthLastDay,
-  nextMonthDay,
-  isLeapYear,
-  courseExpireDateArray,
-  checkPhone
+  changeTwoDecimal,
+  getUrlCode
 }

+ 11 - 0
src/views/adapay/AdapayApi.js

@@ -0,0 +1,11 @@
+import qs from 'qs'
+const axios = require('@/common/axios').default
+
+// 台牌支付
+export function executePayment (data) {
+    return axios({
+        url: '/api-user/examOrder/executePayment',
+        method: 'post',
+        data: qs.stringify(data)
+    })
+}

+ 113 - 0
src/views/adapay/PayCenter.vue

@@ -0,0 +1,113 @@
+<template>
+	<div class="payCenter">
+		<div class="error-text">
+			<van-icon v-if="errorText" class="error-icon" name="warning-o" />
+			{{ errorText }}
+		</div>
+	</div>
+</template>
+
+<script>
+import { changeTwoDecimal, getUrlCode } from '@/utils/common'
+export default {
+	name: 'payCenter',
+	data() {
+		let query = this.$route.query
+		return {
+			amount: changeTwoDecimal(query.amount), // 支付金额
+			orderNo: query.orderNo, // 订单号
+			sign: query.sign, // 签名
+			payType: query.payType,
+			errorText: null, // 错误信息
+			orderBody: query.orderBody,
+			orderSubject: query.orderSubject,
+			code: null,
+			platform: query.platform
+		}
+	},
+	mounted() {
+		// 判断当前浏览器
+		const payType = this.payType
+		const ua = window.navigator.userAgent.toLowerCase()
+		if (ua.match(/MicroMessenger/i) == 'micromessenger') {
+			if(payType === 'wx_pub') {
+				//授权
+				let code = getUrlCode('code')
+				if(code) {
+					this.code = code // 赋值code码
+					this.onPayPage() // 跳转支付页
+				} else {
+					this.goAuth()
+				}
+                document.title = '微信支付'
+			} else if(payType == 'alipay_qr') {
+				this.errorText = '请使用支付宝扫码'
+			}
+		} else if (ua.match(/AlipayClient/i) == 'alipayclient') {
+			if(payType === 'wx_pub') {
+				this.errorText = '请使用微信扫码'
+			} else if(payType == 'alipay_qr') {
+				// 支付宝支付
+                document.title = '支付宝支付'
+                this.onPayPage() // 跳转支付页
+			}
+		} else {
+			this.errorText = '请在微信或支付宝客户端打开'
+		}
+		this.errorText && (document.title = 'ERROR')
+	},
+	methods: {
+        onPayPage() {
+            // 跳转对应支付页
+            this.$router.replace({
+                path: 'payDefine',
+                query: {
+                    amount: this.amount, // 支付金额
+                    orderNo: this.orderNo, // 订单号
+                    sign: this.sign, // 签名
+                    payType: this.payType,
+                    orderBody: this.orderBody,
+					orderSubject: this.orderSubject,
+					platform: this.platform, // 平台
+					code: this.code // 获取授权码
+                }
+            })
+        },
+		goAuth() { // 用户授权
+			// let urls = this.config.value = window.location.origin + '/#/payDefine?orderNo=' + this.orderNo + '&sign=' + this.sign + '&amount=' + this.amount + '&payType=' + this.payType + '&orderBody=' + this.orderBody + '&orderSubject=' + this.orderSubject
+			let urlNow = encodeURIComponent(window.location.href);
+			let scope = 'snsapi_base'; //snsapi_userinfo   //静默授权 用户无感知
+			let appid = 'wx751141096e75a4ee';
+			// let appid = 'wx80f175c0eb6836e9';
+			let url =
+				`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${urlNow}&response_type=code&scope=${scope}&state=STATE&connect_redirect=1#wechat_redirect`;
+			window.location.replace(url)
+		}
+	},
+	destroyed() {
+		this.$toast.clear()
+		this.$dialog.close()
+		document.title = '管乐迷'
+	}
+}
+</script>
+
+<style lang="less">
+.payCenter {
+    min-height: 100vh;
+    overflow: hidden;
+}
+.error-icon {
+	display: block;
+	color: #ffb07b;
+	font-size: 120px;
+	margin-bottom: .3rem;
+}
+.error-text {
+    font-size: .15rem;
+    width: 100%;
+    text-align: center;
+    color: #3F3F3F;
+    margin-top: 100px;
+}
+</style>

+ 273 - 0
src/views/adapay/PayDefine.vue

@@ -0,0 +1,273 @@
+<template>
+	<div class="payDefine">
+		<m-header v-if="headerStatus" />
+
+		<div class="container" v-if="browserStatus">
+			<div class="amount">¥{{ amount }}</div>
+			<van-cell-group :border="true">
+				<!-- 扫码支付 -->
+				<van-cell title="订单信息" :value="orderBody" />
+				<!-- <van-cell title="收款方" value="深圳大雅乐盟网管教育股份有限公司" /> -->
+				<van-cell title="支付方式" :value="payTypeString" />
+				<van-cell title="实付金额" :value="'¥' + amount + '元'" />
+			</van-cell-group>
+
+			<van-button type="primary" block size="large" @click="getPayment" round color="#14928A">立即支付</van-button>
+		</div>
+
+		<div class="container" else>
+			<div class="error-text">
+				<van-icon v-if="errorText" class="error-icon" name="warning-o" />
+				{{ errorText }}
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+/* eslint-disable */
+const axios = require('@/common/axios').default
+import MHeader from '@/components/MHeader'
+import { executePayment } from './AdapayApi'
+import {
+	browser,
+	changeTwoDecimal,
+	getUrlCode,
+} from '@/utils/common'
+export default {
+	name: 'payDefine',
+	components: {
+		MHeader
+	},
+	data() {
+		let query = this.$route.query
+		return {
+			headerStatus: false,
+			browserStatus: false,
+			amount: changeTwoDecimal(query.amount), // 支付金额
+			orderNo: query.orderNo, // 订单号
+			sign: query.sign, // 签名
+			payType: query.payType,
+			payTypeString: query.payType == 'wx_pub' ? '微信' : '支付宝',
+			errorText: null, // 错误信息
+			orderBody: query.orderBody,
+			orderSubject: query.orderSubject,
+			code: query.code, // 微信授权code码
+		}
+	},
+	mounted() {
+		if (window.location.href.indexOf("?#") < 0) {
+			window.location.href = window.location.href.replace("#", "?#");
+		}
+		// 判断当前浏览器
+		const payType = this.payType
+		const ua = window.navigator.userAgent.toLowerCase()
+		if (ua.match(/MicroMessenger/i) == 'micromessenger') {
+			if(payType === 'wx_pub') {
+				//授权
+				let code = getUrlCode('code')
+				if(code) {
+					this.code = code // 赋值code码
+				}
+				this.browserStatus = true
+				document.title = '微信支付'
+			} else if(payType == 'alipay_qr') {
+				this.errorText = '请使用支付宝扫码'
+			}
+		} else if (ua.match(/AlipayClient/i) == 'alipayclient') {
+			if(payType === 'wx_pub') {
+				this.errorText = '请使用微信扫码'
+			} else if(payType == 'alipay_qr') {
+				// 支付宝支付
+				this.browserStatus = true
+				document.title = '支付宝支付'
+			}
+		} else {
+			this.errorText = '请在微信或支付宝客户端打开'
+		}
+		this.errorText && (document.title = 'ERROR')
+	},
+	methods: {
+		// 下单
+		async getPayment() {
+			try {
+                if (!(parseFloat(this.amount) > 0)) {
+                    this.$toast('支付金额异常')
+                    return
+                }
+                let that = this,
+                    payMap = {
+						orderNo: this.orderNo,
+						sign: this.sign,
+						amount: this.amount,
+						payChannel: this.payType, // 支付渠道
+						orderBody: this.orderBody,
+						orderSubject: this.orderSubject
+					}
+				// 判断是否是微信公众号支付
+                if(this.payType == 'wx_pub') {
+                    payMap.code = this.code
+				}
+				this.$toast.loading({
+					duration: 0,
+					message: '加载中...',
+					forbidClick: true
+				})
+
+                await executePayment(payMap).then(res => {
+					this.$toast.clear()
+                    let result = res.data
+                    if(result.code == 200) {
+                        let payment = result.data
+                        if (payment.status === 'succeeded') {
+							this.scanCodePay(payment)
+                        } else if(payment.status == 'failed') {
+							this.browserStatus = false
+							this.errorText = payment.error_msg
+							document.title = 'ERROR'
+                        } else if(payment.status == 'pending') {
+                            this.$dialog.alert({
+                                title: '提示',
+                                message: '订单处理中...',
+                                confirmButtonColor: '#269a93'
+                            })
+                        }
+                    } else {
+                        this.$dialog.alert({
+                            title: '提示',
+                            message: result.msg,
+                            confirmButtonColor: '#269a93'
+                        })
+                    }
+                }).catch(err => {
+					this.$toast.clear()
+                    this.$dialog.alert({
+                        title: '提示',
+                        message: JSON.stringify(err),
+                        confirmButtonColor: '#269a93'
+                    })
+                })
+            } catch (error) {
+                this.$dialog.alert({
+                    title: '提示',
+                    message: '网络异常,请检查网络连接',
+                    confirmButtonColor: '#269a93'
+                })
+            }
+		},
+		scanCodePay(data) {
+			// 判断支付方式 如果是 test 模式 支付用测试url 否则用生产url
+			if(this.payType == 'alipay_qr') {
+				let url = data.prod_mode === "false" ? data.expend.qrcode_url + "?payment_id=" + data.id + "&pay_channel=" + data.pay_channel : data.expend.qrcode_url
+				window.location.href = url
+			} else if(this.payType == 'wx_pub') {
+				let tempPayInfo = JSON.parse(data.expend.pay_info)
+				this.payInfo = tempPayInfo
+				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();
+				}
+			}
+		},
+		onBridgeReady() {
+			let payInfo = this.payInfo
+			let orderNo = this.orderNo
+			WeixinJSBridge.invoke(
+				'getBrandWCPayRequest', {
+					"appId": payInfo.appId,     //公众号名称,由商户传入
+					"timeStamp": payInfo.timeStamp,         //时间戳,自1970年以来的秒数
+					"nonceStr": payInfo.nonceStr, //随机串
+					"package": payInfo.package,
+					"signType": payInfo.signType,         //微信签名方式:
+					"paySign": payInfo.paySign //微信签名
+				},
+				(res) => {
+					// if(res.err_msg == "get_brand_wcpay_request:ok" ){
+						// 使用以上方式判断前端返回,微信团队郑重提示:
+						//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
+					// } else
+					if(res.err_msg == "get_brand_wcpay_request:cancel" || res.err_msg == "get_brand_wcpay_request:fail") {
+						// 用户取消支付
+						this.$router.replace({
+							path: '/levelMusic',
+							query: {
+								type: "error",
+								orderNo: orderNo,
+								isBack: "off"
+							}
+						})
+					} else {
+						// 使用以上方式判断前端返回,微信团队郑重提示:
+						//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
+						this.$router.replace({
+							path: '/levelMusic',
+							query: {
+								orderNo: this.orderNo,
+								isBack: "off"
+							}
+						})
+					}
+				}
+			);
+		},
+		goAuth() { // 用户授权
+			let urlNow = encodeURIComponent(window.location.href);
+			let scope = 'snsapi_base'; //snsapi_userinfo   //静默授权 用户无感知
+			let appid = 'wx751141096e75a4ee';
+			// let appid = 'wx86f161d5a32af6ac';
+			let url =
+				`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${urlNow}&response_type=code&scope=${scope}&state=STATE&connect_redirect=1#wechat_redirect`;
+			window.location.replace(url)
+		}
+	},
+	destroyed() {
+		this.$toast.clear()
+		this.$dialog.close()
+		document.title = '酷乐秀'
+	}
+}
+</script>
+
+<style lang="less" scoped>
+	.payDefine {
+		overflow: hidden;
+		background: #fff;
+		min-height: 100vh;
+	}
+	.amount {
+		padding: .3rem 0;
+		font-size: .3rem;
+		text-align: center;
+		font-weight: 600;
+	}
+	/deep/.van-cell__title, /deep/.van-cell__value {
+		flex: auto;
+		font-size: .15rem;
+		color: #4F4F4F;
+	}
+	/deep/.van-button {
+		font-size: .16rem;
+		width: 86%;
+    	margin: .2rem auto;
+	}
+	.error-text {
+		font-size: .15rem;
+		width: 100%;
+		text-align: center;
+		color: #3F3F3F;
+		margin-top: 100px;
+	}
+
+	.error-icon {
+		display: block;
+		color: #ffb07b;
+		font-size: 120px;
+		margin-bottom: .3rem;
+	}
+</style>

+ 217 - 0
src/views/adapay/PayQRCode.vue

@@ -0,0 +1,217 @@
+<template>
+	<div class="payQrCode">
+		<m-header v-if="headerStatus" />
+
+		<div class="payCode" v-if="payment">
+			<!-- <h3 class="popup-title">请在60S内完成支付</h3> -->
+			<h3 class="popup-title">请截图下方二维码<br />登录{{ payTypeString }}扫码支付</h3>
+			<!-- @click="onChangeCode" -->
+			<div id="qrcode">
+				<!-- :logoSrc="config.imagePath" -->
+				<vue-qr v-if="config.value" :text="config.value" :margin="10" :size="250" />
+			</div>
+			<p class="code-tips" v-if="codeRefreshStatus">点击二维码进行刷新</p>
+			<p class="popup-tips">
+				使用说明:<br/>
+				1.长按二维码保存图片到相册(或截屏保存到相册)<br/>
+				2.打开{{ payTypeString }}扫一扫<br/>
+				3.选择相册中的二维码
+			</p>
+		</div>
+	</div>
+</template>
+
+<script>
+// /* eslint-disable */
+import VueQr from 'vue-qr'
+import MHeader from '@/components/MHeader'
+// import { checkOrderStatus } from "@/api/student"
+// import qs from 'qs' executePayment
+// changeTwoDecimal,
+// 	getUrlCode
+//  browser,
+import { browser } from '@/utils/common'
+export default {
+	name: 'payQrCode',
+	components: {
+		MHeader,
+		VueQr
+	},
+	data() {
+		let query = this.$route.query
+		console.log(query)
+		return {
+			headerStatus: false,
+			codeRefreshStatus: false, // 是否进行刷新
+			// 支付宝: alipay_qr;  微信: wx_pub
+			payType: query.payType, // 支付方式
+			payTypeString: query.payType == 'wx_pub' ? '微信' : '支付宝',
+			payment: query.payment ? JSON.parse(query.payment) : null, // 对象
+			openId: null,
+			config: {
+				value: null,//显示的值、跳转的地址
+				// imagePath: require('../../assets/images/icon_app.png')//中间logo的地址
+				// imagePath: query.payType == 'wx_pub' ? require('../../assets/images/wx_icon.png') : require('../../assets/images/zfb.png')
+			},
+			orderTimer: null,
+			platform: query.platform
+			// query.platform
+		}
+	},
+	mounted() {
+		// 判断是否在app里面
+		if (!browser().android && !browser().iPhone) {
+			this.headerStatus = true
+		} else {
+			document.title = '支付扫码'
+		}
+		if(this.platform == 'manager') { // 如果是教务端则显示头部
+			this.headerStatus = true
+		}
+		document.title = '支付扫码'
+		// 判断是否有支付对象
+		if(!this.payment || !this.payType) {
+			this.$dialog.alert({
+				message: '支付订单信息错误请重新支付'
+			}).then(() => {
+				this.$router.back()
+			})
+		} else {
+			// 判断是否是微信浏览器支付 并且是微信支付
+			// 微信支付
+			let { orderNo, sign, amount, orderBody, orderSubject } = this.payment
+			this.config.value = window.location.origin + '/#/payCenter?orderNo=' + orderNo + '&sign=' + sign + '&amount=' + amount + '&payType=' + this.payType + '&orderBody=' + orderBody + '&orderSubject=' + orderSubject
+			setTimeout(() => {
+				if(this.platform == 'teacher') {
+					this.getPaymentOrderTeacherStatus()
+				} else {
+					this.getPaymentOrderStatus()
+				}
+			}, 3000)
+		}
+	},
+	methods: {
+		getPaymentOrderStatus() { // 循环查询订单
+			// let { orderNo } = this.payment
+			let orderTimer = setInterval(() => {
+				// 判断是否在当前路由,如果不是则清除定时器
+				if(this.$route.name != 'payQRCode') {
+					clearInterval(orderTimer)
+					return
+				}
+				this.orderTimer = orderTimer
+				// checkOrderStatus({ orderNo: orderNo }).then(res => {
+				// 	let result = res.data
+				// 	if(result.code == 200) {
+				// 		let tempOrder = result.data.order
+				// 		if(tempOrder.status != 'ING') {
+				// 			clearInterval(orderTimer)
+				// 			this.onCallBackUrl(orderNo)
+				// 		}
+				// 	} else {
+				// 		clearInterval(orderTimer)
+				// 		this.onCallBackUrl(orderNo)
+				// 	}
+				// }).catch(() => {
+				// 	clearInterval(orderTimer)
+				// })
+			}, 5000)
+		},
+		onCallBackUrl(orderNo) {
+			this.$router.replace({
+				path: '/levelMusic',
+				query: {
+					orderNo: orderNo
+				}
+			})
+		}
+	},
+	beforeDestroy() {
+		clearInterval(this.orderTimer)
+	},
+	destroyed() {
+		this.$toast.clear()
+		clearInterval(this.orderTimer)
+	}
+}
+</script>
+
+<style lang="less" scoped>
+.payQrCode {
+	overflow: hidden;
+	// background: #fff;
+	min-height: 100vh;
+}
+
+.payCode {
+	width: 90%;
+	margin: .3rem 5%;
+	background: #fff;
+	padding: .4rem 0;
+}
+
+.popup-title {
+	padding-bottom: .2rem;
+	text-align: center;
+	font-size: .16rem;
+	color: #4F4F4F;
+	font-weight: bold;
+}
+
+.code-tips {
+	text-align: center;
+    padding-top: .05rem;
+    color: red;
+}
+.popup-tips {
+	margin: .15rem;
+	margin-bottom: 0;
+	padding: .1rem .12rem;
+	font-size: .12rem;
+	background: #EBEBEB;
+}
+
+// .button-group {
+// 	padding: .15rem;
+// 	font-size: .14rem;
+// 	color: #009688;
+// 	text-align: center;
+// }
+
+// .loading-section {
+// 	width: 200px;
+// 	height: 200px;
+// 	background: #fff;
+// 	display: flex;
+// 	justify-content: center;
+// 	align-items: center;
+// }
+
+#qrcode {
+	background: #fff;
+	// padding: .05rem;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	min-height: 250px;
+}
+
+// .pay-section {
+// 	margin-top: .05rem;
+// }
+
+// .title {
+// 	font-size: .16rem;
+// 	color: #444;
+// 	font-weight: bold;
+// }
+
+// .pay-name {
+// 	padding-left: .1rem;
+// }
+
+// .orderno {
+// 	font-size: .14rem;
+// 	color: #777777;
+// }
+</style>

+ 300 - 0
src/views/adapay/PayResult.vue

@@ -0,0 +1,300 @@
+<template>
+	<div class="payWxResult">
+		<m-header v-if="headerStatus" />
+
+		<div v-if="browserStatus" key="browser">
+			<div class="container">
+				<van-cell-group :border="false">
+					<van-cell title="订单金额" :value="'¥' + amount" />
+					<van-cell title="订单信息" :value="payMap.orderBody" />
+					<!-- <van-cell title="收款方" value="深圳大雅乐盟网管教育股份有限公司" /> -->
+				</van-cell-group>
+			</div>
+
+			<div class="order-loading">
+				<p>{{ payType == 'wx_pub' ? '微信支付' : '支付宝支付' }}</p>
+				<van-loading type="spinner" color="#14928A" />
+			</div>
+		</div>
+		<div v-else key="browser">
+			<div class="error-text">
+				<van-icon v-if="errorText" class="error-icon" name="warning-o" />
+				{{ errorText }}
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+/* eslint-disable */
+import MHeader from '@/components/MHeader'
+import { executePayment } from './AdapayApi'
+import {
+	browser,
+	getUrlCode,
+	changeTwoDecimal
+} from '@/utils/common'
+export default {
+	name: 'payWxResult',
+	components: {
+		MHeader
+	},
+	data() {
+		let query = this.$route.query
+		const { payMap } = query.payment ? JSON.parse(query.payment) : {}
+		return {
+			headerStatus: false,
+			browserStatus: false,
+			payType: query.payType, // 支付方式
+			payMap: payMap,
+			amount: changeTwoDecimal(0), // 支付金额
+			errorText: null
+		}
+	},
+	mounted() {
+		// if (window.location.href.indexOf("?#") < 0) {
+		// 	window.location.href = window.location.href.replace("#", "?#");
+		// }
+		// 判断是否在app里面
+		// if (!browser().android || !browser().iPhone) {
+		// 	this.headerStatus = true
+		// }
+		//  else {
+		// 	document.title = '微信支付'
+		// }
+
+		// 判断是否有支付对象
+		if(!this.payMap || !this.payType) {
+			this.$dialog.alert({
+				message: '支付订单信息错误请重新支付'
+			}).then(() => {
+				this.$router.back()
+			})
+		} else {
+			this.amount = changeTwoDecimal(this.payMap.amount)
+			// 判断当前浏览器
+			const ua = window.navigator.userAgent.toLowerCase()
+            if (ua.match(/MicroMessenger/i) == 'micromessenger') {
+				this.browserStatus = true
+                this.getWxPay()
+            } else if (ua.match(/AlipayClient/i) == 'alipayclient') {
+				this.browserStatus = true
+                this.getPayment()
+            } else {
+				this.errorText = '请在微信或支付宝客户端打开'
+				document.title = 'ERROR'
+			}
+		}
+		// this.getWxPay()
+	},
+	methods: {
+		// 下单
+		getPayment() {
+			try {
+                if (!(parseFloat(this.amount) > 0)) {
+                    this.$toast('支付金额异常')
+                    return
+				}
+				let { orderNo, sign, amount, orderBody, orderSubject } = this.payMap
+                let that = this,
+                    payMap = {
+						orderNo: orderNo,
+						sign: sign,
+						amount: amount,
+						orderBody: orderBody,
+						orderSubject: orderSubject,
+						payChannel: this.payType, // 支付渠道
+					}
+				// 判断是否是微信公众号支付
+                if(this.payType == 'wx_pub') {
+                    payMap.code = this.code
+				}
+
+				this.$toast.loading({
+					duration: 0,
+					message: '加载中...',
+					forbidClick: true
+				})
+
+                executePayment(payMap).then(res => {
+					this.$toast.clear()
+                    let result = res.data
+                    if(result.code == 200) {
+                        let payment = result.data
+                        if (payment.status === 'succeeded') {
+							this.scanCodePay(payment)
+                        } else if(payment.status == 'failed') {
+                            this.browserStatus = false
+							this.errorText = payment.error_msg
+							document.title = 'ERROR'
+                        } else if(payment.status == 'pending') {
+                            this.$dialog.alert({
+                                title: '提示',
+                                message: '订单处理中...',
+                                confirmButtonColor: '#269a93'
+                            })
+                        }
+                    } else {
+                        this.$dialog.alert({
+                            title: '提示',
+                            message: result.msg,
+                            confirmButtonColor: '#269a93'
+                        })
+                    }
+                }).catch(err => {
+					this.$toast.clear()
+                    this.$dialog.alert({
+                        title: '提示',
+                        message: JSON.stringify(err),
+                        confirmButtonColor: '#269a93'
+                    })
+                })
+            } catch (error) {
+                this.$dialog.alert({
+                    title: '提示',
+                    message: error.toString(),
+                    confirmButtonColor: '#269a93'
+                })
+            }
+		},
+		scanCodePay(data) {
+			// 判断支付方式 如果是 test 模式 支付用测试url 否则用生产url
+			if(this.payType == 'alipay_wap') {
+				window.location.href = data.expend.pay_info
+			} else if(this.payType == 'wx_pub') {
+				let tempPayInfo = JSON.parse(data.expend.pay_info)
+				this.payInfo = tempPayInfo
+				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();
+				}
+			}
+		},
+		onBridgeReady() {
+			let payInfo = this.payInfo
+			WeixinJSBridge.invoke(
+				'getBrandWCPayRequest', {
+					"appId": payInfo.appId,     //公众号名称,由商户传入
+					"timeStamp": payInfo.timeStamp,         //时间戳,自1970年以来的秒数
+					"nonceStr": payInfo.nonceStr, //随机串
+					"package": payInfo.package,
+					"signType": payInfo.signType,         //微信签名方式:
+					"paySign": payInfo.paySign //微信签名
+				},
+				(res) => {
+					console.log(res)
+					// if(res.err_msg == "get_brand_wcpay_request:ok" ){
+						// 使用以上方式判断前端返回,微信团队郑重提示:
+						//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
+					// } else
+					// 支付取消或支付失败
+					let { orderNo } = this.payMap
+					if(res.err_msg == "get_brand_wcpay_request:cancel" || res.err_msg == "get_brand_wcpay_request:fail") {
+						// 用户取消支付
+						this.$router.replace({
+							path: '/levelMusic',
+							query: {
+								type: "error",
+								orderNo: orderNo,
+								isBack: "off"
+							}
+						})
+					} else {
+						// 使用以上方式判断前端返回,微信团队郑重提示:
+						//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
+						this.$router.replace({
+							path: '/levelMusic',
+							query: {
+								orderNo: orderNo,
+								isBack: "off"
+							}
+						})
+					}
+				}
+			);
+		},
+		getWxPay() { // 微信公众号支付
+			//授权
+			let code = getUrlCode('code')
+			if (!code) {
+				this.goAuth()
+			} else {
+				this.code = code
+				this.getPayment()
+			}
+		},
+		goAuth() { // 用户授权
+			let urlNow = encodeURIComponent(window.location.href);
+			let scope = 'snsapi_base'; //snsapi_userinfo   //静默授权 用户无感知
+			let appid = 'wx751141096e75a4ee';
+			let url =
+				`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${urlNow}&response_type=code&scope=${scope}&state=STATE&connect_redirect=1#wechat_redirect`;
+			window.location.replace(url);
+		}
+	},
+	destroyed() {
+		this.$toast.clear()
+		this.$dialog.close()
+	}
+}
+</script>
+
+<style lang="less" scoped>
+	.payWxResult {
+		overflow: hidden;
+		// background: #fff;
+		min-height: 100vh;
+	}
+	.container {
+		background: #fff;
+		padding: .15rem 0;
+	}
+	/deep/.van-cell {
+		padding: .12rem .16rem;
+	}
+	/deep/.van-cell__title, /deep/.van-cell__value {
+		flex: auto;
+		font-size: .16rem;
+		color: #4F4F4F;
+	}
+	/deep/.van-button {
+		font-size: .16rem;
+		width: 86%;
+		margin: .2rem auto;
+	}
+
+	.order-loading {
+		padding: .15rem 0;
+		margin-top: .15rem;
+		background-color: #ffffff;
+		text-align: center;
+		font-size: .15rem;
+		 & > p {
+			margin-bottom: .15rem;
+		 }
+	}
+	/deep/.van-loading__spinner {
+		width: .5rem;
+		height: .5rem;
+	}
+	.error-text {
+		font-size: .15rem;
+		width: 100%;
+		text-align: center;
+		color: #3F3F3F;
+		margin-top: 100px;
+	}
+
+	.error-icon {
+		display: block;
+		color: #ffb07b;
+		font-size: 120px;
+		margin-bottom: .3rem;
+	}
+</style>

+ 59 - 12
src/views/signup/SignUp.vue

@@ -1,47 +1,94 @@
 <template>
     <div class="SignUp">
-        <m-header />
-		<div class="container">
+        <!-- <m-header /> -->
+		<div v-show="show" class="container" :style="backgroundImg">
 			<div class="title">
-				<h2>6月春考</h2>
-				<p>报名时间:2020.6.5-6.20</p>
+				<h2>{{ baseInfo.posterTitle }}</h2>
+				<p>报名时间:{{ baseInfo.enrollStartTime }}~{{ baseInfo.enrollEndTime }}</p>
 			</div>
-			<m-button class="sign-btn" @click="onSubmit" text="我要报名" />
+			<m-button class="sign-btn" v-if="baseInfo.status === 'APPLYING'" @click="onSubmit" text="我要报名" />
 		</div>
     </div>
 </template>
 <script>
-import MHeader from '@/components/MHeader'
+// import MHeader from '@/components/MHeader'
 import MButton from '@/components/MButton'
+import dayjs from 'dayjs'
 import _ from 'lodash'
+import setLoading from '@/utils/loading'
+import { examinationBasicInfo } from './SignUpApi'
+// ETTING("SETTING", "设置中"),
+// NOT_START("NOT_START", "未开始"),
+// APPLYING("APPLYING","报名中"),
+// APPLIED("APPLIED", "报名结束"),
+// EXAM_ING("EXAM_ING", "考试中"),
+// EXAM_END("EXAM_END", "考试结束"),
+// RESULT_CONFIRM("RESULT_CONFIRM", "确认考试结果"),
+// CLOSE("CLOSE", "关闭")
 export default {
     name: 'SignUp',
-	components: { MHeader, MButton },
+	components: { MButton },
     data () {
+		localStorage.removeItem('examId')
+		let query = this.$route.query
         return {
-			show: true
+			examId: query.examId,
+			show: false,
+			baseInfo: {}, // 基本信息
+			backgroundImg: null
         }
     },
     mounted() {
+		this.__init()
     },
     methods: {
+		async __init() {
+			setLoading(true)
+			try {
+				localStorage.setItem('examId', this.examId)
+				let res = await examinationBasicInfo({ examId: this.examId })
+				if(res.data.code == 200) {
+					let tempData = res.data.data
+					this.baseInfo = {
+						posterTitle: tempData.posterTitle,
+						enrollStartTime: dayjs(tempData.enrollStartTime).format("YYYY.MM.DD"),
+						enrollEndTime: dayjs(tempData.enrollEndTime).format("YYYY.MM.DD"),
+						status: tempData.status
+					}
+					// 设置背景图
+					this.backgroundImg = {
+						backgroundImage: `url(${tempData.posterBackgroundImg}) !important`
+					}
+				}
+			} catch(err) {
+				//
+			}
+			this.show = true
+			setLoading(false)
+		},
 		onSubmit: _.throttle(function() {
 			// console.log(show)
+			this.$router.replace({
+				path: '/signUpAccount'
+			})
 		}, 500)
     }
 }
 </script>
 <style lang="less" scoped>
 .SignUp {
-    height: 100vh;
+	height: 100vh;
+	max-width: 700px;
+	position: relative;
     overflow-y: auto;
     overflow-x: hidden;
-    background-color: #fff;
+	background-color: #fff;
+	margin: 0 auto;
 }
 .container {
-	min-height: calc(100vh - .44rem);
+	min-height: 100vh;
 	background: url('../../assets/images/level/signup_bg.png') no-repeat center top;
-	background-size: contain;
+	background-size: cover;
 	.title {
 		text-align: center;
 		padding-top: .55rem;

+ 1 - 3
src/views/signup/SignUpAccount.vue

@@ -6,7 +6,6 @@
         <div class="title">基本信息</div>
         <!-- <van-form ref="form" :show-error="false" validate-first @submit="onSubmit" @failed="onFailed"> -->
         <van-field v-model="form.phone" required name="phone" label="手机号" placeholder="请输入手机号" />
-
         <van-field v-model="form.code" required clearable name="code" label="验证码" placeholder="请输入验证码" >
             <template #button>
                 <span class="codeText" v-show="countDownStatus" @click="onGetCode">获取验证码</span>
@@ -40,7 +39,7 @@ export default {
     data () {
         const query = this.$route.query
         return {
-            organId: query.organId,
+            organId: query.examId,
             patternPhone: patternPhone,
             form: {
                 phone: null,
@@ -150,7 +149,6 @@ export default {
             }
             // 验证码
             this.onCheckPhone()
-            
         },
         checkPhone(phoneNumber) {
             let result = true

+ 113 - 14
src/views/signup/SignUpApi.js

@@ -1,27 +1,18 @@
 import qs from 'qs'
 const axios = require('@/common/axios').default
-const apiPrefix = '/api-auth'
 // 手机号密码方式登录
 export function usernameLogin(data) {
     return axios({
-        url: apiPrefix + '/usernameLogin',
+        url: '/api-auth/usernameLogin',
         method: 'post',
         data: qs.stringify(data)
     })
 }
-// 刷新token
-export function refreshToken(data) {
-    return axios({
-        url: apiPrefix + '/refreshToken',
-        method: 'post',
-        data
-    })
-}
 
 // 发送登录短信验证码
 export function sendSms(data) {
     return axios({
-        url: apiPrefix + '/code/sendSms',
+        url: '/api-auth/code/sendSms',
         method: 'post',
         data: qs.stringify(data)
     })
@@ -30,7 +21,7 @@ export function sendSms(data) {
 // 校验短信验证码
 export function verifySmsCode(data) {
     return axios({
-        url: apiPrefix + '/code/verifySmsCode',
+        url: '/api-auth/code/verifySmsCode',
         method: 'post',
         data: qs.stringify(data)
     })
@@ -39,7 +30,7 @@ export function verifySmsCode(data) {
 // 短信验证码的方式登录
 export function smsLogin(data) {
     return axios({
-        url: apiPrefix + '/smsLogin',
+        url: '/api-auth/smsLogin',
         method: 'post',
         data: qs.stringify(data)
     })
@@ -48,7 +39,115 @@ export function smsLogin(data) {
 // 检查手机号
 export function queryUserByPhone (data) {
     return axios({
-        url: apiPrefix + '/user/noAuth/queryUserByPhone',
+        url: '/api-auth/user/noAuth/queryUserByPhone',
+        method: 'get',
+        params: data
+    })
+}
+
+// 获取考级报名信息
+export function examinationBasicInfo (data) {
+    return axios({
+        url: '/api-user/examinationBasic/getInfo',
+        method: 'post',
+        data: qs.stringify(data)
+    })
+}
+
+// 获取学生信息
+export function getStudent (data) {
+    return axios({
+        url: '/api-user/student/getStudent',
+        method: 'get',
+        params: data
+    })
+}
+
+// 更新学员基本信息
+export function updateStudentInfo (data) {
+    return axios({
+        url: '/api-user/student/updateInfo',
+        method: 'post',
+        data: qs.stringify(data)
+    })
+}
+
+// ocr
+export function ocr (data) {
+    return axios({
+        url: '/api-user/examRegistration/ocr',
+        method: 'post',
+        data: data
+    })
+}
+
+// 上传文件
+export function uploadFile (data) {
+    return axios({
+        url: '/api-user/uploadFile',
+        method: 'post',
+        data: data
+    })
+}
+
+// 获取考试项目专业
+export function getExamSubjects (data) {
+    return axios({
+        url: '/api-user/examSubject/getExamSubjects',
+        method: 'get',
+        params: data
+    })
+}
+
+// 获取考级专业相应级别列表-报名
+export function getExamSubjectLevel (data) {
+    return axios({
+        url: '/api-user/examSubjectSong/getExamSubjectLevel',
+        method: 'get',
+        params: data
+    })
+}
+
+// 获取考级专业相应级别的曲目-报名
+export function getExamSubjectSong (data) {
+    return axios({
+        url: '/api-user/examSubjectSong/getExamSubjectSong',
+        method: 'get',
+        params: data
+    })
+}
+
+// 报名
+export function examRegistrationAdd (data) {
+    return axios({
+        url: '/api-user/examRegistration/add',
+        method: 'post',
+        data: qs.stringify(data)
+    })
+}
+
+// 修改学员报名信息
+export function examRegistrationUpdate (data) {
+    return axios({
+        url: '/api-user/examRegistration/update',
+        method: 'post',
+        data: qs.stringify(data)
+    })
+}
+
+// 修改学员报名信息
+export function getTheoryLevelList (data) {
+    return axios({
+        url: '/api-user/examMusicTheory/getTheoryLevelList',
+        method: 'get',
+        params: data
+    })
+}
+
+// 获取用户项目未支付的订单
+export function getExamIngOrder (data) {
+    return axios({
+        url: '/api-user/examOrder/getExamIngOrder',
         method: 'get',
         params: data
     })

+ 202 - 48
src/views/signup/SignUpBaseInfo.vue

@@ -5,32 +5,43 @@
 
         <!-- <van-form ref="form" :show-error="false" validate-first @submit="onSubmit" @failed="onFailed"> -->
         <div class="title">基本信息</div>
-        <van-field v-model="form.phone" required name="phone" label="身份证号" placeholder="请输入身份证号" :rules="[{ pattern: patternCard, message: '身份证号输入有误' }]" >
+        <van-field v-model="form.idCardNo" readonly required name="idCardNo" label="身份证号" placeholder="请输入身份证号" >
             <template #button>
-                <span class="codeText">上传</span>
+                <!-- <span class="codeText">上传</span> -->
+                <van-uploader :before-read="beforeRead"
+                                :after-read="afterReadOCR"
+                                accept="image/*"
+                                multiple
+                                :max-count="1">
+                    <span class="codeText">上传</span>
+                </van-uploader>
             </template>
         </van-field>
-        <!-- #2DC7AA -->
-        <div class="cardTips">如有括号,请用英文括号()</div>
-        <van-field required v-model="form.phone" name="phone" label="姓名" placeholder="请输入姓名" :rules="[{ required: true, message: '姓名输入有误' }]" />
+        <!-- <div class="cardTips">如有括号,请用英文括号()</div> -->
+        <van-field readonly required v-model="form.realName" name="realName" label="姓名" placeholder="请输入姓名" />
 
-        <van-field name="radio" label="性别">
+        <van-field name="radio" required label="性别">
             <template #input>
-                <van-radio-group v-model="form.sex" direction="horizontal">
-                    <van-radio checked-color="var(--main-color)" :name="1">男</van-radio>
-                    <van-radio checked-color="var(--main-color)" :name="0">女</van-radio>
+                <van-radio-group v-model="form.gender" direction="horizontal">
+                    <van-radio disabled checked-color="var(--main-color)" :name="1">男</van-radio>
+                    <van-radio disabled checked-color="var(--main-color)" :name="0">女</van-radio>
                 </van-radio-group>
             </template>
         </van-field>
 
-        <van-field readonly clickable name="birthday" v-model="form.birthday" label="生日" placeholder="请选择" @click="birthdayStatus = true" is-link />
+        <van-field readonly required name="birthdate" v-model="form.birthdate" label="生日" placeholder="请选择" />
 
-        <van-field readonly clickable name="nation" v-model="form.nation" label="民族" placeholder="请选择" is-link />
+        <van-field readonly required name="nation" v-model="form.nation" label="民族" placeholder="请选择" />
 
         <div class="title">证件照上传</div>
 
         <div class="upload-img">
-            <van-uploader v-model="fileList" multiple :max-count="1" :max-size="3 * 1024 * 1024" >
+            <van-uploader v-model="certificatePhoto" :before-read="beforeRead"
+                                :before-delete="beforeDelete"
+                                :after-read="afterRead"
+                                accept="image/*"
+                                multiple
+                                :max-count="1">
                 <div class="upload-container">
                     <i class="icon-upload-add"></i>
                     <p>点击上传</p>
@@ -39,35 +50,32 @@
             <p class="upload-tips">须使用免冠证件照,纯底色<br/>(纯白、纯蓝或纯红)<br/>(图像预览可能会异常)</p>
         </div>
 
-        <m-button class="step-btn" @click="onSubmit" text="下一步" native-type="submit" />
+        <m-button class="step-btn" @click="onSubmit" text="下一步" />
         <!-- </van-form> -->
-
-        <van-popup v-model="birthdayStatus" position="bottom">
-            <van-datetime-picker
-                type="date"
-                :formatter="formatter"
-                @cancel="birthdayStatus = false"
-                @confirm="onConfirm" />
-        </van-popup>
     </div>
 </template>
 <script>
 import MHeader from '@/components/MHeader'
 import MStep from '@/components/MStep'
 import MButton from '@/components/MButton'
-import { getYMD } from '@/utils/common'
+import setLoading from '@/utils/loading'
+import { getStudent, ocr, uploadFile, updateStudentInfo, getExamIngOrder } from './SignUpApi'
+import dayjs from 'dayjs'
 export default {
     name: 'signupBaseInfo',
 	components: { MHeader, MStep, MButton },
     data () {
+        const examId = localStorage.getItem('examId')
         return {
-            patternCard: /^1(3|4|5|6|7|8|9)\d{9}$/,
-            birthdayStatus: false,
+            examId: examId,
+            certificatePhoto: [],
             form: {
-                phone: null,
-                sex: 1,
-                birthday: null,
-                nation: null
+                idCardNo: null,
+                realName: null,
+                gender: 1,
+                birthdate: null,
+                nation: null,
+                certificatePhoto: null
             },
             fileList: [],
         }
@@ -79,32 +87,172 @@ export default {
         //     localStorage.setItem('Authorization', decodeURI(params.Authorization))
         //     localStorage.setItem('userInfo', decodeURI(params.Authorization))
         // }
+        this.__init()
     },
     methods: {
-        onSubmit() {
-            // console.log('submit', values)
-            this.$router.push({
-                path: '/signUpLevel'
-            })
+        async __init() {
+            setLoading(true)
+            try {
+                const res = await getStudent()
+                if(res.data.code == 200) {
+                    const tempData = res.data.data
+                    this.form = {
+                        idCardNo: tempData.sysUser.idCardNo,
+                        realName: tempData.sysUser.realName,
+                        gender: tempData.sysUser.gender,
+                        birthdate: dayjs(tempData.sysUser.birthdate).format('YYYY-MM-DD'),
+                        nation: tempData.sysUser.nation,
+                        certificatePhoto: tempData.certificatePhoto
+                    }
+                    if(tempData.certificatePhoto) { // 判断是否在头像
+                        this.certificatePhoto = [{url: tempData.certificatePhoto}]
+                    }
+                }
+
+                const order = await getExamIngOrder({ examinationBasicId: this.examId })
+                const resultOrder = order.data
+                if(resultOrder.code == 200 && resultOrder.data) {
+                    this.$dialog.confirm({
+                        title: '提示',
+                        message: "您有待支付订单",
+                        confirmButtonColor: '#269a93',
+                        cancelButtonText: '已完成支付',
+                        confirmButtonText: '重新下单'
+                    }).then(() => {
+                        this.$router.push({
+                            path: '/signUpPayment'
+                        })
+                    }).catch(() => {
+                        this.$dialog.close()
+                    })
+                }
+            } catch(err) {
+                //
+            }
+            setLoading(false)
         },
-        onFailed() {
-            // console.log('failed', errorInfo);
-            // console.log(this.$refs['form'].scrollToField(errorInfo.errors[0].name))
-            // this.$refs['form'].scrollToField(errorInfo.errors[0].name,  false)
+        async onSubmit() {
+            if(!this.onCheckFields()) {
+                return
+            }
+            setLoading(true)
+            try {
+                let res = await updateStudentInfo(this.form)
+                setLoading(false)
+                let result = res.data
+                if(result.code == 200) {
+                    this.$router.push({
+                        path: '/signUpLevel'
+                    })
+                } else {
+                    this.$toast(result.msg)
+                }
+            } catch(err) {
+                //
+            }
+            // this.$router.push({
+            //     path: '/signUpLevel'
+            // })
         },
-        onConfirm(val) {
-            this.form.birthday = getYMD(val, true)
-            this.birthdayStatus = false
+        onCheckFields() { // 校验字段
+            let form = this.form
+            if(!form.idCardNo || !form.realName || !form.birthdate || !form.nation) {
+                this.$toast('请上传身份证正面进行扫描')
+                return false
+            } else if(!form.certificatePhoto) {
+                this.$toast('请上传证件照片')
+                return false
+            }
+            return true
         },
-        formatter(type, val) {
-            if (type === 'year') {
-                return `${val}年`
-            } else if (type === 'month') {
-                return `${val}月`
-            } else if (type === 'day') {
-                return `${val}日`
+        beforeRead(file) {
+            const isLt2M = file.size / 1024 / 1024 < 2
+            if (!isLt2M) {
+                this.$toast('上传证书大小不能超过 2MB')
+                return false
             }
-            return val
+            return true
+        },
+        beforeDelete() {
+            this.form.certificatePhoto = '' // 上传图片地址为空
+            return true
+        },
+        async afterRead(file) { // 上传头像
+            // setLoading(true)
+            try {
+                file.status = 'uploading'
+                file.message = '上传中...'
+                let formData = new FormData()
+                formData.append('file', file.file)
+                let res = await uploadFile(formData)
+                let result = res.data
+                // setLoading(false)
+                if(result.code == 200) {
+                    file.status = 'done'
+                    this.form.certificatePhoto = result.data.url
+                } else {
+                    file.status = 'failed'
+                    file.message = '上传失败'
+                    this.$toast(result.msg)
+                    return false
+                }
+            } catch (err) {
+                return false
+            }
+        },
+        async afterReadOCR(file) { // 上传身份证照片识别
+            setLoading(true)
+            try {
+                let formData = new FormData()
+                formData.append('file', file.file)
+                formData.append('idCardSide', "front")
+                let res = await ocr(formData)
+                let result = res.data
+                setLoading(false)
+                if(result.code == 200) {
+                    this.idCardParse(result.data)
+                } else {
+                    this.$toast(result.msg)
+                    return false
+                }
+            } catch (err) {
+                return false
+            }
+        },
+        idCardParse(data) {
+            // 身份证信息解析
+            let wordsResult = data.words_result
+            let errorText
+            switch (data.image_status) {
+                case "normal":
+                    this.form = {
+                        idCardNo: wordsResult["公民身份号码"].words,
+                        realName: wordsResult["姓名"].words,
+                        gender: wordsResult["性别"].words == '男' ? 1 : 0,
+                        birthdate: dayjs(wordsResult["出生"].words).format('YYYY-MM-DD'),
+                        nation: wordsResult["民族"].words
+                    }
+                    break;
+                case "reversed_side":
+                    errorText = "身份证正反面颠倒"
+                    break;
+                case "non_idcard":
+                    errorText = "上传的图片中不包含身份证"
+                    break;
+                case "blurred":
+                    errorText = "身份证模糊"
+                    break;
+                case "other_type_card":
+                    errorText = "身份证关键字段反光或过曝"
+                    break;
+                case "over_dark":
+                    errorText = "身份证欠曝(亮度过低)"
+                    break;
+                default:
+                    errorText = "上传身份证有误"
+                    break;
+            }
+            errorText && this.$toast(errorText)
         }
     }
 }
@@ -184,4 +332,10 @@ export default {
     padding-top: .03rem;
     padding-bottom: .15rem;
 }
+
+/deep/.van-radio__icon--disabled.van-radio__icon--checked .van-icon {
+    background-color: var(--main-color);
+    border-color: var(--main-color);
+    color: #ffffff;
+}
 </style>

+ 595 - 115
src/views/signup/SignUpLevel.vue

@@ -3,52 +3,100 @@
         <m-header />
         <m-step :number="3" />
 
-        <!-- <van-form ref="form" :show-error="false" validate-first @submit="onSubmit" @failed="onFailed"> -->
-            <div class="title">基本信息</div>
-            <van-field readonly clickable name="nation" label="报考专业" placeholder="请选择" is-link />
-            <van-field readonly clickable name="nation" label="报考级别" placeholder="请选择" is-link />
-            <van-field name="phone" label="报考曲目" placeholder="请输入报考曲目" />
-            <van-field clearable name="code" label="练习曲目名称及作者" placeholder="自定义曲目" >
-                <template #button>
-                    <span class="codeText" @click="songStatus = true">曲目上传</span>
-                </template>
-            </van-field>
-            <van-field name="phone" label="乐曲一名称及作者" placeholder="请输入曲目名称及作者" />
-            <van-field name="phone" label="乐曲二名称及作者" placeholder="请输入曲目名称及作者" />
-
-            <div class="title">上次考级信息</div>
-             <van-field readonly clickable name="nation" label="上次考级级别" placeholder="请选择级别" is-link />
-             <van-field readonly clearable name="code" label="上次考级证书" >
-                <template #button>
-                    <span class="codeText">上传证书</span>
-                </template>
-            </van-field>
-            <div class="title">乐理知识</div>
-            <van-field readonly clickable name="nation" label="专业级别" placeholder="请选择专业级别" is-link />
-            <van-field readonly clickable name="nation" label="上次考级级别" placeholder="请选择" is-link />
-            <van-field readonly clearable name="code" label="上次考级证书" >
-                <template #button>
-                    <span class="codeText">上传证书</span>
-                </template>
-            </van-field>
-            <div class="title">指导老师</div>
-            <van-field name="phone" label="老师姓名" placeholder="请输入老师姓名" />
-            <van-field name="phone" label="联系方式" placeholder="请输入联系方式" />
-            <!-- <m-button class="stepBtn" text="下一步" native-type="submit" /> -->
-            <div class="m-btn-group">
-                <van-button round color="var(--main-color)" @click="onBack" style="background-color: transparent" plain>上一步</van-button>
-                <van-button round color="var(--main-color)" @click="onSubmit">确认报名</van-button>
+        <div class="title">报考专业</div>
+        <van-field readonly required @click="onGetSheetList('examSubject')" name="subjectId" label="报考专业" placeholder="请选择" v-model="formText.subjectName" is-link />
+        <van-field readonly required @click="onGetSheetList('level')" name="levelId" label="报考级别" placeholder="请选择" v-model="formText.levelName" is-link />
+        <div v-if="form.levelId">
+            <div class="title">报考曲目</div>
+
+            <div class="van-hairline--bottom" v-if="practiceSongIdList" key="practiceNum">
+                <van-field required v-for="(item, index) in practiceNum" :key="index" readonly :label="`练习曲${numberToCN(index)}名称及作者`" v-model.trim="practiceSelect[index]" @click="onChangePractice('practice', index)" placeholder="请选择" is-link />
+            </div>
+            <div class="van-hairline--bottom" v-else key="practiceNum">
+                <van-field required v-for="(item, index) in practiceNum" :key="index" clearable name="code" :label="`练习曲${numberToCN(index)}名称及作者`" placeholder="自定义曲目" >
+                    <template #input>
+                        <van-uploader
+                            :name="`practiceNum-${index}`"
+                            :before-read="beforeRead"
+                            :before-delete="beforeDelete"
+                            :after-read="afterRead"
+                            v-model.trim="practiceUpload[index]"
+                            accept="image/*"
+                            multiple
+                            :max-count="1" />
+                    </template>
+                </van-field>
+            </div>
+
+            <div v-if="performSongIdList" key="performNum">
+                <van-field required v-for="(item, index) in performNum" :key="index" readonly :label="`演奏曲${numberToCN(index)}名称及作者`" v-model.trim="performNumSelect[index]" @click="onChangePractice('performNum', index)" placeholder="请选择" is-link />
+            </div>
+            <div v-else key="performNum">
+                <van-field required v-for="(item, index) in performNum" :key="index" clearable name="code" :label="`演奏曲${numberToCN(index)}名称及作者`" placeholder="自定义曲目" >
+                    <template #input>
+                        <van-uploader
+                            :name="`performNum-${index}`"
+                            :before-read="beforeRead"
+                            :before-delete="beforeDelete"
+                            :after-read="afterRead"
+                            v-model.trim="performNumUpload[index]"
+                            accept="image/*"
+                            multiple
+                            :max-count="1" />
+                    </template>
+                </van-field>
             </div>
-        <!-- </van-form> -->
+        </div>
+        <div class="title">上传证书</div>
+            <!-- <van-field readonly clickable name="nation" label="上次考级级别" placeholder="请选择级别" is-link /> -->
+        <van-field readonly clearable name="code" label="上次考级证书" >
+            <template #input>
+                <van-uploader
+                    name="certificate"
+                    :before-read="beforeRead"
+                    :before-delete="beforeDelete"
+                    :after-read="afterRead"
+                    accept="image/*"
+                    v-model="uploadCertificate"
+                    multiple
+                    :max-count="1" />
+            </template>
+        </van-field>
+        <div class="title">乐理知识</div>
+        <van-field required @click="onGetSheetList('examMusicTheory')" readonly clickable name="nation" label="专业级别" v-model="form.examMusicTheoryName" placeholder="请选择专业级别" is-link />
+        <!-- <van-field readonly clickable name="nation" label="上次考级级别" placeholder="请选择" is-link /> -->
+        <van-field readonly :required="form.examMusicTheoryId ? true : false" clearable name="code" label="上次考级证书" >
+            <template #input>
+                <van-uploader
+                    name="certificate2"
+                    :before-read="beforeRead"
+                    :before-delete="beforeDelete"
+                    :after-read="afterRead"
+                    v-model="uploadCertificate2"
+                    accept="image/*"
+                    multiple
+                    :max-count="1" />
+            </template>
+        </van-field>
+        <div class="title">指导老师</div>
+        <van-field name="adviserName" v-model="form.adviserName" label="老师姓名" placeholder="请输入老师姓名" />
+        <van-field name="adviserPhone" maxlength="11" v-model="form.adviserPhone" label="联系方式" placeholder="请输入联系方式" />
+        <div class="m-btn-group">
+            <van-button round color="var(--main-color)" @click="onBack" style="background-color: transparent" plain>上一步</van-button>
+            <van-button round color="var(--main-color)" @click="onSubmit">确认报名</van-button>
+        </div>
+
+        <!-- 报考专业弹窗 -->
+        <van-popup v-model="sheetForm.sheetStatus" position="bottom">
+            <van-picker :loading="sheetForm.loading" :default-index="sheetForm.index" :columns="sheetForm.columns" show-toolbar @cancel="sheetForm.sheetStatus = false" @confirm="onSheetConfirm" />
+        </van-popup>
 
-        <van-popup v-model="birthdayStatus" position="bottom">
-            <van-datetime-picker
-                type="date"
-                @cancel="birthdayStatus = false"/>
-                <!-- @confirm="onConfirm" -->
+        <!-- 曲目弹窗 -->
+        <van-popup v-model="sheetSong.status" position="bottom">
+            <van-picker :default-index="sheetSong.index" :columns="sheetSong.columns" show-toolbar @cancel="sheetSong.status = false" @confirm="onPracticeConfirm" />
         </van-popup>
 
-        <van-popup class="van-popup-song" v-model="songStatus">
+        <!-- <van-popup class="van-popup-song" v-model="songStatus">
             <div class="song-popup">
                 <div class="title">自定义曲目</div>
                 <div class="song-upload">
@@ -66,30 +114,84 @@
                     <span class="popup-sure" @click="songStatus = false">确定</span>
                 </div>
             </div>
-        </van-popup>
+        </van-popup> -->
     </div>
 </template>
 <script>
 import MHeader from '@/components/MHeader'
 import MStep from '@/components/MStep'
-// import MButton from '@/components/MButton'
-// import { browser } from '@/common/common'
+import setLoading from '@/utils/loading'
+import { patternPhone } from '@/utils/validateRules'
+import { getExamSubjects, getExamSubjectLevel, getExamSubjectSong, uploadFile, getTheoryLevelList, examRegistrationAdd, examRegistrationUpdate } from './SignUpApi'
+const levelToCN = {
+    1: "一级",
+    2: "二级",
+    3: "三级",
+    4: "四级",
+    5: "五级",
+    6: "六级",
+    7: "七级",
+    8: "八级",
+    9: "九级",
+    10: "十级",
+}
 export default {
     name: 'signUpLevel',
 	components: { MHeader, MStep },
     data () {
+        const examId = localStorage.getItem('examId')
         return {
-            patternPhone: /^1(3|4|5|6|7|8|9)\d{9}$/,
-            patternPwd: /^[0-9A-Za-z]{6,16}$/,
-            birthdayStatus: false,
+            examId: examId,
+            patternPhone: patternPhone,
+            sheetForm: { // 上拉弹窗
+                currentType: null, // 当前选择的类型
+                sheetStatus: false,
+                loading: false, // 加载数据
+                index: 0, // 选中的索引值
+                columns: []
+            },
+            examSubjectList: [], // 报考专业
+            examSubjectIndex: 0, // 报考专业选择项目索引
+            levelList: [], // 报考级别
+            levelIndex: 0, // 报考级别选择项目索引
+            practiceNum: 0, // 练习曲数量
+            practiceSongIdList: null,
+            performNum: 0, // 演奏曲数量
+            performSongIdList: null,
+            songList: [], //歌曲数量(包括练习曲和演奏曲)
             songStatus: false, // 曲目状态
             form: {
-                phone: null,
-                sex: 1,
-                birthday: null,
-                nation: null
+                subjectId: null,
+                levelId: null,
+                adviserName: null, // 老师姓名
+                adviserPhone: null, // 联系电话
+                lastExamCertificateUrl: null,
+                lastExamCertificateUrl2: null,
+                examMusicTheoryId: null,
+            },
+            formText: {
+                subjectName: null,
+                levelName: null,
+                examMusicTheoryName: null
+            },
+            sheetSong: { // 上拉弹窗
+                status: false,
+                index: 0, // 选中的索引值
+                columns: []
             },
-            fileList: [],
+            practiceSelect: [], // 循环列表
+            practiceSelectIds: [], // 选中练习曲编号
+            performNumSelect: [],
+            performNumSelectIds: [], // 选中演奏曲编号
+            songSelectIndex: null, // 选中的哪个
+            uploadCertificate: [],  // 上传证书
+            uploadCertificate2: [], // 上传乐理证书
+            practiceUpload: [],
+            practiceUploadImg: [],
+            performNumUpload: [],
+            performNumUploadImg: [],
+            examMusicTheoryList: [], // 乐理列表
+            examMusicTheoryIndex: 0, // 乐理索引
         }
     },
     mounted() {
@@ -99,31 +201,403 @@ export default {
         //     localStorage.setItem('Authorization', decodeURI(params.Authorization))
         //     localStorage.setItem('userInfo', decodeURI(params.Authorization))
         // }
+        this.__init()
+        // this.form.levelId = 1
+        // this.practiceNum = 2
+        // this.practiceSongIdList = ""
+        // this.performNum = 2
+        // this.performSongIdList = ""
+        // this.getExamSubjectSong()
     },
     methods: {
-        onSubmit() {
-            // console.log('submit', values)
+        async __init() {
+            setLoading(true)
+            try {
+                // 获取报考专业
+                const res = await getExamSubjects({ examId: this.examId })
+                const result = res.data
+                if(result.code == 200 && result.data.length > 0) {
+                    let tempArr = []
+                    result.data.forEach(item => {
+                        item.value = item.id
+                        item.text = item.name
+                        tempArr.push(item)
+                    })
+                    this.examSubjectList = tempArr
+                }
+
+                const resTheory = await getTheoryLevelList({ examId: this.examId })
+                const resultTheory = resTheory.data
+                if(resultTheory.code == 200 && resultTheory.data.length > 0) {
+                    let tempArr2 = []
+                    resultTheory.data.forEach(item => {
+                        item.value = item.id
+                        item.text = levelToCN[item.level]
+                        tempArr2.push(item)
+                    })
+                    this.examMusicTheoryList = tempArr2
+                }
+            } catch(err) {
+                //
+            }
+            setLoading(false)
+        },
+        onGetSheetList(type) {
+            let sheetForm = this.sheetForm
+            let form = this.form
+            sheetForm.columns = []
+            sheetForm.currentType = type
+            sheetForm.index = 0
+            // 报考专业
+            if(type === "examSubject") {
+                if(this.examSubjectList.length > 0) {
+                    sheetForm.sheetStatus = true
+                    sheetForm.columns = this.examSubjectList
+                    sheetForm.index = this.examSubjectIndex
+                } else {
+                    this.$toast("暂无报考专业")
+                    return
+                }
+            } else if(type === "level") {
+                if(!form.subjectId) {
+                    this.$toast("请选择报考专业")
+                    return
+                }
+                if(this.levelList.length > 0) {
+                    sheetForm.sheetStatus = true
+                    sheetForm.columns = this.levelList
+                    sheetForm.index = this.levelIndex
+                } else {
+                    this.$toast("暂无报考级别")
+                    return
+                }
+            } else if(type == "examMusicTheory") {
+                if(this.examMusicTheoryList.length > 0) {
+                    sheetForm.sheetStatus = true
+                    sheetForm.columns = this.examMusicTheoryList
+                    sheetForm.index = this.examMusicTheoryIndex
+                } else {
+                    this.$toast("暂无乐理专业级别")
+                    return
+                }
+            }
+        },
+        onSheetConfirm(value, index) {
+            let sheetForm = this.sheetForm,
+                form = this.form,
+                formText = this.formText
+            if(!value) { // 判断是否在选中的值
+                sheetForm.sheetStatus = false
+                return
+            }
+            if(sheetForm.currentType == "examSubject") {
+                if(form.subjectId != value.examSubjectId) {
+                    form.subjectId = value.examSubjectId
+                    formText.subjectName = value.name
+                    this.examSubjectIndex = index
+
+                    // 清除报考级别
+                    form.levelId = null
+                    formText.levelName = null
+                    this.levelIndex = 0
+                    this.practiceNum = 0 // 练习曲数量
+                    this.practiceSongIdList = null
+                    this.performNum = 0 // 演奏曲数量
+                    this.performSongIdList = null
+                    this.getExamSubjectLevel() // 请求报考级别
+                }
+                sheetForm.sheetStatus = false
+            } else if(sheetForm.currentType == 'level') {
+                form.levelId = value.value
+                formText.levelName = value.text
+                this.levelIndex = index
+                this.practiceNum = value.practiceNum
+                this.practiceSongIdList = value.practiceSongIdList
+                this.performNum = value.performNum
+                this.performSongIdList = value.performSongIdList
+                sheetForm.sheetStatus = false
+                this.getExamSubjectSong()
+            } else if(sheetForm.currentType == "examMusicTheory") {
+                form.examMusicTheoryId = value.value
+                form.examMusicTheoryName = value.text
+                this.examMusicTheoryIndex = index
+                sheetForm.sheetStatus = false
+            }
+        },
+        async getExamSubjectLevel() {
+            setLoading(true)
+            try {
+                const form = this.form
+                const res = await getExamSubjectLevel({ examSubjectId: form.subjectId, examinationBasicId: this.examId })
+                const result = res.data
+                if(result.code == 200 && result.data.length > 0) {
+                    let tempArr = []
+                    result.data.forEach(item => {
+                        item.value = item.level
+                        item.text = levelToCN[item.level]
+                        tempArr.push(item)
+                    })
+                    this.levelList = tempArr
+                }
+            } catch(err) {
+                //
+            }
+            setLoading(false)
+        },
+        async getExamSubjectSong() {
+            setLoading(true)
+            try {
+                const form = this.form
+                const params = {
+                    // examSubjectId: form.subjectId,
+                    // examinationBasicId: this.examId,
+                    // level: form.levelId
+                    examSubjectId: 5,
+                    examinationBasicId: 6,
+                    level: 1
+                }
+                const res = await getExamSubjectSong(params)
+                const result = res.data
+                if(result.code == 200 && result.data.length > 0) {
+                    let tempArr = []
+                    result.data.forEach(item => {
+                        item.value = item.id
+                        item.text = item.songName + '-' + item.songAuthor
+                        tempArr.push(item)
+                    })
+                    this.songList = tempArr
+                }
+            } catch(err) {
+                //
+            }
+            setLoading(false)
+        },
+        onChangePractice(type, index) {
+            let songList = this.songList
+            // console.log(songList)
+            let sheetSong = this.sheetSong
+            sheetSong.columns = []
+            sheetSong.index = 0
+            let tempPracticeArr = [],
+                tempPerformArr = []
+            songList.forEach(item => {
+                if(item.type == "PERFORM") {
+                    if(this.performNumSelectIds.includes(item.id)) {
+                        item.disabled = true
+                    } else {
+                        item.disabled = false
+                    }
+                    tempPerformArr.push(item)
+                } else if(item.type == "PRACTICE") {
+                    if(this.practiceSelectIds.includes(item.id)) {
+                        item.disabled = true
+                    } else {
+                        item.disabled = false
+                    }
+                    tempPracticeArr.push(item)
+                }
+            })
+            if(type == 'practice') {
+                sheetSong.columns = tempPracticeArr
+            } else if(type == 'performNum') {
+                sheetSong.columns = tempPerformArr
+            }
+            this.songSelectIndex = index
+            sheetSong.status = true
+            // console.log(sheetSong)
+            // if(this.examSubjectList.length > 0) {
+            //     sheetForm.sheetStatus = true
+            //     sheetForm.columns = this.examSubjectList
+            //     sheetForm.index = this.examSubjectIndex
+            // } else {
+            //     this.$toast("暂无报考专业")
+            //     return
+            // }
+        },
+        onPracticeConfirm(value) {
+            // 没有内容
+            if(!value) {
+                return
+            }
+            let songSelectIndex = this.songSelectIndex
+            if(value.type == "PRACTICE") { // 练习
+                this.practiceSelect[songSelectIndex] = value.text
+                this.practiceSelectIds[songSelectIndex] = value.value
+            } else if(value.type == "PERFORM") { // 演奏
+                this.performNumSelect[songSelectIndex] = value.text
+                this.performNumSelectIds[songSelectIndex] = value.value
+            }
+
+            this.sheetSong.status = false
+        },
+        beforeRead(file) {
+            const isLt2M = file.size / 1024 / 1024 < 2
+
+            if (!isLt2M) {
+                this.$toast('上传证书大小不能超过 2MB')
+                return false
+            }
+            return true
+        },
+        beforeDelete(file, detail) {
+            let form = this.form
+            if(detail.name == "certificate2") {
+                form.lastExamCertificateUrl2 = "" // 上传图片地址为空
+            } else if(detail.name == "certificate") {
+                form.lastExamCertificateUrl = ""
+            }
+            return true
+        },
+        async afterRead(file, detail) { // 上传头像
+            const obj = detail.name.split('-')
+            try {
+                file.status = 'uploading'
+                file.message = '上传中...'
+                let formData = new FormData()
+                formData.append('file', file.file)
+                let res = await uploadFile(formData)
+                let result = res.data
+                if(result.code == 200) {
+                    file.status = 'done'
+                    let form = this.form
+                    if(obj[0] == "certificate2") {
+                        form.lastExamCertificateUrl2 = result.data.url // 上传图片地址为空
+                    } else if(obj[0] == "certificate") {
+                        form.lastExamCertificateUrl = result.data.url
+                    } else if(obj[0] == 'practiceNum') {
+                        this.practiceUploadImg[obj[1]] = result.data.url
+                    } else if(obj[0] == 'performNum') {
+                        this.performNumUploadImg[obj[1]] = result.data.url
+                    }
+                } else {
+                    file.status = 'failed'
+                    file.message = '上传失败'
+                    this.$toast(result.msg)
+                    return false
+                }
+            } catch (err) {
+                return false
+            }
+        },
+        async onSubmit() {
+            // setLoading(true)
             this.$router.push({
-                path: '/SignUpPayment'
+                path: '/signUpPayment'
             })
+            try {
+                // 验证
+                if(!this.onCheckFields()) {
+                    return
+                }
+                let form = this.form,
+                    formText = this.formText
+                let params = {
+                    adviserName: form.adviserName,
+                    adviserPhone: form.adviserPhone,
+                    examMusicTheoryId: form.examMusicTheoryId,
+                    examMusicTheoryLevel: formText.examMusicTheoryName,
+                    examSubjectSongId: form.subjectId,
+                    examinationBasicId: this.examId,
+                    lastExamCertificateUrl: form.lastExamCertificateUrl,
+                    level: form.levelId
+                }
+                console.log("参数", params)
+                let res = await examRegistrationAdd(params)
+                setLoading(false)
+                let result = res.data
+                if(result.code == 200) {
+                    //
+                } else {
+                    this.$toast(result.msg)
+                }
+            } catch(err) {
+                //
+            }
+        },
+        onCheckFields() {
+            // 校验数据
+            let form = this.form
+            if(!form.subjectId) {
+                this.$toast('请选择报考专业')
+                return false
+            }
+
+            if(!form.levelId) {
+                this.$toast('请选择报考级别')
+                return false
+            }
+            // 有值说明是列表
+            if(this.practiceSongIdList) {
+                if(this.practiceSelectIds.length != this.practiceNum) {
+                    this.$toast('请选择练习曲')
+                    return false
+                }
+            } else {
+                if(this.practiceUploadImg.length != this.practiceNum) {
+                    this.$toast('请上传练习曲')
+                    return false
+                }
+            }
+
+            if(this.performSongIdList) {
+                if(this.performNumSelectIds.length != this.performNum) {
+                    this.$toast('请选择演奏曲')
+                    return false
+                }
+            } else {
+                if(this.performNumUploadImg.length != this.performNum) {
+                    this.$toast('请上传演奏曲')
+                    return false
+                }
+            }
+
+            if(!form.examMusicTheoryId) {
+                this.$toast('请选择乐理专业级别')
+                return false
+            }
+
+            if(form.examMusicTheoryId > 1 && !form.lastExamCertificateUrl2) {
+                this.$toast('请上传考级证书')
+                return false
+            }
+
+            if(form.adviserPhone && !this.checkPhone(form.adviserPhone)) {
+                return false
+            }
+            return true
         },
-        onFailed() {
-            // console.log('failed', errorInfo);
-            // console.log(this.$refs['form'].scrollToField(errorInfo.errors[0].name))
-            // this.$refs['form'].scrollToField(errorInfo.errors[0].name,  false)
+        checkPhone(phoneNumber) {
+            let result = true
+            if(!(this.patternPhone.test(phoneNumber))){
+                this.$toast('联系方式输入有误')
+                result = false
+            }
+            return result
         },
-        onBack() {
+        onBack() { // 上一步
             window.history.go(-1)
+        },
+        numberToCN (value) {
+            const tempNumber = {
+                0: '一',
+                1: '二',
+                2: '三',
+                3: '四',
+                4: '五',
+            }
+            return tempNumber[value]
         }
     }
 }
 </script>
 <style lang="less" scoped>
 .signUpLevel {
-    height: 100vh;
+    // height: 100vh;
+    padding-bottom: 1rem;
     overflow-y: auto;
     overflow-x: hidden;
     background-color: var(--main-bg-color);
+    position: relative;
     .title {
         font-size: .16rem;
         color: var(--font-second-color);
@@ -147,64 +621,70 @@ export default {
     }
 }
 
-.van-popup-song {
-    width: 80%;
-    border-radius: .08rem;
-}
-.song-popup {
-    text-align: center;
-    .title {
-        font-size: 18px;
-        font-weight: 500;
-        color: var(--font-main-color);
-        padding: .2rem 0 .24rem;
-    }
-    .song-upload {
-        margin: 0 .5rem;
-        padding: .18rem 0 .1rem;
-        border-radius: .05rem;
-        // border: 1px dashed #777777;
-        border: 1px dashed transparent;
-        // background: linear-gradient(wihte, wihte);
-        background: linear-gradient(0deg, transparent 6px, #777777 6px) repeat-y,
-            linear-gradient(0deg, transparent 50%, #777777 0) repeat-y,
-            linear-gradient(90deg, transparent 50%, #777777 0) repeat-x,
-            linear-gradient(90deg, transparent 50%, #777777 0) repeat-x;
-        background-size: 1px 12px, 1px 12px, 12px 1px, 12px 1px;
-        background-position: 0 0, 100% 0, 0 0, 0 100%;
-        font-size: .16rem;
-        color: #777;
-    }
-    .song-popup-tips {
-        font-size: .14rem;
-        color: #808080;
-        padding-top: .1rem;
-        padding-bottom: .25rem;
-    }
-    .popup-group {
-        width: 100%;
-        display: flex;
-        color: var(--main-color);
-        background-color: #F0F0F0;
-        font-size: .18rem;
-        span {
-            padding: .12rem 0;
-            flex: 1;
-        }
-        .popup-sure {
-            color: #ffffff;
-            background-color: var(--main-color);
-        }
-    }
-}
+// .van-popup-song {
+//     width: 80%;
+//     border-radius: .08rem;
+// }
+// .song-popup {
+//     text-align: center;
+//     .title {
+//         font-size: 18px;
+//         font-weight: 500;
+//         color: var(--font-main-color);
+//         padding: .2rem 0 .24rem;
+//     }
+//     .song-upload {
+//         margin: 0 .5rem;
+//         padding: .18rem 0 .1rem;
+//         border-radius: .05rem;
+//         // border: 1px dashed #777777;
+//         border: 1px dashed transparent;
+//         // background: linear-gradient(wihte, wihte);
+//         background: linear-gradient(0deg, transparent 6px, #777777 6px) repeat-y,
+//             linear-gradient(0deg, transparent 50%, #777777 0) repeat-y,
+//             linear-gradient(90deg, transparent 50%, #777777 0) repeat-x,
+//             linear-gradient(90deg, transparent 50%, #777777 0) repeat-x;
+//         background-size: 1px 12px, 1px 12px, 12px 1px, 12px 1px;
+//         background-position: 0 0, 100% 0, 0 0, 0 100%;
+//         font-size: .16rem;
+//         color: #777;
+//     }
+//     .song-popup-tips {
+//         font-size: .14rem;
+//         color: #808080;
+//         padding-top: .1rem;
+//         padding-bottom: .25rem;
+//     }
+//     .popup-group {
+//         width: 100%;
+//         display: flex;
+//         color: var(--main-color);
+//         background-color: #F0F0F0;
+//         font-size: .18rem;
+//         span {
+//             padding: .12rem 0;
+//             flex: 1;
+//         }
+//         .popup-sure {
+//             color: #ffffff;
+//             background-color: var(--main-color);
+//         }
+//     }
+// }
 
+/deep/.van-uploader__upload {
+    margin-bottom: 0;
+}
 
 .m-btn-group {
-    margin-top: .35rem;
-    margin-bottom: .25rem;
-    padding: 0 .2rem;
+    position: fixed;
+    bottom: 0;
+    width: calc(100% - .4rem);
+    padding: .1rem .2rem;
     display: flex;
     justify-content: space-between;
+    background-color: #fff;
+    box-shadow:0px -1px 4px 0px rgba(226,226,226,1);
     .van-button {
         font-size: .18rem;
         height: .5rem;

+ 17 - 22
src/views/signup/SignUpPayment.vue

@@ -28,7 +28,7 @@
                 <template #default>姜杰城航天桥分部</template>
             </van-cell>
             <van-cell title="报名费用:" :border="false">
-                <template #default>¥480.00</template>
+                <template #default>¥{{ payMoney }}</template>
             </van-cell>
         </van-cell-group>
 
@@ -38,35 +38,29 @@
 
         <div class="pay-group">
             <div class="pay-amount">
-                <span>¥</span>480.00
+                <span>¥</span>{{ payMoney }}
             </div>
             <div class="pay-btn">
-                <van-button color="var(--main-color)" round>确认并支付</van-button>
+                <van-button color="var(--main-color)" @click="onSubmit" round>确认并支付</van-button>
             </div>
         </div>
+
+        <m-payment :closeStatus="isStatus" :amount="Number(payMoney)" :payment="payment" @onChangeStatus="onChangeStatus" />
     </div>
 </template>
 <script>
 import MHeader from '@/components/MHeader'
 import MStep from '@/components/MStep'
-// import MButton from '@/components/MButton'
-// import { browser } from '@/common/common'
+import MPayment from '@/components/MPayment'
+import { changeTwoDecimal } from '@/utils/common'
 export default {
     name: 'signupPayment',
-	components: { MHeader, MStep },
+	components: { MHeader, MStep, MPayment },
     data () {
         return {
-            patternPhone: /^1(3|4|5|6|7|8|9)\d{9}$/,
-            patternPwd: /^[0-9A-Za-z]{6,16}$/,
-            birthdayStatus: false,
-            songStatus: false, // 曲目状态
-            form: {
-                phone: null,
-                sex: 1,
-                birthday: null,
-                nation: null
-            },
-            fileList: [],
+            payMoney: changeTwoDecimal(480),
+            isStatus: false,
+			payment: {}, // 支付对象
         }
     },
     mounted() {
@@ -78,13 +72,14 @@ export default {
         // }
     },
     methods: {
+        onChangeStatus(val) {
+            this.isStatus = val
+        },
         onSubmit() {
             // console.log('submit', values)
-        },
-        onFailed() {
-            // console.log('failed', errorInfo);
-            // console.log(this.$refs['form'].scrollToField(errorInfo.errors[0].name))
-            // this.$refs['form'].scrollToField(errorInfo.errors[0].name,  false)
+            this.payment = {}
+            // 开始支付窗口
+            this.isStatus = true
         }
     }
 }

+ 5 - 35
vue.config.js

@@ -1,11 +1,9 @@
 const path = require('path')
 
-// let targetUrl = 'http://admin.dayaedu.com'
-let targetUrl = 'http://192.168.3.28:8000/'
-// let targetUrl = 'http://192.168.3.27:8000' // 箭河
+let targetUrl = 'http://kjtest.dayaedu.com'
+// let targetUrl = 'http://192.168.3.28:8000/'
+// let targetUrl = 'http://192.168.3.139:8000' // 箭河
 // let targetUrl = 'http://192.168.3.48:8000'
-// let targetUrl = 'http://testadm.dayaedu.com/'
-// let targetUrl = 'https://mstuonline.dayaedu.com'
 // let version = '1.0.0'
 // webpack.prod.conf.js
 // const Version = new Date().getTime();
@@ -94,32 +92,11 @@ module.exports = {
     hotOnly: false,
     // 查阅 https://github.com/vuejs/vue-doc-zh-cn/vue-cli/cli-service.md#配置代理
     proxy: {
-      '/contracts': {
+      '/api-user': {
         target: targetUrl,
         changeOrigin: true,
         ws: true,
-        '^/contracts': '/contracts',
-        xfwd: true
-      },
-      '/student-server': {
-        target: targetUrl,
-        changeOrigin: true,
-        ws: true,
-        '^/student-server': '/student-server',
-        xfwd: true
-      },
-      '/api-cms': {
-        target: targetUrl,
-        changeOrigin: true,
-        ws: true,
-        '^/api-cms': '/api-cms',
-        xfwd: true
-      },
-      '/api-student': {
-        target: targetUrl,
-        changeOrigin: true,
-        ws: true,
-        '^/api-student': '/api-student',
+        '^/api-user': '/api-user',
         xfwd: true
       },
       '/api-auth': {
@@ -128,13 +105,6 @@ module.exports = {
         ws: true,
         '^/api-auth': '/api-auth',
         xfwd: true
-      },
-      '/musicGroup': {
-        target: targetUrl,
-        changeOrigin: true,
-        ws: true,
-        '^/musicGroup': '/musicGroup',
-        xfwd: true
       }
     }, // string | Object
   },