index.tsx 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186
  1. import {
  2. Image,
  3. Cell,
  4. CellGroup,
  5. Tag,
  6. Button,
  7. Stepper,
  8. Icon,
  9. Popup,
  10. showConfirmDialog,
  11. showToast,
  12. Form,
  13. Field,
  14. CountDown,
  15. RadioGroup,
  16. Radio,
  17. Picker
  18. } from 'vant';
  19. import {
  20. computed,
  21. defineComponent,
  22. nextTick,
  23. onMounted,
  24. reactive,
  25. ref
  26. } from 'vue';
  27. import qs from 'query-string';
  28. import { state as baseState, setLogin, setLoginInit } from '@/state';
  29. import styles from './index.module.less';
  30. import MSticky from '@/components/m-sticky';
  31. // import MVideo from '@/components/m-video';
  32. import { useRoute, useRouter } from 'vue-router';
  33. import { useStudentRegisterStore } from '@/store/modules/student-register-store';
  34. import request from '@/helpers/request';
  35. import { browser, checkPhone, moneyFormat } from '@/helpers/utils';
  36. import deepClone from '@/helpers/deep-clone';
  37. import OWxTip from '@/components/m-wx-tip';
  38. import MDialog from '@/components/m-dialog';
  39. // import f1 from './images/new/f-1.png';
  40. // import f2 from './images/new/f-2.png';
  41. // import f3 from './images/new/f-3.png';
  42. // import iconTip2 from './images/new/icon-tip2.png';
  43. // import functionBg from './images/new/function-bg.png';
  44. import giftTip from './images/new/icon-4.png';
  45. import iconGift from './images/new/icon-gift.png';
  46. import dayjs from 'dayjs';
  47. // import MMessageTip from '@/components/m-message-tip';
  48. import { CurrentTime, useCountDown } from '@vant/use';
  49. import Payment from '../adapay/payment';
  50. import QrcodePayment from './qrcode-payment';
  51. import MImgCode from '@/components/m-img-code';
  52. import { beforeSubmit } from './order-state';
  53. const classList: any = [];
  54. for (let i = 1; i <= 40; i++) {
  55. classList.push({ text: i + '班', value: i });
  56. }
  57. const GRADE_ENUM = {
  58. '1': '一年级',
  59. '2': '二年级',
  60. '3': '三年级',
  61. '4': '四年级',
  62. '5': '五年级',
  63. '6': '六年级',
  64. '7': '七年级',
  65. '8': '八年级',
  66. '9': '九年级'
  67. } as any;
  68. const getGradeList = (gradeYear: string) => {
  69. let tempList: any = [];
  70. const five = [
  71. { text: '一年级', value: 1 },
  72. { text: '二年级', value: 2 },
  73. { text: '三年级', value: 3 },
  74. { text: '四年级', value: 4 },
  75. { text: '五年级', value: 5 }
  76. ];
  77. const one = [{ text: '六年级', value: 6 }];
  78. const three = [
  79. { text: '七年级', value: 7 },
  80. { text: '八年级', value: 8 },
  81. { text: '九年级', value: 9 }
  82. ];
  83. if (gradeYear === 'FIVE_YEAR_SYSTEM') {
  84. tempList.push(...[...five]);
  85. } else if (gradeYear === 'SIX_YEAR_SYSTEM') {
  86. tempList.push(...[...five, ...one]);
  87. } else if (gradeYear === 'THREE_YEAR_SYSTEM') {
  88. tempList.push(...[...three]);
  89. } else if (gradeYear === 'FORE_YEAR_SYSTEM') {
  90. tempList.push(...[...one, ...three]);
  91. } else {
  92. tempList.push(...[...five, ...one, ...three]);
  93. }
  94. return tempList;
  95. };
  96. export default defineComponent({
  97. name: 'student-register',
  98. setup() {
  99. const route = useRoute();
  100. const studentRegisterStore = useStudentRegisterStore();
  101. const router = useRouter();
  102. // 初始化学校编号
  103. studentRegisterStore.setShoolId(route.query.sId as any);
  104. const countDownRef = ref();
  105. const forms = reactive({
  106. schoolId: route.query.sId as any,
  107. paymentType: '', // 支付类型
  108. // popupShow: false,
  109. details: [] as any[],
  110. // schoolType: '', // 学校类型
  111. gradeYear: '', // 学制
  112. // bugGoods: false, // 是否购买AI
  113. registerType: '', // 报名类型
  114. detailVip: {} as any,
  115. giftVipDay: 0, // 赠送天数
  116. submitLoading: false,
  117. // showMore: true,
  118. showTips: false,
  119. showButton: false,
  120. showMessage: '请使用微信打开',
  121. countDownStatus: true,
  122. countDownTime: 1000 * 120, // 倒计时时间
  123. // modelValue: false, // 是否选中协议
  124. imgCodeStatus: false,
  125. gradeNumText: '',
  126. currentClassText: '',
  127. gradeStatus: false,
  128. classStatus: false,
  129. loading: false,
  130. dialogStatus: false,
  131. dialogMessage: '',
  132. dialogConfirmStatus: false,
  133. contract_sign: false, // 是否实名认证
  134. countDownTimePay: 60 * 1000,
  135. dialogConfig: {} as any,
  136. showOtherSchool: false,
  137. showOtherMessage: '',
  138. joinType: '' as 'digitalize' | 'tradition',
  139. gradeList: [] as any,
  140. classList: [] as any
  141. });
  142. const state = reactive({
  143. showQrcode: false,
  144. qrCodeUrl: '',
  145. pay_channel: '',
  146. orderInfo: {} as any, // 订单信息
  147. authShow: false,
  148. orderNo: null as any,
  149. config: {} as any,
  150. paymentStatus: false,
  151. orderTimer: null as any
  152. });
  153. const studentInfo = reactive({
  154. autoRegister: true,
  155. client_id: 'cooleshow-student',
  156. client_secret: 'cooleshow-student',
  157. extra: {
  158. nickname: '',
  159. currentGradeNum: '',
  160. currentClass: '',
  161. gender: 1,
  162. registerType: null as any, // 报名类型
  163. giftVipDay: 0 // 赠送会员天数
  164. },
  165. grant_type: 'password',
  166. loginType: 'SMS',
  167. password: '',
  168. username: ''
  169. });
  170. const countDown = useCountDown({
  171. // 倒计时 60 秒
  172. time: forms.countDownTimePay,
  173. onChange(current: CurrentTime) {
  174. forms.dialogMessage = `有待支付订单,请在${Math.ceil(
  175. current.total / 1000
  176. )}s后重试`;
  177. },
  178. onFinish() {
  179. forms.dialogStatus = false;
  180. }
  181. });
  182. const onCodeSend = () => {
  183. forms.countDownStatus = false;
  184. nextTick(() => {
  185. countDownRef.value.start();
  186. });
  187. };
  188. const onSendCode = () => {
  189. // 发送验证码
  190. if (!checkPhone(studentInfo.username)) {
  191. return showToast('请输入正确的手机号码');
  192. }
  193. forms.imgCodeStatus = true;
  194. };
  195. const validatePhone = computed(() => {
  196. return checkPhone(studentInfo.username) ? true : false;
  197. });
  198. const onFinished = () => {
  199. forms.countDownStatus = true;
  200. countDownRef.value.reset();
  201. };
  202. const orderType = computed(() => {
  203. return state.orderInfo.orderType;
  204. });
  205. const getRegisterGoods = async () => {
  206. try {
  207. const { data } = await request.get(
  208. '/edu-app/open/userOrder/registerGoods/' + forms.schoolId,
  209. {
  210. noAuthorization: true // 是否请求接口的时候添加toekn
  211. }
  212. );
  213. // 默认选中商品
  214. studentRegisterStore.setVip(data.details || []);
  215. forms.details = deepClone(data.details || []);
  216. if (forms.details.length > 0) {
  217. forms.detailVip = forms.details[0];
  218. // forms.giftVipDay = forms.details[0].membershipDays;
  219. }
  220. forms.giftVipDay = data.giftVipDay || 0;
  221. forms.gradeYear = data.gradeYear;
  222. forms.registerType = data.registerType;
  223. studentInfo.extra.registerType = data.registerType;
  224. const schoolInstrumentList = data.schoolInstrumentList || [];
  225. if (data.schoolInstrumentSetType === 'SCHOOL') {
  226. forms.gradeList = getGradeList(data.gradeYear);
  227. forms.classList = classList;
  228. } else if (data.schoolInstrumentSetType === 'GRADE') {
  229. schoolInstrumentList.forEach((item: any) => {
  230. forms.gradeList.push({
  231. text: GRADE_ENUM[item.gradeNum],
  232. value: item.gradeNum,
  233. instrumentId: item.instrumentId
  234. });
  235. });
  236. forms.classList = classList;
  237. } else if (data.schoolInstrumentSetType === 'CLASS') {
  238. // 班级
  239. const tempGradeList: any[] = [];
  240. schoolInstrumentList.forEach((item: any) => {
  241. if (!tempGradeList.includes(item.gradeNum)) {
  242. tempGradeList.push(item.gradeNum);
  243. }
  244. });
  245. const lastGradeList: any[] = [];
  246. tempGradeList.forEach((temp: any) => {
  247. const list = {
  248. text: GRADE_ENUM[temp],
  249. value: temp,
  250. children: [] as any
  251. };
  252. schoolInstrumentList.forEach((item: any) => {
  253. if (item === item.gradeNum) {
  254. list.children.push({
  255. text: item.classNum + '班',
  256. value: item.classNum
  257. });
  258. }
  259. });
  260. lastGradeList.push(list);
  261. });
  262. forms.gradeList = lastGradeList;
  263. forms.classList = [];
  264. }
  265. if (browser().weixin) {
  266. // if (
  267. // data.schoolStatus === 0 &&
  268. // forms.schoolId == '1770035687490105346'
  269. // ) {
  270. // forms.showTips = true;
  271. // forms.showMessage = '团购时间已截止,感谢您的参与';
  272. // forms.showButton = false;
  273. // return;
  274. // }
  275. if (data.registerType !== 'BUG_GOODS' || data.schoolStatus === 0) {
  276. forms.showTips = true;
  277. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  278. forms.showButton = false;
  279. return;
  280. }
  281. } else {
  282. forms.showTips = true;
  283. }
  284. } catch {}
  285. };
  286. // 计算金额
  287. const calcPrice = computed(() => {
  288. let amount: number = 0; //现价
  289. let originAmount: number = 0; // 原价
  290. const vipList: any[] = studentRegisterStore.getVip;
  291. vipList.forEach((vip: any) => {
  292. amount += Number(vip.currentPrice);
  293. originAmount += Number(vip.originalPrice);
  294. });
  295. // const goodsList: any[] = studentRegisterStore.getGoods;
  296. // goodsList.forEach((good: any) => {
  297. // amount += Number(good.price) * good.quantity;
  298. // originAmount += Number(good.originalPrice) * good.quantity;
  299. // });
  300. return {
  301. amount,
  302. originAmount
  303. };
  304. });
  305. const checkForm = () => {
  306. if (!checkPhone(studentInfo.username)) {
  307. showToast('请输入正确的手机号码');
  308. return true;
  309. } else if (!studentInfo.password) {
  310. showToast('请输入验证码');
  311. return true;
  312. } else if (!studentInfo.extra.nickname) {
  313. showToast('请输入学生姓名');
  314. return true;
  315. } else if (!studentInfo.extra.currentGradeNum) {
  316. showToast('请选择所在年级');
  317. return true;
  318. } else if (!studentInfo.extra.currentClass) {
  319. showToast('请选择所在班级');
  320. return true;
  321. }
  322. return false;
  323. };
  324. // 登记成功之后购买
  325. const onSubmit = async () => {
  326. forms.submitLoading = true;
  327. try {
  328. if (checkForm()) return;
  329. const { extra, ...res } = studentInfo;
  330. const result = await request.post('/edu-app/userlogin', {
  331. requestType: 'form',
  332. data: {
  333. ...res,
  334. extra: JSON.stringify({
  335. ...extra,
  336. giftVipDay:
  337. forms.detailVip.membershipDays || 0 + forms.giftVipDay || 0,
  338. schoolId: forms.schoolId
  339. })
  340. }
  341. });
  342. if (result.code !== 200) {
  343. if (result.code === 5436) {
  344. forms.showTips = true;
  345. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  346. forms.showButton = false;
  347. } else if (result.code === 5435) {
  348. forms.showTips = true;
  349. forms.showMessage = result.message;
  350. forms.showButton = true;
  351. } else if (result.code === 5435) {
  352. forms.showTips = true;
  353. forms.showMessage = result.message;
  354. forms.showButton = false;
  355. }
  356. } else {
  357. studentRegisterStore.setToken(
  358. result.data.token_type + ' ' + result.data.access_token
  359. );
  360. setLoginInit();
  361. // 传统方式
  362. if (forms.joinType === 'tradition') {
  363. setTimeout(() => {
  364. showToast('报名成功');
  365. router.push('/download');
  366. }, 100);
  367. return;
  368. }
  369. // 获取用户信息
  370. const res = await request.get('/edu-app/user/getUserInfo', {
  371. requestType: 'form'
  372. });
  373. setLogin(res.data);
  374. await onRegisterSubmit();
  375. }
  376. } finally {
  377. }
  378. forms.submitLoading = false;
  379. };
  380. // 登记成功之后购买
  381. const onRegisterSubmit = async () => {
  382. try {
  383. // 请求是否有待支付订单,如果有则自动关闭
  384. const status = await paymentOrderUnpaid();
  385. if (status) return;
  386. const schoolInfo = await request.get(
  387. '/edu-app/userPaymentOrder/registerStatus/' + forms.schoolId
  388. );
  389. const vipList = studentRegisterStore.getVip;
  390. if (schoolInfo.data.hasBuyCourse && vipList.length > 0) {
  391. forms.dialogConfirmStatus = true;
  392. return;
  393. }
  394. await paymentContinue();
  395. } catch {
  396. //
  397. }
  398. };
  399. const getUserInfos = async () => {
  400. if (
  401. studentInfo.password.length !== 6 ||
  402. !checkPhone(studentInfo.username)
  403. ) {
  404. return;
  405. }
  406. try {
  407. // 15907120131;
  408. const { data } = await request.get(
  409. `/edu-app/open/student/studentInfo?mobile=${studentInfo.username}&code=${studentInfo.password}&type=REGISTER`
  410. );
  411. if (data) {
  412. if (!studentInfo.extra.nickname) {
  413. studentInfo.extra.nickname = data.nickname;
  414. }
  415. if (!studentInfo.extra.currentGradeNum) {
  416. const tempGrade: any = forms.gradeList || [];
  417. tempGrade?.forEach((i: any) => {
  418. if (i.value === data.currentGradeNum) {
  419. forms.gradeNumText = i.text;
  420. studentInfo.extra.currentGradeNum = data.currentGradeNum;
  421. }
  422. });
  423. }
  424. if (!studentInfo.extra.currentClass) {
  425. forms.classList.forEach((i: any) => {
  426. if (i.value === data.currentClass) {
  427. forms.currentClassText = i.text;
  428. studentInfo.extra.currentClass = data.currentClass;
  429. }
  430. });
  431. }
  432. // if (!studentInfo.extra.gender) {
  433. studentInfo.extra.gender =
  434. studentInfo.extra.gender !== data.gender
  435. ? data.gender
  436. : studentInfo.extra.gender;
  437. }
  438. } catch {
  439. //
  440. }
  441. };
  442. // 查询未支付订单
  443. const paymentOrderUnpaid = async () => {
  444. let result = false;
  445. try {
  446. const { data } = await request.get('/edu-app/userPaymentOrder/unpaid');
  447. // 判断是否有待支付订单
  448. if (!data.id) return false;
  449. // 判断是否可以取消订单
  450. if (data.cancelPayment) {
  451. await request.post(
  452. '/edu-app/userPaymentOrder/cancelPayment/' + data.orderNo
  453. );
  454. return false;
  455. } else {
  456. forms.countDownTime = data.cancelTimes;
  457. countDown.reset(Number(data.cancelTimes));
  458. countDown.start();
  459. forms.dialogMessage = `有待支付订单,请在${Math.ceil(
  460. countDown.current.value.total / 1000
  461. )}s后重试`;
  462. forms.dialogStatus = true;
  463. forms.dialogConfig = data;
  464. result = true;
  465. }
  466. } catch {
  467. //
  468. }
  469. return result;
  470. };
  471. const paymentContinue = async () => {
  472. try {
  473. const vipList = studentRegisterStore.getVip;
  474. const goodsList = studentRegisterStore.getGoods;
  475. const params: any[] = [];
  476. vipList.forEach((vip: any) => {
  477. params.push({
  478. giftVipDay: vip.membershipDays,
  479. goodsId: vip.goodsId,
  480. goodsNum: 1,
  481. goodsType: vip.goodsType,
  482. paymentCashAmount: vip.currentPrice, // 现金支付金额
  483. paymentCouponAmount: 0 // 优惠券金额
  484. });
  485. });
  486. goodsList.forEach((goods: any) => {
  487. params.push({
  488. goodsId: goods.productId,
  489. goodsNum: goods.quantity,
  490. goodsType: 'INSTRUMENTS',
  491. paymentCashAmount: goods.price, // 现金支付金额
  492. paymentCouponAmount: 0, // 优惠券金额
  493. goodsSkuId: goods.productSkuId
  494. });
  495. });
  496. // 创建订单
  497. const result = await request.post(
  498. '/edu-app/userPaymentOrder/executeOrder',
  499. {
  500. // hideLoading: false,
  501. data: {
  502. registerType: forms.registerType,
  503. paymentType: forms.paymentType,
  504. bizId: forms.schoolId, // 乐团编号
  505. orderType: 'SCHOOL_REGISTER',
  506. paymentCashAmount: calcPrice.value.amount || 0,
  507. paymentCouponAmount: 0,
  508. goodsInfos: params,
  509. orderName: '学生登记',
  510. orderDesc: '学生登记'
  511. }
  512. }
  513. );
  514. if (result.code === 5436) {
  515. forms.showTips = true;
  516. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  517. forms.showButton = false;
  518. } else if (result.code === 5435) {
  519. forms.showTips = true;
  520. forms.showMessage = result.message;
  521. forms.showButton = true;
  522. } else {
  523. state.config = {
  524. ...result.data.paymentConfig,
  525. paymentType: result.data.paymentType
  526. };
  527. state.orderNo = result.data.orderNo;
  528. await lastSubmit();
  529. }
  530. } catch (e: any) {
  531. console.log(e, 'any');
  532. }
  533. };
  534. const lastSubmit = async () => {
  535. try {
  536. const users = baseState.user.data;
  537. // 判断是否需要实名认证, 姓名,卡号 - 参数设置可以控制
  538. if (
  539. forms.contract_sign &&
  540. (!users?.account.realName || !users?.account.idCardNo)
  541. ) {
  542. state.authShow = true;
  543. return;
  544. }
  545. const { data } = await request.post(
  546. '/edu-app/userPaymentOrder/updateReceiveAddress',
  547. {
  548. // hideLoading: false,
  549. data: {
  550. orderNo: state.orderNo,
  551. orderType: 'SCHOOL_REGISTER'
  552. }
  553. }
  554. );
  555. state.pay_channel = data.paymentChannel;
  556. if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
  557. router.replace({
  558. path: '/payment-result',
  559. query: {
  560. orderNo: state.orderNo
  561. }
  562. });
  563. } else {
  564. onCallback();
  565. }
  566. } catch {
  567. //
  568. }
  569. };
  570. /**
  571. * @description 回调,判断是否有支付渠道,如果有则直接去支付
  572. * @returns void
  573. */
  574. const onCallback = () => {
  575. const pt = state.pay_channel;
  576. // 判断是否有支付方式
  577. if (pt) {
  578. const payCode: string = beforeSubmit(state.pay_channel);
  579. onConfirm({
  580. payCode,
  581. pay_channel: pt
  582. });
  583. } else {
  584. if (orderType.value === 'VIP') {
  585. state.paymentStatus = true;
  586. } else {
  587. // 直接去拉取微信支付
  588. onConfirm({
  589. payCode: 'payResult',
  590. pay_channel: 'wx_pub'
  591. });
  592. }
  593. }
  594. };
  595. const onConfirm = (val: any) => {
  596. const config: any = state.config;
  597. state.pay_channel = val.pay_channel;
  598. const params = qs.stringify({
  599. pay_channel: val.pay_channel,
  600. wxAppId: config.wxAppId,
  601. alipayAppId: config.alipayAppId,
  602. paymentType: forms.paymentType,
  603. body: config.body,
  604. price: config.price,
  605. orderNo: config.merOrderNo,
  606. userId: config.userId
  607. });
  608. // console.log(params, state.config);
  609. // return;
  610. if (val.payCode === 'payResult') {
  611. window.location.href =
  612. window.location.origin + '/classroom-app/#/payResult?' + params;
  613. } else {
  614. state.qrCodeUrl =
  615. window.location.origin + '/classroom-app/#/payDefine?' + params;
  616. state.showQrcode = true;
  617. state.paymentStatus = false;
  618. setTimeout(() => {
  619. getPaymentOrderStatus();
  620. }, 300);
  621. }
  622. };
  623. // 放弃支付时,则取消订单
  624. const onBackOut = async () => {
  625. try {
  626. await request.post(
  627. '/edu-app/userPaymentOrder/cancelPayment/' + state.orderNo
  628. );
  629. // router.back();
  630. } catch {
  631. //
  632. }
  633. };
  634. // 轮询查询订单状态
  635. const getPaymentOrderStatus = async () => {
  636. // 循环查询订单
  637. // const orderNo = state.orderNo
  638. const orderTimer = setInterval(async () => {
  639. // 判断是否在当前路由,如果不是则清除定时器
  640. if (route.name != 'student-register-form') {
  641. clearInterval(orderTimer);
  642. return;
  643. }
  644. state.orderTimer = orderTimer;
  645. try {
  646. const { data } = await request.post(
  647. '/edu-app/open/userOrder/paymentStatus/' + state.orderNo,
  648. {
  649. hideLoading: true
  650. }
  651. );
  652. if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
  653. // 默认关闭支付二维码弹窗
  654. state.showQrcode = false;
  655. clearInterval(state.orderTimer);
  656. setTimeout(() => {
  657. router.replace({
  658. path: '/payment-result',
  659. query: {
  660. orderNo: state.orderNo
  661. }
  662. });
  663. }, 100);
  664. }
  665. } catch {
  666. //
  667. clearInterval(state.orderTimer);
  668. }
  669. }, 5000);
  670. };
  671. // 实名认证成功
  672. const onAuthSuccess = () => {
  673. //
  674. state.authShow = false;
  675. paymentContinue(); // 实名成功后自动支付
  676. };
  677. onMounted(async () => {
  678. getRegisterGoods();
  679. });
  680. return () => (
  681. <div class={styles['student-register']}>
  682. <div class={styles.studentRegisterContainer}>
  683. <div
  684. class={[styles.studentSection, styles.studentSectionForm]}
  685. // style={{ display: 'none' }}
  686. >
  687. <div class={styles.title1}></div>
  688. <Form labelAlign="left" class={styles.registerForm}>
  689. <Field
  690. clearable={false}
  691. label="联系方式(直接监护人)"
  692. placeholder="请输入手机号码"
  693. type="tel"
  694. required
  695. autocomplete="off"
  696. inputAlign="right"
  697. class={styles.username}
  698. v-model={studentInfo.username}
  699. border={false}
  700. maxlength={11}>
  701. {{
  702. label: () => (
  703. <div>
  704. 联系方式
  705. {/* (直接监护人) */}
  706. <p class={styles.tips}>(直接监护人)</p>
  707. </div>
  708. )
  709. }}
  710. </Field>
  711. <div class={['van-hairline--bottom', styles.fieldTipsGroup]}>
  712. <div class={[styles.fieldTips]}>
  713. 手机号是音乐数字课堂的唯一登录账户
  714. </div>
  715. </div>
  716. <Field
  717. center
  718. clearable={false}
  719. required
  720. inputAlign="right"
  721. label="验证码"
  722. placeholder="请输入验证码"
  723. autocomplete="off"
  724. type="number"
  725. v-model={studentInfo.password}
  726. maxlength={6}
  727. onUpdate:modelValue={(val: any) => {
  728. getUserInfos();
  729. }}>
  730. {{
  731. button: () =>
  732. forms.countDownStatus ? (
  733. <span
  734. class={[
  735. styles.codeText,
  736. !validatePhone.value ? styles.codeTextDisabled : ''
  737. ]}
  738. onClick={onSendCode}>
  739. 获取验证码
  740. </span>
  741. ) : (
  742. <CountDown
  743. ref={(el: any) => (countDownRef.value = el)}
  744. auto-start={false}
  745. class={styles.countDown}
  746. time={forms.countDownTime}
  747. onFinish={onFinished}
  748. format="ss秒后重试"
  749. />
  750. )
  751. }}
  752. </Field>
  753. <Field
  754. clearable={false}
  755. required
  756. inputAlign="right"
  757. label="学生姓名"
  758. placeholder="请输入学生姓名"
  759. autocomplete="off"
  760. maxlength={14}
  761. v-model={studentInfo.extra.nickname}
  762. />
  763. <Field
  764. clearable={false}
  765. required
  766. inputAlign="right"
  767. label="学生性别"
  768. placeholder="请选择性别"
  769. autocomplete="off"
  770. // v-model={studentInfo.extra.nickname}
  771. >
  772. {{
  773. input: () => (
  774. <RadioGroup
  775. checked-color="linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)"
  776. v-model={studentInfo.extra.gender}
  777. direction="horizontal">
  778. <Tag
  779. size="large"
  780. type="primary"
  781. color={
  782. !(studentInfo.extra.gender === 1)
  783. ? '#F5F6FA'
  784. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  785. }
  786. textColor={
  787. !(studentInfo.extra.gender === 1) ? '#626264' : '#fff'
  788. }
  789. class={styles.radioSection}>
  790. <Radio class={styles.radioItem} name={1}></Radio>男
  791. </Tag>
  792. <Tag
  793. size="large"
  794. type="primary"
  795. color={
  796. !(studentInfo.extra.gender === 0)
  797. ? '#F5F6FA'
  798. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  799. }
  800. textColor={
  801. !(studentInfo.extra.gender === 0) ? '#626264' : '#fff'
  802. }
  803. class={styles.radioSection}>
  804. <Radio class={styles.radioItem} name={0}></Radio>女
  805. </Tag>
  806. </RadioGroup>
  807. )
  808. }}
  809. </Field>
  810. <Field
  811. clearable={false}
  812. required
  813. inputAlign="right"
  814. label="所在年级"
  815. placeholder="请选择年级"
  816. isLink
  817. readonly
  818. clickable={false}
  819. modelValue={forms.gradeNumText}
  820. onClick={() => (forms.gradeStatus = true)}
  821. />
  822. <Field
  823. clearable={false}
  824. required
  825. inputAlign="right"
  826. label="所在班级"
  827. placeholder="请选择班级"
  828. isLink
  829. readonly
  830. clickable={false}
  831. modelValue={forms.currentClassText}
  832. onClick={() => (forms.classStatus = true)}
  833. />
  834. {forms.giftVipDay > 0 ? (
  835. <div class={styles.memberNumer}>
  836. <img src={iconGift} class={styles.iconGift} />
  837. <p>
  838. 注册成功即可获得乐器AI学练工具
  839. <span>{forms.giftVipDay || 0}</span>天有效期
  840. </p>
  841. </div>
  842. ) : (
  843. ''
  844. )}
  845. </Form>
  846. </div>
  847. <div class={styles.studentSection}>
  848. <div class={styles.title2}></div>
  849. <div class={styles.goodsGroup}>
  850. <div
  851. class={[
  852. styles.goodsItem,
  853. forms.joinType === 'digitalize' && styles.checked
  854. ]}
  855. onClick={() => (forms.joinType = 'digitalize')}>
  856. <div class={styles.goodsInner}>
  857. <i class={styles.proposalTip}></i>
  858. 数字化方式
  859. </div>
  860. </div>
  861. <div
  862. class={[
  863. styles.goodsItem,
  864. forms.joinType === 'tradition' && styles.checked
  865. ]}
  866. onClick={() => (forms.joinType = 'tradition')}>
  867. <div class={styles.goodsInner}>传统方式</div>
  868. </div>
  869. </div>
  870. </div>
  871. {forms.joinType === 'digitalize' && (
  872. <div class={[styles.goodsExtra]}>
  873. <i class={styles.iconArrow}></i>
  874. <Cell border={false} class={styles.goodsCell}>
  875. {{
  876. icon: () => (
  877. <Image class={styles.img} src={forms.detailVip.goodsUrl} />
  878. ),
  879. title: () => (
  880. <div class={styles.section}>
  881. <div class={styles.sectionContent}>
  882. <h2>
  883. {forms.detailVip.goodsName}
  884. <Tag class={styles.brandName}>
  885. {forms.detailVip.brandName}
  886. </Tag>
  887. </h2>
  888. <p class={[styles.model]}>
  889. {/* 解决学生不会练、不知练的对错、家长无法辅导、无需再额外请老师 */}
  890. {forms.detailVip.description}
  891. </p>
  892. <span class={styles.sendInstrument}>赠送课堂乐器</span>
  893. </div>
  894. </div>
  895. )
  896. }}
  897. </Cell>
  898. {forms.detailVip.membershipDays ? (
  899. <div class={styles.memberNumer}>
  900. <img src={iconGift} class={styles.iconGift} />
  901. <p>
  902. 现在购买赠送乐器AI学练工具
  903. <span>{forms.detailVip.membershipDays || 0}</span>天有效期
  904. </p>
  905. </div>
  906. ) : (
  907. ''
  908. )}
  909. </div>
  910. )}
  911. {forms.joinType === 'tradition' && (
  912. <div class={styles.goodsTradition}>
  913. <i class={styles.iconArrow}></i>
  914. <div class={styles.goodsTitle}></div>
  915. <div class={styles.steps}>
  916. <div class={styles.step}>
  917. <span class={styles.nums}>
  918. <span class={styles.numInner}>1</span>
  919. </span>
  920. <div class={styles.stepContent}>
  921. <span>AI工具标准:</span>
  922. 可以学练音乐教材中的乐曲,通过手机应用商店准备。
  923. </div>
  924. </div>
  925. <div class={styles.step}>
  926. <span class={styles.nums}>
  927. <span class={styles.numInner}>2</span>
  928. </span>
  929. <div class={styles.stepContent}>
  930. <span>乐器标准:</span>
  931. 管数不限,建议20管以上C调加嘴排箫(音域宽,能演奏更多复杂乐曲,不需要重复更换),黑色,要选择单一原调(调性多学生很难掌握),价格由学生根据自身情况确定。
  932. </div>
  933. </div>
  934. </div>
  935. </div>
  936. )}
  937. {forms.joinType && (
  938. <MSticky position="bottom">
  939. <div class={styles.paymentContainer}>
  940. {forms.joinType === 'digitalize' && (
  941. <>
  942. <div class={styles.payemntPrice}>
  943. <img src={giftTip} class={styles.giftTip} />
  944. <div>
  945. <span class={styles.needPrice}>
  946. <i style="font-style: normal">¥ </i>
  947. <span>{moneyFormat(calcPrice.value.amount)}</span>
  948. <i style="font-style: normal">/年</i>
  949. </span>
  950. {calcPrice.value.originAmount >
  951. calcPrice.value.amount ? (
  952. <del class={styles.allPrice}>
  953. ¥ {moneyFormat(calcPrice.value.originAmount)}
  954. </del>
  955. ) : (
  956. ''
  957. )}
  958. </div>
  959. </div>
  960. <div
  961. class={styles.paymentBtn}
  962. onClick={() => {
  963. onSubmit();
  964. }}>
  965. <Button
  966. round
  967. disabled={forms.submitLoading}
  968. loading={forms.submitLoading}>
  969. 立即支付
  970. </Button>
  971. </div>
  972. </>
  973. )}
  974. {forms.joinType === 'tradition' && (
  975. <div
  976. class={styles.traditionBtn}
  977. onClick={() => {
  978. onSubmit();
  979. }}>
  980. <Button
  981. round
  982. disabled={forms.submitLoading}
  983. loading={forms.submitLoading}>
  984. 提交报名
  985. </Button>
  986. </div>
  987. )}
  988. </div>
  989. </MSticky>
  990. )}
  991. </div>
  992. {forms.imgCodeStatus ? (
  993. <MImgCode
  994. v-model:value={forms.imgCodeStatus}
  995. phone={studentInfo.username}
  996. type="REGISTER"
  997. onClose={() => {
  998. forms.imgCodeStatus = false;
  999. }}
  1000. onSendCode={onCodeSend}
  1001. />
  1002. ) : null}
  1003. {/* 年级 */}
  1004. <Popup
  1005. v-model:show={forms.gradeStatus}
  1006. position="bottom"
  1007. round
  1008. safeAreaInsetBottom
  1009. lazyRender={false}
  1010. class={'popupBottomSearch'}>
  1011. <Picker
  1012. showToolbar
  1013. columns={forms.gradeList}
  1014. onCancel={() => (forms.gradeStatus = false)}
  1015. onConfirm={(val: any) => {
  1016. const selectedOption = val.selectedOptions[0];
  1017. studentInfo.extra.currentGradeNum = selectedOption.value;
  1018. forms.gradeNumText = selectedOption.text;
  1019. forms.gradeStatus = false;
  1020. }}
  1021. />
  1022. </Popup>
  1023. {/* 班级 */}
  1024. <Popup
  1025. v-model:show={forms.classStatus}
  1026. position="bottom"
  1027. round
  1028. class={'popupBottomSearch'}>
  1029. <Picker
  1030. showToolbar
  1031. columns={forms.classList}
  1032. onCancel={() => (forms.classStatus = false)}
  1033. onConfirm={(val: any) => {
  1034. const selectedOption = val.selectedOptions[0];
  1035. studentInfo.extra.currentClass = selectedOption.value;
  1036. forms.currentClassText = selectedOption.text;
  1037. forms.classStatus = false;
  1038. }}
  1039. />
  1040. </Popup>
  1041. {/* 已经购买过样品 */}
  1042. <MDialog
  1043. title="提示"
  1044. v-model:show={forms.dialogConfirmStatus}
  1045. message={'已购买会员,是否确认购买?'}
  1046. primaryColor="#FF8057"
  1047. allowHtml={true}
  1048. confirmButtonText="确定"
  1049. showCancelButton
  1050. onConfirm={async () => {
  1051. await paymentContinue();
  1052. }}
  1053. />
  1054. <MDialog
  1055. title="提示"
  1056. v-model:show={forms.dialogStatus}
  1057. message={forms.dialogMessage}
  1058. allowHtml={true}
  1059. primaryColor="#FF8057"
  1060. confirmButtonText="继续支付"
  1061. onConfirm={async () => {
  1062. // const paymentConfig = forms.dialogConfig.paymentConfig;
  1063. // router.push({
  1064. // path: '/order-detail',
  1065. // query: {
  1066. // pm: 1, // h5乐团报名
  1067. // config: JSON.stringify(paymentConfig.paymentConfig),
  1068. // orderNo: paymentConfig.orderNo
  1069. // }
  1070. // });
  1071. // console.log(forms.dialogConfig, 'dialogConfig');
  1072. countDown.pause();
  1073. const paymentConfig = forms.dialogConfig.paymentConfig;
  1074. state.config = paymentConfig?.paymentConfig;
  1075. state.orderNo = paymentConfig?.orderNo;
  1076. await lastSubmit();
  1077. }}
  1078. onCancel={(val: any) => {
  1079. countDown.pause();
  1080. }}
  1081. />
  1082. <Popup
  1083. show={state.paymentStatus}
  1084. closeOnClickOverlay={false}
  1085. position="bottom"
  1086. round
  1087. closeOnPopstate
  1088. safeAreaInsetBottom
  1089. style={{ minHeight: '30%' }}>
  1090. <Payment
  1091. paymentConfig={state.orderInfo}
  1092. onClose={() => (state.paymentStatus = false)}
  1093. onBackOut={onBackOut}
  1094. onConfirm={(val: any) => onConfirm(val)}
  1095. />
  1096. </Popup>
  1097. <Popup
  1098. v-model:show={state.showQrcode}
  1099. round
  1100. onClose={() => {
  1101. // 二维码关闭时清除定时器
  1102. clearInterval(state.orderTimer);
  1103. }}>
  1104. <QrcodePayment
  1105. url={state.qrCodeUrl}
  1106. pay_channel={state.pay_channel}
  1107. orderType={orderType.value}
  1108. />
  1109. </Popup>
  1110. {/* 是否在微信中打开 */}
  1111. <OWxTip
  1112. show={forms.showTips}
  1113. message={forms.showMessage}
  1114. showButton={forms.showButton}
  1115. buttonText="刷新"
  1116. onConfirm={() => window.location.reload()}
  1117. />
  1118. </div>
  1119. );
  1120. }
  1121. });