index.tsx 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. import {
  2. computed,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. reactive,
  7. ref,
  8. watch
  9. } from 'vue';
  10. import styles from './index.module.less';
  11. import infoTitle from '../images/new/r-title.png';
  12. import giftTip from '../images/new/gift-tip.png';
  13. import iconGift from '../images/new/icon-gift.png';
  14. import {
  15. Button,
  16. CountDown,
  17. Field,
  18. Form,
  19. Picker,
  20. Popup,
  21. Radio,
  22. RadioGroup,
  23. Tag,
  24. showToast
  25. } from 'vant';
  26. import MProtocol from '@/components/m-protocol';
  27. import { state as baseState, setLogin } from '@/state';
  28. import qs from 'query-string';
  29. import MImgCode from '@/components/m-img-code';
  30. import { browser, checkPhone, moneyFormat } from '@/helpers/utils';
  31. import request from '@/helpers/request';
  32. import { useStudentRegisterStore } from '@/store/modules/student-register-store';
  33. import { setLoginInit, state } from '@/state';
  34. import deepClone from '@/helpers/deep-clone';
  35. import { useRoute, useRouter } from 'vue-router';
  36. import { ACCESS_TOKEN } from '@/store/mutation-types';
  37. import { storage } from '@/helpers/storage';
  38. import OWxTip from '@/components/m-wx-tip';
  39. import MDialog from '@/components/m-dialog';
  40. import { CurrentTime, useCountDown } from '@vant/use';
  41. import QrcodePayment from '../qrcode-payment';
  42. import UserAuth from '../component/user-auth';
  43. import Payment from '@/views/adapay/payment';
  44. import { beforeSubmit } from '../order-state';
  45. import OPopup from '@/components/m-popup';
  46. import MSticky from '@/components/m-sticky';
  47. const studentRegisterStore = useStudentRegisterStore();
  48. const classList: any = [];
  49. for (let i = 1; i <= 40; i++) {
  50. classList.push({ text: i + '班', value: i });
  51. }
  52. export default defineComponent({
  53. name: 'register-modal',
  54. setup() {
  55. const studentDetails = sessionStorage.getItem('register-student');
  56. const countDownRef = ref();
  57. const route = useRoute();
  58. const router = useRouter();
  59. const gradeList = ref([]);
  60. const forms = reactive({
  61. schoolId: route.query.schoolId as any,
  62. countDownStatus: true,
  63. countDownTime: 1000 * 120, // 倒计时时间
  64. modelValue: false, // 是否选中协议
  65. imgCodeStatus: false,
  66. gradeNumText: '',
  67. currentClassText: '',
  68. gradeStatus: false,
  69. classStatus: false,
  70. loading: false,
  71. schoolType: '', // 学校类型
  72. gradeYear: '', // 学制
  73. bugGoods: false, // 是否购买AI
  74. registerType: '', // 报名类型
  75. giftVipDay: 0, // 赠送天数
  76. dialogStatus: false,
  77. dialogMessage: '',
  78. dialogConfirmStatus: false,
  79. paymentType: '', // 支付类型
  80. contract_sign: false, // 是否实名认证
  81. countDownTimePay: 60 * 1000,
  82. dialogConfig: {} as any,
  83. showMore: true,
  84. showTips: false,
  85. showButton: false,
  86. showMessage: '请使用微信打开'
  87. });
  88. const state = reactive({
  89. showQrcode: false,
  90. qrCodeUrl: '',
  91. pay_channel: '',
  92. orderInfo: {} as any, // 订单信息
  93. authShow: false,
  94. orderNo: null as any,
  95. config: {} as any,
  96. paymentStatus: false,
  97. orderTimer: null as any
  98. });
  99. const studentInfo = reactive({
  100. autoRegister: true,
  101. client_id: 'cooleshow-student',
  102. client_secret: 'cooleshow-student',
  103. extra: {
  104. nickname: '',
  105. currentGradeNum: '',
  106. currentClass: '',
  107. gender: 1,
  108. registerType: null as any, // 报名类型
  109. giftVipDay: 0 // 赠送会员天数
  110. },
  111. grant_type: 'password',
  112. loginType: 'SMS',
  113. password: '',
  114. username: ''
  115. });
  116. const countDown = useCountDown({
  117. // 倒计时 60 秒
  118. time: forms.countDownTimePay,
  119. onChange(current: CurrentTime) {
  120. forms.dialogMessage = `有待支付订单,请在${Math.ceil(
  121. current.total / 1000
  122. )}s后重试`;
  123. },
  124. onFinish() {
  125. forms.dialogStatus = false;
  126. }
  127. });
  128. const onCodeSend = () => {
  129. forms.countDownStatus = false;
  130. nextTick(() => {
  131. countDownRef.value.start();
  132. });
  133. };
  134. const onSendCode = () => {
  135. // 发送验证码
  136. if (!checkPhone(studentInfo.username)) {
  137. return showToast('请输入正确的手机号码');
  138. }
  139. forms.imgCodeStatus = true;
  140. };
  141. const validatePhone = computed(() => {
  142. return checkPhone(studentInfo.username) ? true : false;
  143. });
  144. const orderType = computed(() => {
  145. return state.orderInfo.orderType;
  146. });
  147. const onFinished = () => {
  148. forms.countDownStatus = true;
  149. countDownRef.value.reset();
  150. };
  151. const onSubmit = async () => {
  152. try {
  153. if (checkForm()) return;
  154. forms.loading = true;
  155. const { extra, ...res } = studentInfo;
  156. const result = await request.post('/edu-app/userlogin', {
  157. // hideLoading: false,
  158. requestType: 'form',
  159. data: {
  160. ...res,
  161. extra: JSON.stringify({
  162. ...extra,
  163. schoolId: forms.schoolId
  164. })
  165. }
  166. });
  167. if (result.code !== 200) {
  168. sessionStorage.setItem(
  169. 'register-student',
  170. JSON.stringify({
  171. ...res,
  172. extra: JSON.stringify({
  173. ...extra,
  174. schoolId: forms.schoolId
  175. })
  176. })
  177. );
  178. if (result.code === 5436) {
  179. forms.showTips = true;
  180. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  181. forms.showButton = false;
  182. } else if (result.code === 5435) {
  183. forms.showTips = true;
  184. forms.showMessage = result.message;
  185. forms.showButton = true;
  186. }
  187. } else {
  188. studentRegisterStore.setToken(
  189. result.data.token_type + ' ' + result.data.access_token
  190. );
  191. setLoginInit();
  192. // 获取用户信息
  193. const res = await request.get('/edu-app/user/getUserInfo', {
  194. requestType: 'form'
  195. });
  196. setLogin(res.data);
  197. await onRegisterSubmit();
  198. }
  199. } catch {
  200. } finally {
  201. forms.loading = false;
  202. }
  203. };
  204. const checkForm = () => {
  205. if (!studentInfo.extra.nickname) {
  206. showToast('请输入学生姓名');
  207. return true;
  208. } else if (!studentInfo.extra.currentGradeNum) {
  209. showToast('请选择所在年级');
  210. return true;
  211. } else if (!studentInfo.extra.currentClass) {
  212. showToast('请选择所在班级');
  213. return true;
  214. } else if (!checkPhone(studentInfo.username)) {
  215. showToast('请输入正确的手机号码');
  216. return true;
  217. } else if (!studentInfo.password) {
  218. showToast('请输入验证码');
  219. return true;
  220. }
  221. return false;
  222. };
  223. const getGradeList = () => {
  224. let tempList: any = [];
  225. const five = [
  226. { text: '一年级', value: 1 },
  227. { text: '二年级', value: 2 },
  228. { text: '三年级', value: 3 },
  229. { text: '四年级', value: 4 },
  230. { text: '五年级', value: 5 }
  231. ];
  232. const one = [{ text: '六年级', value: 6 }];
  233. const three = [
  234. { text: '七年级', value: 7 },
  235. { text: '八年级', value: 8 },
  236. { text: '九年级', value: 9 }
  237. ];
  238. if (forms.gradeYear === 'FIVE_YEAR_SYSTEM') {
  239. tempList.push([...five]);
  240. } else if (forms.gradeYear === 'SIX_YEAR_SYSTEM') {
  241. tempList.push([...five, ...one]);
  242. } else if (forms.gradeYear === 'THREE_YEAR_SYSTEM') {
  243. tempList.push([...three]);
  244. } else if (forms.gradeYear === 'FORE_YEAR_SYSTEM') {
  245. tempList.push([...one, ...three]);
  246. } else {
  247. tempList.push([...five, ...one, ...three]);
  248. }
  249. return tempList;
  250. };
  251. const getRegisterGoods = async () => {
  252. try {
  253. const { data } = await request.get(
  254. '/edu-app/open/userOrder/registerGoods/' + forms.schoolId,
  255. {
  256. noAuthorization: true // 是否请求接口的时候添加toekn
  257. }
  258. );
  259. // 默认选中商品
  260. // studentRegisterStore.setVip(data.details || []);
  261. const details = deepClone(data.details || []);
  262. if (details.length > 0) {
  263. forms.giftVipDay = details[0].membershipDays;
  264. }
  265. forms.bugGoods = data.bugGoods;
  266. forms.schoolType = data.schoolType;
  267. forms.gradeYear = data.gradeYear;
  268. forms.registerType = data.registerType;
  269. studentInfo.extra.giftVipDay = forms.giftVipDay;
  270. studentInfo.extra.registerType = forms.registerType;
  271. if (browser().weixin) {
  272. if (data.registerType !== 'BUG_GOODS' || data.schoolStatus === 0) {
  273. forms.showTips = true;
  274. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  275. forms.showButton = false;
  276. }
  277. } else {
  278. forms.showTips = true;
  279. }
  280. } catch {}
  281. };
  282. // 计算金额
  283. const calcPrice = computed(() => {
  284. let amount: number = 0; //现价
  285. let originAmount: number = 0; // 原价
  286. const vipList: any[] = studentRegisterStore.getVip;
  287. vipList.forEach((vip: any) => {
  288. amount += Number(vip.currentPrice);
  289. originAmount += Number(vip.originalPrice);
  290. });
  291. const goodsList: any[] = studentRegisterStore.getGoods;
  292. goodsList.forEach((good: any) => {
  293. amount += Number(good.price) * good.quantity;
  294. originAmount += Number(good.originalPrice) * good.quantity;
  295. });
  296. return {
  297. amount,
  298. originAmount
  299. };
  300. });
  301. // 登记成功之后购买
  302. const onRegisterSubmit = async () => {
  303. try {
  304. // 请求是否有待支付订单,如果有则自动关闭
  305. const status = await paymentOrderUnpaid();
  306. if (status) return;
  307. const schoolInfo = await request.get(
  308. '/edu-app/userPaymentOrder/registerStatus/' + forms.schoolId
  309. );
  310. const vipList = studentRegisterStore.getVip;
  311. if (schoolInfo.data.hasBuyCourse && vipList.length > 0) {
  312. forms.dialogConfirmStatus = true;
  313. return;
  314. }
  315. await paymentContinue();
  316. } catch {
  317. //
  318. }
  319. };
  320. // 查询未支付订单
  321. const paymentOrderUnpaid = async () => {
  322. let result = false;
  323. try {
  324. const { data } = await request.get('/edu-app/userPaymentOrder/unpaid');
  325. // 判断是否有待支付订单
  326. if (!data.id) return false;
  327. // 判断是否可以取消订单
  328. if (data.cancelPayment) {
  329. await request.post(
  330. '/edu-app/userPaymentOrder/cancelPayment/' + data.orderNo
  331. );
  332. return false;
  333. } else {
  334. forms.countDownTime = data.cancelTimes;
  335. countDown.reset(Number(data.cancelTimes));
  336. countDown.start();
  337. forms.dialogMessage = `有待支付订单,请在${Math.ceil(
  338. countDown.current.value.total / 1000
  339. )}s后重试`;
  340. forms.dialogStatus = true;
  341. forms.dialogConfig = data;
  342. result = true;
  343. }
  344. } catch {
  345. //
  346. }
  347. return result;
  348. };
  349. const paymentContinue = async () => {
  350. try {
  351. const vipList = studentRegisterStore.getVip;
  352. const goodsList = studentRegisterStore.getGoods;
  353. const params: any[] = [];
  354. vipList.forEach((vip: any) => {
  355. params.push({
  356. giftVipDay: vip.membershipDays,
  357. goodsId: vip.goodsId,
  358. goodsNum: 1,
  359. goodsType: vip.goodsType,
  360. paymentCashAmount: vip.currentPrice, // 现金支付金额
  361. paymentCouponAmount: 0 // 优惠券金额
  362. });
  363. });
  364. goodsList.forEach((goods: any) => {
  365. params.push({
  366. goodsId: goods.productId,
  367. goodsNum: goods.quantity,
  368. goodsType: 'INSTRUMENTS',
  369. paymentCashAmount: goods.price, // 现金支付金额
  370. paymentCouponAmount: 0, // 优惠券金额
  371. goodsSkuId: goods.productSkuId
  372. });
  373. });
  374. // 创建订单
  375. const result = await request.post(
  376. '/edu-app/userPaymentOrder/executeOrder',
  377. {
  378. // hideLoading: false,
  379. data: {
  380. registerType: forms.registerType,
  381. paymentType: forms.paymentType,
  382. bizId: forms.schoolId, // 乐团编号
  383. orderType: 'SCHOOL_REGISTER',
  384. paymentCashAmount: calcPrice.value.amount || 0,
  385. paymentCouponAmount: 0,
  386. goodsInfos: params,
  387. orderName: '学生登记',
  388. orderDesc: '学生登记'
  389. }
  390. }
  391. );
  392. if (result.code === 5436) {
  393. forms.showTips = true;
  394. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  395. forms.showButton = false;
  396. } else if (result.code === 5435) {
  397. forms.showTips = true;
  398. forms.showMessage = result.message;
  399. forms.showButton = true;
  400. } else {
  401. state.config = {
  402. ...result.data.paymentConfig,
  403. paymentType: result.data.paymentType
  404. };
  405. state.orderNo = result.data.orderNo;
  406. const users = baseState.user.data;
  407. // 判断是否需要实名认证, 姓名,卡号 - 参数设置可以控制
  408. if (
  409. forms.contract_sign &&
  410. (!users?.account.realName || !users?.account.idCardNo)
  411. ) {
  412. state.authShow = true;
  413. return;
  414. }
  415. const { data } = await request.post(
  416. '/edu-app/userPaymentOrder/updateReceiveAddress',
  417. {
  418. // hideLoading: false,
  419. data: {
  420. orderNo: state.orderNo,
  421. orderType: 'SCHOOL_REGISTER'
  422. }
  423. }
  424. );
  425. state.pay_channel = data.paymentChannel;
  426. if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
  427. router.replace({
  428. path: '/payment-result',
  429. query: {
  430. orderNo: state.orderNo
  431. }
  432. });
  433. } else {
  434. onCallback();
  435. }
  436. }
  437. } catch (e: any) {
  438. console.log(e, 'any');
  439. }
  440. };
  441. /**
  442. * @description 回调,判断是否有支付渠道,如果有则直接去支付
  443. * @returns void
  444. */
  445. const onCallback = () => {
  446. const pt = state.pay_channel;
  447. // 判断是否有支付方式
  448. if (pt) {
  449. const payCode: string = beforeSubmit(state.pay_channel);
  450. onConfirm({
  451. payCode,
  452. pay_channel: pt
  453. });
  454. } else {
  455. if (orderType.value === 'VIP') {
  456. state.paymentStatus = true;
  457. } else {
  458. // 直接去拉取微信支付
  459. onConfirm({
  460. payCode: 'payResult',
  461. pay_channel: 'wx_pub'
  462. });
  463. }
  464. }
  465. };
  466. const onConfirm = (val: any) => {
  467. const config: any = state.config;
  468. state.pay_channel = val.pay_channel;
  469. const params = qs.stringify({
  470. pay_channel: val.pay_channel,
  471. wxAppId: config.wxAppId,
  472. alipayAppId: config.alipayAppId,
  473. paymentType: forms.paymentType,
  474. body: config.body,
  475. price: config.price,
  476. orderNo: config.merOrderNo,
  477. userId: config.userId
  478. });
  479. if (val.payCode === 'payResult') {
  480. window.location.href =
  481. window.location.origin + '/classroom-app/#/payResult?' + params;
  482. } else {
  483. state.qrCodeUrl =
  484. window.location.origin + '/classroom-app/#/payDefine?' + params;
  485. state.showQrcode = true;
  486. state.paymentStatus = false;
  487. setTimeout(() => {
  488. getPaymentOrderStatus();
  489. }, 300);
  490. }
  491. };
  492. // 放弃支付时,则取消订单
  493. const onBackOut = async () => {
  494. try {
  495. await request.post(
  496. '/edu-app/userPaymentOrder/cancelPayment/' + state.orderNo
  497. );
  498. // router.back();
  499. } catch {
  500. //
  501. }
  502. };
  503. // 轮询查询订单状态
  504. const getPaymentOrderStatus = async () => {
  505. // 循环查询订单
  506. // const orderNo = state.orderNo
  507. const orderTimer = setInterval(async () => {
  508. // 判断是否在当前路由,如果不是则清除定时器
  509. if (route.name != 'student-register-form') {
  510. clearInterval(orderTimer);
  511. return;
  512. }
  513. state.orderTimer = orderTimer;
  514. try {
  515. const { data } = await request.post(
  516. '/edu-app/open/userOrder/paymentStatus/' + state.orderNo,
  517. {
  518. hideLoading: true
  519. }
  520. );
  521. if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
  522. // 默认关闭支付二维码弹窗
  523. state.showQrcode = false;
  524. clearInterval(state.orderTimer);
  525. setTimeout(() => {
  526. router.replace({
  527. path: '/payment-result',
  528. query: {
  529. orderNo: state.orderNo
  530. }
  531. });
  532. }, 100);
  533. }
  534. } catch {
  535. //
  536. clearInterval(state.orderTimer);
  537. }
  538. }, 5000);
  539. };
  540. // 实名认证成功
  541. const onAuthSuccess = () => {
  542. //
  543. state.authShow = false;
  544. paymentContinue(); // 实名成功后自动支付
  545. };
  546. onMounted(async () => {
  547. try {
  548. // 获取支付类型
  549. const { data } = await request.get(
  550. '/edu-app/open/paramConfig/queryByParamNameList',
  551. {
  552. requestType: 'form',
  553. params: {
  554. paramNames: 'payment_service_provider,contract_sign'
  555. }
  556. }
  557. );
  558. if (data && Array.isArray(data)) {
  559. data.forEach((item: any) => {
  560. if (item.paramName === 'contract_sign') {
  561. forms.contract_sign = item.paramValue === '1' ? true : false;
  562. } else if (item.paramName === 'payment_service_provider') {
  563. forms.paymentType = item.paramValue || '';
  564. }
  565. });
  566. }
  567. getRegisterGoods();
  568. } catch {}
  569. gradeList.value = getGradeList();
  570. if (studentDetails) {
  571. const studentJson = JSON.parse(studentDetails);
  572. const extraJson = studentJson.extra
  573. ? JSON.parse(studentJson.extra)
  574. : {};
  575. studentInfo.extra.nickname = extraJson.nickname;
  576. studentInfo.extra.currentGradeNum = extraJson.currentGradeNum;
  577. studentInfo.extra.currentClass = extraJson.currentClass;
  578. studentInfo.extra.gender = extraJson.gender;
  579. studentInfo.username = studentJson.username;
  580. classList.forEach((i: any) => {
  581. if (i.value === extraJson.currentClass) {
  582. forms.currentClassText = i.text;
  583. }
  584. });
  585. const tempGrade: any = gradeList.value[0] || [];
  586. tempGrade?.forEach((i: any) => {
  587. if (i.value === extraJson.currentGradeNum) {
  588. forms.gradeNumText = i.text;
  589. }
  590. });
  591. sessionStorage.removeItem('register-student');
  592. }
  593. });
  594. return () => (
  595. <div class={styles.registerModal}>
  596. <div class={styles.registerModalSection}>
  597. <img src={infoTitle} class={styles.infoTitle} />
  598. <Form labelAlign="left" class={styles.registerForm}>
  599. <Field
  600. clearable
  601. label="联系方式(直接监护人)"
  602. placeholder="请输入手机号码"
  603. type="tel"
  604. required
  605. autocomplete="off"
  606. inputAlign="right"
  607. class={styles.username}
  608. v-model={studentInfo.username}
  609. border={false}
  610. maxlength={11}>
  611. {{
  612. label: () => (
  613. <div>
  614. 联系方式
  615. {/* (直接监护人) */}
  616. <p class={styles.tips}>(直接监护人)</p>
  617. </div>
  618. )
  619. }}
  620. </Field>
  621. <div class={['van-hairline--bottom', styles.fieldTipsGroup]}>
  622. <div class={[styles.fieldTips]}>
  623. 手机号是数字化器乐课堂的唯一登录账户
  624. </div>
  625. </div>
  626. <Field
  627. center
  628. clearable
  629. required
  630. inputAlign="right"
  631. label="验证码"
  632. placeholder="请输入验证码"
  633. autocomplete="off"
  634. type="number"
  635. v-model={studentInfo.password}
  636. maxlength={6}>
  637. {{
  638. button: () =>
  639. forms.countDownStatus ? (
  640. <span
  641. class={[
  642. styles.codeText,
  643. !validatePhone.value ? styles.codeTextDisabled : ''
  644. ]}
  645. onClick={onSendCode}>
  646. 获取验证码
  647. </span>
  648. ) : (
  649. <CountDown
  650. ref={(el: any) => (countDownRef.value = el)}
  651. auto-start={false}
  652. class={styles.countDown}
  653. time={forms.countDownTime}
  654. onFinish={onFinished}
  655. format="ss秒后重试"
  656. />
  657. )
  658. }}
  659. </Field>
  660. <Field
  661. clearable
  662. required
  663. inputAlign="right"
  664. label="学生姓名"
  665. placeholder="请输入学生姓名"
  666. autocomplete="off"
  667. maxlength={14}
  668. v-model={studentInfo.extra.nickname}
  669. />
  670. <Field
  671. clearable
  672. required
  673. inputAlign="right"
  674. label="学生性别"
  675. placeholder="请选择性别"
  676. autocomplete="off"
  677. // v-model={studentInfo.extra.nickname}
  678. >
  679. {{
  680. input: () => (
  681. <RadioGroup
  682. checked-color="linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)"
  683. v-model={studentInfo.extra.gender}
  684. direction="horizontal">
  685. <Tag
  686. size="large"
  687. type="primary"
  688. color={
  689. !(studentInfo.extra.gender === 1)
  690. ? '#F5F6FA'
  691. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  692. }
  693. textColor={
  694. !(studentInfo.extra.gender === 1) ? '#626264' : '#fff'
  695. }
  696. class={styles.radioSection}>
  697. <Radio class={styles.radioItem} name={1}></Radio>男
  698. </Tag>
  699. <Tag
  700. size="large"
  701. type="primary"
  702. color={
  703. !(studentInfo.extra.gender === 0)
  704. ? '#F5F6FA'
  705. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  706. }
  707. textColor={
  708. !(studentInfo.extra.gender === 0) ? '#626264' : '#fff'
  709. }
  710. class={styles.radioSection}>
  711. <Radio class={styles.radioItem} name={0}></Radio>女
  712. </Tag>
  713. </RadioGroup>
  714. )
  715. }}
  716. </Field>
  717. <Field
  718. clearable
  719. required
  720. inputAlign="right"
  721. label="所在年级"
  722. placeholder="请选择年级"
  723. isLink
  724. readonly
  725. clickable={false}
  726. modelValue={forms.gradeNumText}
  727. onClick={() => (forms.gradeStatus = true)}
  728. />
  729. <Field
  730. clearable
  731. required
  732. inputAlign="right"
  733. label="所在班级"
  734. placeholder="请选择班级"
  735. isLink
  736. readonly
  737. clickable={false}
  738. modelValue={forms.currentClassText}
  739. onClick={() => (forms.classStatus = true)}
  740. />
  741. {forms.giftVipDay > 0 && (
  742. <div class={styles.memberNumer}>
  743. <img src={iconGift} class={styles.iconGift} />
  744. <p>
  745. 注册成功即可获得乐器AI学练工具
  746. <span>{forms.giftVipDay || 0}</span>天
  747. </p>
  748. </div>
  749. )}
  750. </Form>
  751. {/* <MProtocol
  752. center
  753. v-model:modelValue={forms.modelValue}
  754. prototcolType="REGISTER"
  755. /> */}
  756. <MSticky position="bottom">
  757. <div class={styles.paymentContainer}>
  758. <div class={styles.payemntPrice}>
  759. <img src={giftTip} class={styles.giftTip} />
  760. <div>
  761. <span class={styles.needPrice}>
  762. <i style="font-style: normal">¥ </i>
  763. <span>{moneyFormat(calcPrice.value.amount)}</span>
  764. <i style="font-style: normal">/年</i>
  765. </span>
  766. {calcPrice.value.originAmount > calcPrice.value.amount ? (
  767. <del class={styles.allPrice}>
  768. ¥ {moneyFormat(calcPrice.value.originAmount)}
  769. </del>
  770. ) : (
  771. ''
  772. )}
  773. </div>
  774. </div>
  775. <div class={styles.paymentBtn} onClick={onSubmit}>
  776. <Button round disabled={forms.loading} loading={forms.loading}>
  777. 立即支付
  778. </Button>
  779. </div>
  780. </div>
  781. </MSticky>
  782. </div>
  783. {forms.imgCodeStatus ? (
  784. <MImgCode
  785. v-model:value={forms.imgCodeStatus}
  786. phone={studentInfo.username}
  787. type="REGISTER"
  788. onClose={() => {
  789. forms.imgCodeStatus = false;
  790. }}
  791. onSendCode={onCodeSend}
  792. />
  793. ) : null}
  794. {/* 年级 */}
  795. <Popup
  796. v-model:show={forms.gradeStatus}
  797. position="bottom"
  798. round
  799. safeAreaInsetBottom
  800. lazyRender={false}
  801. class={'popupBottomSearch'}>
  802. <Picker
  803. showToolbar
  804. columns={gradeList.value as any}
  805. onCancel={() => (forms.gradeStatus = false)}
  806. onConfirm={(val: any) => {
  807. const selectedOption = val.selectedOptions[0];
  808. studentInfo.extra.currentGradeNum = selectedOption.value;
  809. forms.gradeNumText = selectedOption.text;
  810. forms.gradeStatus = false;
  811. }}
  812. />
  813. </Popup>
  814. {/* 班级 */}
  815. <Popup
  816. v-model:show={forms.classStatus}
  817. position="bottom"
  818. round
  819. class={'popupBottomSearch'}>
  820. <Picker
  821. showToolbar
  822. columns={classList}
  823. onCancel={() => (forms.classStatus = false)}
  824. onConfirm={(val: any) => {
  825. const selectedOption = val.selectedOptions[0];
  826. studentInfo.extra.currentClass = selectedOption.value;
  827. forms.currentClassText = selectedOption.text;
  828. forms.classStatus = false;
  829. }}
  830. />
  831. </Popup>
  832. {/* 已经购买过样品 */}
  833. <MDialog
  834. title="提示"
  835. v-model:show={forms.dialogConfirmStatus}
  836. message={'已购买会员,是否确认购买?'}
  837. primaryColor="#FF8057"
  838. allowHtml={true}
  839. confirmButtonText="确定"
  840. showCancelButton
  841. onConfirm={async () => {
  842. await paymentContinue();
  843. }}
  844. />
  845. <Popup
  846. show={state.paymentStatus}
  847. closeOnClickOverlay={false}
  848. position="bottom"
  849. round
  850. closeOnPopstate
  851. safeAreaInsetBottom
  852. style={{ minHeight: '30%' }}>
  853. <Payment
  854. paymentConfig={state.orderInfo}
  855. onClose={() => (state.paymentStatus = false)}
  856. onBackOut={onBackOut}
  857. onConfirm={(val: any) => onConfirm(val)}
  858. />
  859. </Popup>
  860. <Popup
  861. v-model:show={state.showQrcode}
  862. round
  863. onClose={() => {
  864. // 二维码关闭时清除定时器
  865. clearInterval(state.orderTimer);
  866. }}>
  867. <QrcodePayment
  868. url={state.qrCodeUrl}
  869. pay_channel={state.pay_channel}
  870. orderType={orderType.value}
  871. />
  872. </Popup>
  873. <OPopup v-model:modelValue={state.authShow}>
  874. <UserAuth onSuccess={onAuthSuccess} hideHeader={!browser().isApp} />
  875. </OPopup>
  876. {/* 是否在微信中打开 */}
  877. <OWxTip
  878. show={forms.showTips}
  879. message={forms.showMessage}
  880. showButton={forms.showButton}
  881. buttonText="刷新"
  882. onConfirm={() => window.location.reload()}
  883. />
  884. </div>
  885. );
  886. }
  887. });