index.tsx 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690
  1. import {
  2. Image,
  3. Cell,
  4. Tag,
  5. Button,
  6. Popup,
  7. showToast,
  8. Form,
  9. Field,
  10. CountDown,
  11. RadioGroup,
  12. Radio,
  13. Picker,
  14. closeToast
  15. } from 'vant';
  16. import {
  17. computed,
  18. defineComponent,
  19. nextTick,
  20. onMounted,
  21. onUnmounted,
  22. reactive,
  23. ref
  24. } from 'vue';
  25. import qs from 'query-string';
  26. import {
  27. state as baseState,
  28. goWechatAuth,
  29. setLogin,
  30. setLoginInit
  31. } from '@/state';
  32. import styles from './index.module.less';
  33. import MSticky from '@/components/m-sticky';
  34. // import MVideo from '@/components/m-video';
  35. import { useRoute, useRouter } from 'vue-router';
  36. import { useStudentRegisterStore } from '@/store/modules/student-register-store';
  37. import request from '@/helpers/request';
  38. import requestStudent from './request';
  39. import { browser, checkPhone, getUrlCode, moneyFormat } from '@/helpers/utils';
  40. import deepClone from '@/helpers/deep-clone';
  41. import OWxTip from '@/components/m-wx-tip';
  42. import MDialog from '@/components/m-dialog';
  43. // import f1 from './images/new/f-1.png';
  44. // import f2 from './images/new/f-2.png';
  45. // import f3 from './images/new/f-3.png';
  46. // import iconTip2 from './images/new/icon-tip2.png';
  47. // import functionBg from './images/new/function-bg.png';
  48. import tuangou from './images/new/tuangou.png';
  49. import icon3 from './images/new/icon-3.png';
  50. import icon5 from './images/new/icon-5.png';
  51. import icon6 from './images/new/icon-6.png';
  52. import giftTip from './images/new/icon-4.png';
  53. import iconGift from './images/new/icon-gift.png';
  54. import dayjs from 'dayjs';
  55. // import MMessageTip from '@/components/m-message-tip';
  56. import { CurrentTime, useCountDown } from '@vant/use';
  57. import Payment from '../adapay/payment';
  58. import QrcodePayment from './qrcode-payment';
  59. import MImgCode from '@/components/m-img-code';
  60. import { beforeSubmit } from './order-state';
  61. import { useInterval, useIntervalFn } from '@vueuse/core';
  62. import MPopup from '@/components/m-popup';
  63. import UserAuth from './component/user-auth';
  64. const classList: any = [];
  65. for (let i = 1; i <= 40; i++) {
  66. classList.push({ text: i + '班', value: i });
  67. }
  68. const GRADE_ENUM = {
  69. '1': '一年级',
  70. '2': '二年级',
  71. '3': '三年级',
  72. '4': '四年级',
  73. '5': '五年级',
  74. '6': '六年级',
  75. '7': '七年级',
  76. '8': '八年级',
  77. '9': '九年级'
  78. } as any;
  79. const getGradeList = (gradeYear: string, instrumentCode?: string) => {
  80. let tempList: any = [];
  81. const five = [
  82. { text: '一年级', value: 1, instrumentCode },
  83. { text: '二年级', value: 2, instrumentCode },
  84. { text: '三年级', value: 3, instrumentCode },
  85. { text: '四年级', value: 4, instrumentCode },
  86. { text: '五年级', value: 5, instrumentCode }
  87. ];
  88. const one = [{ text: '六年级', value: 6, instrumentCode }];
  89. const three = [
  90. { text: '七年级', value: 7, instrumentCode },
  91. { text: '八年级', value: 8, instrumentCode },
  92. { text: '九年级', value: 9, instrumentCode }
  93. ];
  94. if (gradeYear === 'FIVE_YEAR_SYSTEM') {
  95. tempList.push(...[...five]);
  96. } else if (gradeYear === 'SIX_YEAR_SYSTEM') {
  97. tempList.push(...[...five, ...one]);
  98. } else if (gradeYear === 'THREE_YEAR_SYSTEM') {
  99. tempList.push(...[...three]);
  100. } else if (gradeYear === 'FORE_YEAR_SYSTEM') {
  101. tempList.push(...[...one, ...three]);
  102. } else {
  103. tempList.push(...[...five, ...one, ...three]);
  104. }
  105. return tempList;
  106. };
  107. export default defineComponent({
  108. name: 'student-register',
  109. setup() {
  110. const route = useRoute();
  111. const studentRegisterStore = useStudentRegisterStore();
  112. const router = useRouter();
  113. // 初始化学校编号
  114. studentRegisterStore.setShoolId(route.query.sId as any);
  115. const countDownRef = ref();
  116. const mstickyRef = ref();
  117. const forms = reactive({
  118. schoolId: route.query.sId as any,
  119. paymentType: '', // 支付类型
  120. // popupShow: false,
  121. details: [] as any[],
  122. // schoolType: '', // 学校类型
  123. gradeYear: '', // 学制
  124. schoolInstrumentSetType: null as any,
  125. // bugGoods: false, // 是否购买AI
  126. registerType: '', // 报名类型
  127. detailVip: {} as any,
  128. giftVipDay: 0, // 赠送天数
  129. submitLoading: false,
  130. // showMore: true,
  131. showTips: false,
  132. showButton: false,
  133. showMessage: '请使用微信扫描二维码',
  134. countDownStatus: true,
  135. countDownTime: 1000 * 120, // 倒计时时间
  136. // modelValue: false, // 是否选中协议
  137. imgCodeStatus: false,
  138. gradeNumText: '',
  139. currentClassText: '',
  140. gradeStatus: false,
  141. classStatus: false,
  142. loading: false,
  143. // dialogStatusVisible: false,
  144. // dialogStatusMessage: '',
  145. dialogStatus: false,
  146. dialogMessage: '',
  147. confirmButtonText: '确定',
  148. cancelButtonText: '取消',
  149. messageAlign: 'center' as 'left' | 'center' | 'right',
  150. dialogConfirmStatus: false,
  151. contract_sign: false, // 是否实名认证
  152. countDownTimePay: 60 * 1000,
  153. dialogConfig: {} as any,
  154. showOtherSchool: false,
  155. showOtherMessage: '',
  156. joinType: '' as 'digitalize' | 'tradition',
  157. gradeList: [] as any,
  158. classList: [] as any,
  159. saveUserId: null as any,
  160. saveId: null as any,
  161. openId: null as any,
  162. code: null as any,
  163. intervalFnRef: null as any, // 页面订时器
  164. registerExpireTime: null as any, // 结束时间
  165. instrumentCode: null as any, // 乐器编码
  166. activeOverTime: 0, // 活动结束时间
  167. activeOverStatus: true, // 活动是否结束 默认已结束
  168. gradePopupIndex: [] as any, // 年级下拉索引
  169. classPopupIndex: [] as any // 班级下拉索引
  170. });
  171. const state = reactive({
  172. showQrcode: false,
  173. qrCodeUrl: '',
  174. pay_channel: '',
  175. orderInfo: {} as any, // 订单信息
  176. authShow: false,
  177. orderNo: null as any,
  178. config: {} as any,
  179. paymentStatus: false,
  180. orderTimer: null as any
  181. });
  182. const studentInfo = reactive({
  183. autoRegister: true,
  184. client_id: 'cooleshow-student',
  185. client_secret: 'cooleshow-student',
  186. extra: {
  187. nickname: '',
  188. currentGradeNum: '' as any,
  189. currentClass: '' as any,
  190. gender: 1 as any,
  191. registerType: null as any, // 报名类型
  192. giftVipDay: 0 // 赠送会员天数
  193. },
  194. grant_type: 'password',
  195. loginType: 'SMS',
  196. password: '',
  197. username: ''
  198. });
  199. // 页面定时
  200. const pageTimer = useInterval(1000, { controls: true });
  201. pageTimer.pause();
  202. // const countDown = useCountDown({
  203. // // 倒计时 60 秒
  204. // time: forms.countDownTimePay,
  205. // onChange(current: CurrentTime) {
  206. // forms.dialogStatusMessage = `有待支付订单,请在${Math.ceil(
  207. // current.total / 1000
  208. // )}s后重试`;
  209. // },
  210. // onFinish() {
  211. // forms.dialogStatusVisible = false;
  212. // }
  213. // });
  214. const overCountDown = useCountDown({
  215. time: forms.activeOverTime,
  216. onFinish() {
  217. forms.activeOverStatus = true;
  218. console.log(forms.submitLoading, 'forms.submitLoading');
  219. if (forms.submitLoading) return;
  220. applyOver();
  221. }
  222. });
  223. /** 报名结束提示 */
  224. const applyOver = () => {
  225. forms.showTips = true;
  226. forms.showMessage = '团购时间已截止,感谢您的参与';
  227. forms.showButton = false;
  228. forms.intervalFnRef?.pause();
  229. };
  230. const onCodeSend = () => {
  231. forms.countDownStatus = false;
  232. nextTick(() => {
  233. countDownRef.value.start();
  234. });
  235. };
  236. const onSendCode = () => {
  237. // 发送验证码
  238. if (!checkPhone(studentInfo.username)) {
  239. return showToast('请输入正确的手机号码');
  240. }
  241. forms.imgCodeStatus = true;
  242. };
  243. const validatePhone = computed(() => {
  244. return checkPhone(studentInfo.username) ? true : false;
  245. });
  246. const onFinished = () => {
  247. forms.countDownStatus = true;
  248. countDownRef.value.reset();
  249. };
  250. const orderType = computed(() => {
  251. return state.orderInfo.orderType;
  252. });
  253. const getRegisterGoods = async () => {
  254. try {
  255. const { data } = await request.get(
  256. '/edu-app/open/userOrder/registerGoods/' + forms.schoolId,
  257. {
  258. noAuthorization: true // 是否请求接口的时候添加toekn
  259. }
  260. );
  261. // 默认选中商品
  262. studentRegisterStore.setVip(data.details || []);
  263. forms.details = deepClone(data.details || []);
  264. forms.registerExpireTime = data.registerExpireTime; // '2024-03-27 17:33:52'; //
  265. if (forms.registerExpireTime) {
  266. if (dayjs(new Date()).isBefore(forms.registerExpireTime)) {
  267. // 活动没有结束
  268. forms.activeOverStatus = false;
  269. // 默认返回毫秒
  270. forms.activeOverTime = dayjs(forms.registerExpireTime).diff(
  271. dayjs(new Date())
  272. );
  273. overCountDown.reset(forms.activeOverTime);
  274. overCountDown.start();
  275. } else {
  276. applyOver();
  277. forms.activeOverStatus = true;
  278. }
  279. }
  280. if (forms.details.length > 0) {
  281. forms.detailVip = forms.details[0];
  282. // forms.giftVipDay = forms.details[0].membershipDays;
  283. }
  284. forms.giftVipDay = data.giftVipDay || 0;
  285. forms.gradeYear = data.gradeYear;
  286. forms.schoolInstrumentSetType = data.schoolInstrumentSetType;
  287. forms.registerType = data.registerType;
  288. studentInfo.extra.registerType = data.registerType;
  289. const schoolInstrumentList = data.schoolInstrumentList || [];
  290. if (data.schoolInstrumentSetType === 'SCHOOL') {
  291. const instrumentCode = schoolInstrumentList[0]?.instrumentCode;
  292. forms.gradeList = getGradeList(data.gradeYear, instrumentCode);
  293. forms.classList = classList;
  294. } else if (data.schoolInstrumentSetType === 'GRADE') {
  295. schoolInstrumentList.forEach((item: any) => {
  296. forms.gradeList.push({
  297. text: GRADE_ENUM[item.gradeNum],
  298. value: item.gradeNum,
  299. instrumentId: item.instrumentId,
  300. instrumentCode: item.instrumentCode
  301. });
  302. });
  303. forms.gradeList.sort((a: any, b: any) => a.value - b.value);
  304. // console.log(
  305. // forms.gradeList.sort((a: any, b: any) => a.value - b.value),
  306. // 'forms.gradeList.sort((a: any, b: any) => a.value - b.value)'
  307. // );
  308. forms.classList = classList;
  309. } else if (data.schoolInstrumentSetType === 'CLASS') {
  310. // 班级
  311. const tempGradeList: any[] = [];
  312. schoolInstrumentList.forEach((item: any) => {
  313. if (!tempGradeList.includes(item.gradeNum)) {
  314. tempGradeList.push(item.gradeNum);
  315. }
  316. });
  317. const lastGradeList: any[] = [];
  318. tempGradeList.forEach((temp: any) => {
  319. const list = {
  320. text: GRADE_ENUM[temp],
  321. value: temp,
  322. instrumentId: '',
  323. instrumentCode: '',
  324. instrumentName: '',
  325. classList: [] as any
  326. };
  327. schoolInstrumentList.forEach((item: any) => {
  328. if (temp === item.gradeNum) {
  329. list.instrumentId = item.instrumentId;
  330. list.instrumentCode = item.instrumentCode;
  331. list.instrumentName = item.instrumentName;
  332. list.classList.push({
  333. text: item.classNum + '班',
  334. value: item.classNum,
  335. instrumentCode: item.instrumentCode
  336. });
  337. }
  338. });
  339. // 排序班级
  340. list.classList.sort((a: any, b: any) => a.value - b.value);
  341. lastGradeList.push(list);
  342. });
  343. lastGradeList.sort((a: any, b: any) => a.value - b.value);
  344. forms.gradeList = lastGradeList;
  345. forms.classList = [];
  346. } else {
  347. forms.gradeList = getGradeList(data.gradeYear);
  348. forms.classList = classList;
  349. }
  350. if (browser().weixin) {
  351. // if (
  352. // data.schoolStatus === 0 &&
  353. // forms.schoolId == '1770035687490105346'
  354. // ) {
  355. // forms.showTips = true;
  356. // forms.showMessage = '团购时间已截止,感谢您的参与';
  357. // forms.showButton = false;
  358. // return;
  359. // }
  360. if (data.registerType !== 'BUG_GOODS' || data.schoolStatus === 0) {
  361. forms.showTips = true;
  362. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  363. forms.showButton = false;
  364. return;
  365. }
  366. } else {
  367. forms.showTips = true;
  368. return;
  369. }
  370. // 判断是否有倒计时,倒计时是滞结束
  371. if (!forms.registerExpireTime || !forms.activeOverStatus) {
  372. pagePointInit();
  373. }
  374. } catch {}
  375. };
  376. // 计算金额
  377. const calcPrice = computed(() => {
  378. let amount: number = 0; //现价
  379. let originAmount: number = 0; // 原价
  380. const vipList: any[] = studentRegisterStore.getVip;
  381. vipList.forEach((vip: any) => {
  382. amount += Number(vip.currentPrice);
  383. originAmount += Number(vip.originalPrice);
  384. });
  385. // const goodsList: any[] = studentRegisterStore.getGoods;
  386. // goodsList.forEach((good: any) => {
  387. // amount += Number(good.price) * good.quantity;
  388. // originAmount += Number(good.originalPrice) * good.quantity;
  389. // });
  390. return {
  391. amount,
  392. originAmount
  393. };
  394. });
  395. const checkForm = (status = true) => {
  396. if (!checkPhone(studentInfo.username)) {
  397. status && showToast('请输入正确的手机号码');
  398. return true;
  399. } else if (!studentInfo.password) {
  400. status && showToast('请输入验证码');
  401. return true;
  402. } else if (!studentInfo.extra.nickname) {
  403. status && showToast('请输入学生姓名');
  404. return true;
  405. } else if (!studentInfo.extra.currentGradeNum) {
  406. status && showToast('请选择所在年级');
  407. return true;
  408. } else if (!studentInfo.extra.currentClass) {
  409. status && showToast('请选择所在班级');
  410. return true;
  411. }
  412. return false;
  413. };
  414. // 登记成功之后购买
  415. const onSubmit = async () => {
  416. forms.submitLoading = true;
  417. try {
  418. if (checkForm()) {
  419. forms.submitLoading = false;
  420. return;
  421. }
  422. const { extra, ...res } = studentInfo;
  423. const result = await request.post('/edu-app/userlogin', {
  424. requestType: 'form',
  425. data: {
  426. ...res,
  427. extra: JSON.stringify({
  428. ...extra,
  429. giftVipDay:
  430. forms.detailVip.membershipDays || 0 + forms.giftVipDay || 0,
  431. schoolId: forms.schoolId
  432. })
  433. }
  434. });
  435. if (result.code !== 200) {
  436. if (result.code === 5436) {
  437. forms.showTips = true;
  438. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  439. forms.showButton = false;
  440. } else if (result.code === 5435) {
  441. forms.showTips = true;
  442. forms.showMessage = result.message;
  443. forms.showButton = true;
  444. } else if (result.code === 5437) {
  445. forms.showTips = true;
  446. forms.showMessage = '团购时间已截止,感谢您的参与'; //result.message;
  447. forms.showButton = false;
  448. }
  449. } else {
  450. studentRegisterStore.setToken(
  451. result.data.token_type + ' ' + result.data.access_token
  452. );
  453. setLoginInit();
  454. let joinType = 'NOT_REGISTER';
  455. if (forms.joinType === 'digitalize') {
  456. joinType = 'SELECT_INSTRUMENT';
  457. }
  458. if (forms.joinType === 'tradition') {
  459. joinType = 'NOT_BUY_INSTRUMENT';
  460. }
  461. // 更新时间
  462. const id = await updateStat(
  463. pageTimer.counter.value,
  464. joinType,
  465. result.data.userId,
  466. forms.schoolId
  467. );
  468. forms.saveId = id;
  469. forms.saveUserId = id;
  470. pageTimer.counter.value = 0;
  471. // 获取用户信息
  472. const res = await request.get('/edu-app/user/getUserInfo', {
  473. requestType: 'form'
  474. });
  475. setLogin(res.data);
  476. await onRegisterSubmit();
  477. }
  478. } catch {
  479. } finally {
  480. forms.submitLoading = false;
  481. }
  482. };
  483. // 登记成功之后购买
  484. const onRegisterSubmit = async () => {
  485. try {
  486. // 请求是否有待支付订单,如果有则自动关闭
  487. const status = await paymentOrderUnpaid();
  488. if (status) return;
  489. const schoolInfo = await request.get(
  490. '/edu-app/userPaymentOrder/registerStatus/' + forms.schoolId
  491. );
  492. const vipList = studentRegisterStore.getVip;
  493. // 传统方式
  494. if (forms.joinType === 'tradition') {
  495. setTimeout(() => {
  496. showToast('报名成功');
  497. // router.push('/download');
  498. }, 100);
  499. setTimeout(() => {
  500. if (browser().weixin) {
  501. // 关闭微信
  502. (window as any).WeixinJSBridge.call('closeWindow');
  503. }
  504. }, 1000);
  505. return;
  506. }
  507. if (schoolInfo.data.hasBuyCourse && vipList.length > 0) {
  508. forms.dialogConfirmStatus = true;
  509. return;
  510. }
  511. await paymentContinue();
  512. } catch {
  513. //
  514. }
  515. };
  516. const getUserInfos = async () => {
  517. if (
  518. studentInfo.password.length !== 6 ||
  519. !checkPhone(studentInfo.username)
  520. ) {
  521. return;
  522. }
  523. try {
  524. // 15907120131;
  525. const { data } = await request.get(
  526. `/edu-app/open/student/studentInfo?mobile=${studentInfo.username}&code=${studentInfo.password}&type=REGISTER`
  527. );
  528. if (data) {
  529. if (!studentInfo.extra.nickname) {
  530. studentInfo.extra.nickname = data.nickname;
  531. }
  532. if (!studentInfo.extra.currentGradeNum) {
  533. const tempGrade: any = forms.gradeList || [];
  534. // console.log(tempGrade, 'tempGrade');
  535. tempGrade?.forEach((i: any) => {
  536. if (i.value === data.currentGradeNum) {
  537. forms.instrumentCode = i.instrumentCode;
  538. forms.gradeNumText = i.text;
  539. studentInfo.extra.currentGradeNum = data.currentGradeNum;
  540. if (forms.schoolInstrumentSetType === 'CLASS') {
  541. forms.classList = i.classList;
  542. }
  543. }
  544. });
  545. }
  546. if (!studentInfo.extra.currentClass) {
  547. forms.classList.forEach((i: any) => {
  548. if (i.value === data.currentClass) {
  549. forms.currentClassText = i.text;
  550. studentInfo.extra.currentClass = data.currentClass;
  551. }
  552. });
  553. }
  554. studentInfo.extra.gender =
  555. studentInfo.extra.gender !== data.gender
  556. ? data.gender
  557. : studentInfo.extra.gender;
  558. }
  559. } catch {
  560. //
  561. }
  562. };
  563. // 查询未支付订单
  564. const paymentOrderUnpaid = async () => {
  565. let result = false;
  566. try {
  567. const { data } = await request.get(
  568. '/edu-app/userPaymentOrder/schoolRegisterOrder?schoolId=' +
  569. forms.schoolId
  570. );
  571. // 判断是否有待支付订单
  572. if (data && data.length > 0) {
  573. let isPadding = false; // 是否有待支付订单
  574. let paddingConfig = {} as any;
  575. let paddingData = {} as any;
  576. let isFinal = false; // 是否有完成订单
  577. let finalConfig = {} as any;
  578. data.forEach((element: any) => {
  579. // 判断是否待支付
  580. if (element.status === 'PAYING' || element.status === 'WAIT_PAY') {
  581. isPadding = true;
  582. paddingConfig = element.paymentConfig;
  583. paddingData = element;
  584. }
  585. if (
  586. element.status === 'PAID' ||
  587. element.status === 'PART_REFUNDED' ||
  588. element.status === 'REFUNDED'
  589. ) {
  590. isFinal = true;
  591. finalConfig = element.paymentConfig;
  592. }
  593. });
  594. // 判断是否有完成订单 并且选择 自备
  595. if (isFinal && forms.joinType === 'tradition') {
  596. setTimeout(() => {
  597. showToast('您已通过数字化方式报名成功');
  598. }, 100);
  599. return true;
  600. }
  601. // 提交报名信息时,判断该手机号是否存在待支付订单,若存则判断本次提交的报名方式,若本次提交的是团购则提示【您有待支付的报名订单,是否继续支付 重新下单/继续支付】,点击重新下单时,关闭老订单,创建新订单;若本次提交的是自备,则提示 【您有数字化方式报名的待支付订单,请关闭订单后重新报名 取消/关闭】取消则停留在当前界面,关闭则关闭订单,并停留在当前界面,用户需要再次点击报名按钮提交信息
  602. if (isPadding && forms.joinType === 'tradition') {
  603. forms.dialogStatus = true;
  604. forms.dialogMessage =
  605. '您有数字化方式报名的待支付订单,请关闭订单后重新报名';
  606. forms.cancelButtonText = '取消';
  607. forms.confirmButtonText = '关闭';
  608. forms.dialogConfig = paddingConfig;
  609. forms.messageAlign = 'left';
  610. return true;
  611. }
  612. if (isPadding && forms.joinType === 'digitalize') {
  613. // 会选判断逻辑 -
  614. await request.get(
  615. '/edu-app/userPaymentOrder/registerStatus/' + forms.schoolId
  616. );
  617. // const vipList = studentRegisterStore.getVip;
  618. // if (schoolInfo.data.hasBuyCourse && vipList.length > 0) {
  619. // forms.dialogConfirmStatus = true;
  620. // return true;
  621. // }
  622. // 最终确认,有待支付订单直接去支付,没有则才会创建订单
  623. state.config = paddingConfig?.paymentConfig;
  624. state.orderNo = paddingConfig?.orderNo;
  625. await lastSubmit();
  626. return true;
  627. // 判断是否可以取消订单
  628. // if (paddingData.cancelPayment) {
  629. // await request.post(
  630. // '/edu-app/userPaymentOrder/cancelPayment/' +
  631. // paddingConfig.orderNo
  632. // );
  633. // return false;
  634. // } else {
  635. // // forms.countDownTime = paddingData.cancelTimes;
  636. // // countDown.reset(Number(paddingData.cancelTimes));
  637. // // countDown.start();
  638. // // forms.dialogStatusMessage = `有待支付订单,请在${Math.ceil(
  639. // // countDown.current.value.total / 1000
  640. // // )}s后重试`;
  641. // // forms.dialogStatusVisible = true;
  642. // // forms.dialogConfig = paddingData;
  643. // // 继续支付
  644. // // const paymentConfig = forms.dialogConfig;
  645. // state.config = paddingConfig?.paymentConfig;
  646. // state.orderNo = paddingConfig?.orderNo;
  647. // await lastSubmit();
  648. // return true;
  649. // }
  650. }
  651. return false;
  652. } else {
  653. return false;
  654. }
  655. } catch {
  656. //
  657. }
  658. return result;
  659. };
  660. // 重新下单
  661. const resetOrderPayment = async () => {
  662. try {
  663. const orderNo = forms.dialogConfig?.orderNo;
  664. if (!orderNo) return;
  665. await request.post(
  666. '/edu-app/userPaymentOrder/cancelPayment/' + orderNo
  667. );
  668. await onRegisterSubmit();
  669. } catch {
  670. //
  671. }
  672. };
  673. // 取消订单
  674. const cancelPaymentOrder = async () => {
  675. try {
  676. const orderNo = forms.dialogConfig?.orderNo;
  677. if (!orderNo) return;
  678. await request.post(
  679. '/edu-app/userPaymentOrder/cancelPayment/' + orderNo
  680. );
  681. } catch {}
  682. };
  683. const paymentContinue = async () => {
  684. try {
  685. const vipList = studentRegisterStore.getVip;
  686. const goodsList = studentRegisterStore.getGoods;
  687. const params: any[] = [];
  688. vipList.forEach((vip: any) => {
  689. params.push({
  690. giftVipDay: vip.membershipDays,
  691. goodsId: vip.goodsId,
  692. goodsNum: 1,
  693. goodsType: vip.goodsType,
  694. paymentCashAmount: vip.currentPrice, // 现金支付金额
  695. paymentCouponAmount: 0 // 优惠券金额
  696. });
  697. });
  698. goodsList.forEach((goods: any) => {
  699. params.push({
  700. goodsId: goods.productId,
  701. goodsNum: goods.quantity,
  702. goodsType: 'INSTRUMENTS',
  703. paymentCashAmount: goods.price, // 现金支付金额
  704. paymentCouponAmount: 0, // 优惠券金额
  705. goodsSkuId: goods.productSkuId
  706. });
  707. });
  708. // 创建订单
  709. const result = await request.post(
  710. '/edu-app/userPaymentOrder/executeOrder',
  711. {
  712. // hideLoading: false,
  713. data: {
  714. buryId: forms.saveUserId,
  715. registerType: forms.registerType,
  716. paymentType: forms.paymentType,
  717. bizId: forms.schoolId, // 乐团编号
  718. orderType: 'SCHOOL_REGISTER',
  719. paymentCashAmount: calcPrice.value.amount || 0,
  720. paymentCouponAmount: 0,
  721. goodsInfos: params,
  722. orderName: '学生登记',
  723. orderDesc: '学生登记'
  724. }
  725. }
  726. );
  727. if (result.code === 5436) {
  728. forms.showTips = true;
  729. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  730. forms.showButton = false;
  731. } else if (result.code === 5435) {
  732. forms.showTips = true;
  733. forms.showMessage = result.message;
  734. forms.showButton = true;
  735. } else {
  736. state.config = {
  737. ...result.data.paymentConfig,
  738. paymentType: result.data.paymentType
  739. };
  740. state.orderNo = result.data.orderNo;
  741. await lastSubmit();
  742. }
  743. } catch (e: any) {
  744. console.log(e, 'any');
  745. }
  746. };
  747. const lastSubmit = async () => {
  748. try {
  749. const users = baseState.user.data;
  750. // 判断是否需要实名认证, 姓名,卡号 - 参数设置可以控制
  751. if (
  752. forms.contract_sign &&
  753. (!users?.account.realName || !users?.account.idCardNo)
  754. ) {
  755. state.authShow = true;
  756. return;
  757. }
  758. const { data } = await request.post(
  759. '/edu-app/userPaymentOrder/updateReceiveAddress',
  760. {
  761. // hideLoading: false,
  762. data: {
  763. orderNo: state.orderNo,
  764. orderType: 'SCHOOL_REGISTER'
  765. }
  766. }
  767. );
  768. state.pay_channel = data.paymentChannel;
  769. if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
  770. router.replace({
  771. path: '/payment-result',
  772. query: {
  773. orderNo: state.orderNo
  774. }
  775. });
  776. } else {
  777. onCallback();
  778. }
  779. } catch {
  780. //
  781. }
  782. };
  783. /**
  784. * @description 回调,判断是否有支付渠道,如果有则直接去支付
  785. * @returns void
  786. */
  787. const onCallback = () => {
  788. const pt = state.pay_channel;
  789. // 判断是否有支付方式
  790. if (pt) {
  791. const payCode: string = beforeSubmit(state.pay_channel);
  792. onConfirm({
  793. payCode,
  794. pay_channel: pt
  795. });
  796. } else {
  797. if (orderType.value === 'VIP') {
  798. state.paymentStatus = true;
  799. } else {
  800. // 直接去拉取微信支付
  801. onConfirm({
  802. payCode: 'payResult',
  803. pay_channel: 'wx_pub'
  804. });
  805. }
  806. }
  807. };
  808. const onConfirm = (val: any) => {
  809. const config: any = state.config;
  810. state.pay_channel = val.pay_channel;
  811. const params = qs.stringify({
  812. pay_channel: val.pay_channel,
  813. wxAppId: config.wxAppId,
  814. alipayAppId: config.alipayAppId,
  815. paymentType: forms.paymentType,
  816. body: config.body,
  817. price: config.price,
  818. orderNo: config.merOrderNo,
  819. userId: config.userId
  820. });
  821. // console.log(params, state.config);
  822. // return;
  823. if (val.payCode === 'payResult') {
  824. window.location.href =
  825. window.location.origin + '/classroom-app/#/payResult?' + params;
  826. } else {
  827. state.qrCodeUrl =
  828. window.location.origin + '/classroom-app/#/payDefine?' + params;
  829. state.showQrcode = true;
  830. state.paymentStatus = false;
  831. setTimeout(() => {
  832. getPaymentOrderStatus();
  833. }, 300);
  834. }
  835. };
  836. // 放弃支付时,则取消订单
  837. const onBackOut = async () => {
  838. try {
  839. await request.post(
  840. '/edu-app/userPaymentOrder/cancelPayment/' + state.orderNo
  841. );
  842. // router.back();
  843. } catch {
  844. //
  845. }
  846. };
  847. // 轮询查询订单状态
  848. const getPaymentOrderStatus = async () => {
  849. // 循环查询订单
  850. // const orderNo = state.orderNo
  851. const orderTimer = setInterval(async () => {
  852. // 判断是否在当前路由,如果不是则清除定时器
  853. if (route.name != 'student-register-form') {
  854. clearInterval(orderTimer);
  855. return;
  856. }
  857. state.orderTimer = orderTimer;
  858. try {
  859. const { data } = await request.post(
  860. '/edu-app/open/userOrder/paymentStatus/' + state.orderNo,
  861. {
  862. hideLoading: true
  863. }
  864. );
  865. if (data.status !== 'WAIT_PAY' && data.status !== 'PAYING') {
  866. // 默认关闭支付二维码弹窗
  867. state.showQrcode = false;
  868. clearInterval(state.orderTimer);
  869. setTimeout(() => {
  870. router.replace({
  871. path: '/payment-result',
  872. query: {
  873. orderNo: state.orderNo
  874. }
  875. });
  876. }, 100);
  877. }
  878. } catch {
  879. //
  880. clearInterval(state.orderTimer);
  881. }
  882. }, 5000);
  883. };
  884. // 实名认证成功
  885. const onAuthSuccess = () => {
  886. //
  887. state.authShow = false;
  888. paymentContinue(); // 实名成功后自动支付
  889. };
  890. /**
  891. * 页面停留时间
  892. * @param pageBrowseTime 停留时间
  893. * @param joinType 加入方式
  894. * @param userId 用户编号
  895. * @param schoolId 学校编号
  896. */
  897. const updateStat = async (
  898. pageBrowseTime = 5,
  899. joinType?: string,
  900. userId?: string,
  901. schoolId?: string
  902. ) => {
  903. try {
  904. const { data } = await requestStudent.post(
  905. '/edu-app/open/studentRegisterPointRecord/update',
  906. {
  907. data: {
  908. id: forms.saveId,
  909. useTime: pageBrowseTime, // 固定10秒
  910. joinType,
  911. userId,
  912. schoolId
  913. }
  914. }
  915. );
  916. forms.saveId = data;
  917. return data;
  918. } catch {
  919. //
  920. }
  921. };
  922. const getAppIdAndCode = async (url?: string) => {
  923. try {
  924. const { data } = await request.get(
  925. '/edu-app/open/paramConfig/wechatAppId'
  926. );
  927. // 判断是否有微信appId
  928. if (data) {
  929. closeToast();
  930. goWechatAuth(data, url);
  931. }
  932. } catch {
  933. //
  934. }
  935. };
  936. if (browser().weixin) {
  937. //授权
  938. const openId = sessionStorage.getItem('active-open-id');
  939. forms.openId = openId;
  940. const code = getUrlCode();
  941. if (!code) {
  942. const newUrl =
  943. window.location.origin +
  944. window.location.pathname +
  945. '#' +
  946. route.path +
  947. '?' +
  948. qs.stringify({
  949. ...route.query
  950. });
  951. getAppIdAndCode(newUrl);
  952. return '';
  953. } else {
  954. forms.code = code;
  955. }
  956. }
  957. const formatTimerTo = (num: number): string => {
  958. if (num > 9) {
  959. return num + '';
  960. } else {
  961. return '0' + num;
  962. }
  963. };
  964. const pagePointInit = async () => {
  965. try {
  966. // 判断是否获取微信code码
  967. if (!forms.code) return;
  968. const { data } = await request.post(
  969. '/edu-app/open/studentRegisterPointRecord/save',
  970. {
  971. data: {
  972. code: forms.code,
  973. schoolId: forms.schoolId,
  974. openId: forms.openId
  975. }
  976. }
  977. );
  978. forms.saveId = data.id;
  979. forms.openId = data.openId;
  980. sessionStorage.setItem('active-open-id', data.openId);
  981. // 间隔多少时间同步数据
  982. forms.intervalFnRef = useIntervalFn(async () => {
  983. // 页面时间恢复
  984. pageTimer.counter.value = 0;
  985. pageTimer.resume();
  986. // 同步数据时先进行有效时间进行保存
  987. await updateStat();
  988. }, 5000);
  989. } catch {}
  990. };
  991. onMounted(async () => {
  992. await getRegisterGoods();
  993. });
  994. onUnmounted(() => {
  995. forms.intervalFnRef?.pause(); // 暂停回调
  996. });
  997. return () => (
  998. <div class={styles['student-register']}>
  999. <div class={styles.studentRegisterContainer}>
  1000. {!forms.activeOverStatus && (
  1001. <div class={styles.countdownSection}>
  1002. <div class={styles.timer}>
  1003. <img src={icon3} class={styles.timerTitle} />
  1004. <div class={styles.timerAll}>
  1005. <span>{formatTimerTo(overCountDown.current.value.days)}</span>
  1006. <span>
  1007. {formatTimerTo(overCountDown.current.value.hours)}
  1008. </span>
  1009. <span>
  1010. {formatTimerTo(overCountDown.current.value.minutes)}
  1011. </span>
  1012. <span>
  1013. {formatTimerTo(overCountDown.current.value.seconds)}
  1014. </span>
  1015. </div>
  1016. </div>
  1017. <div class={styles.timerTip}>
  1018. 为了确保您能顺利参与学习,请在规定时间内报名。
  1019. </div>
  1020. </div>
  1021. )}
  1022. <div
  1023. class={[
  1024. styles.studentSection,
  1025. styles.studentSectionForm,
  1026. forms.giftVipDay <= 0 && styles.noSendDay
  1027. ]}
  1028. // style={{ display: 'none' }}
  1029. >
  1030. <div class={styles.title1}></div>
  1031. <Form labelAlign="left" class={styles.registerForm}>
  1032. <Field
  1033. clearable={false}
  1034. label="联系方式(直接监护人)"
  1035. placeholder="请输入手机号码"
  1036. type="tel"
  1037. required
  1038. autocomplete="off"
  1039. inputAlign="right"
  1040. class={styles.username}
  1041. v-model={studentInfo.username}
  1042. border={false}
  1043. maxlength={11}>
  1044. {{
  1045. label: () => (
  1046. <div>
  1047. 联系方式
  1048. {/* (直接监护人) */}
  1049. <p class={styles.tips}>(直接监护人)</p>
  1050. </div>
  1051. )
  1052. }}
  1053. </Field>
  1054. <div class={['van-hairline--bottom', styles.fieldTipsGroup]}>
  1055. <div class={[styles.fieldTips]}>
  1056. 手机号是音乐数字课堂的唯一登录账户
  1057. </div>
  1058. </div>
  1059. <Field
  1060. center
  1061. clearable={false}
  1062. required
  1063. inputAlign="right"
  1064. label="验证码"
  1065. placeholder="请输入验证码"
  1066. autocomplete="off"
  1067. type="number"
  1068. v-model={studentInfo.password}
  1069. maxlength={6}
  1070. onUpdate:modelValue={(val: any) => {
  1071. getUserInfos();
  1072. }}>
  1073. {{
  1074. button: () =>
  1075. forms.countDownStatus ? (
  1076. <span
  1077. class={[
  1078. styles.codeText,
  1079. !validatePhone.value ? styles.codeTextDisabled : ''
  1080. ]}
  1081. onClick={onSendCode}>
  1082. 获取验证码
  1083. </span>
  1084. ) : (
  1085. <CountDown
  1086. ref={(el: any) => (countDownRef.value = el)}
  1087. auto-start={false}
  1088. class={styles.countDown}
  1089. time={forms.countDownTime}
  1090. onFinish={onFinished}
  1091. format="ss秒后重试"
  1092. />
  1093. )
  1094. }}
  1095. </Field>
  1096. <Field
  1097. clearable={false}
  1098. required
  1099. inputAlign="right"
  1100. label="学生姓名"
  1101. placeholder="请输入学生姓名"
  1102. autocomplete="off"
  1103. maxlength={14}
  1104. v-model={studentInfo.extra.nickname}
  1105. />
  1106. <Field
  1107. clearable={false}
  1108. required
  1109. inputAlign="right"
  1110. label="学生性别"
  1111. placeholder="请选择性别"
  1112. autocomplete="off"
  1113. // v-model={studentInfo.extra.nickname}
  1114. >
  1115. {{
  1116. input: () => (
  1117. <RadioGroup
  1118. checked-color="linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)"
  1119. v-model={studentInfo.extra.gender}
  1120. direction="horizontal">
  1121. <Tag
  1122. size="large"
  1123. type="primary"
  1124. color={
  1125. !(studentInfo.extra.gender === 1)
  1126. ? '#F5F6FA'
  1127. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  1128. }
  1129. textColor={
  1130. !(studentInfo.extra.gender === 1) ? '#626264' : '#fff'
  1131. }
  1132. class={styles.radioSection}>
  1133. <Radio class={styles.radioItem} name={1}></Radio>男
  1134. </Tag>
  1135. <Tag
  1136. size="large"
  1137. type="primary"
  1138. color={
  1139. !(studentInfo.extra.gender === 0)
  1140. ? '#F5F6FA'
  1141. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  1142. }
  1143. textColor={
  1144. !(studentInfo.extra.gender === 0) ? '#626264' : '#fff'
  1145. }
  1146. class={styles.radioSection}>
  1147. <Radio class={styles.radioItem} name={0}></Radio>女
  1148. </Tag>
  1149. </RadioGroup>
  1150. )
  1151. }}
  1152. </Field>
  1153. <Field
  1154. clearable={false}
  1155. required
  1156. inputAlign="right"
  1157. label="所在年级"
  1158. placeholder="请选择年级"
  1159. isLink
  1160. readonly
  1161. clickable={false}
  1162. modelValue={forms.gradeNumText}
  1163. onClick={() => {
  1164. forms.gradePopupIndex = [studentInfo.extra.currentGradeNum];
  1165. forms.gradeStatus = true;
  1166. }}
  1167. />
  1168. <Field
  1169. clearable={false}
  1170. required
  1171. inputAlign="right"
  1172. label="所在班级"
  1173. placeholder="请选择班级"
  1174. isLink
  1175. readonly
  1176. clickable={false}
  1177. modelValue={forms.currentClassText}
  1178. onClick={() => {
  1179. if (
  1180. forms.schoolInstrumentSetType === 'CLASS' &&
  1181. forms.classList.length <= 0
  1182. ) {
  1183. showToast('请先选择年级');
  1184. return;
  1185. }
  1186. forms.classPopupIndex = [studentInfo.extra.currentClass];
  1187. forms.classStatus = true;
  1188. }}
  1189. />
  1190. {forms.giftVipDay > 0 ? (
  1191. <div class={styles.memberNumer}>
  1192. <img src={iconGift} class={styles.iconGift} />
  1193. <p>
  1194. 注册成功即可获得乐器AI学练工具
  1195. <span>{forms.giftVipDay || 0}</span>天有效期
  1196. </p>
  1197. </div>
  1198. ) : (
  1199. ''
  1200. )}
  1201. </Form>
  1202. </div>
  1203. <div class={styles.studentSection}>
  1204. <div class={styles.title2}></div>
  1205. <div class={styles.goodsGroup}>
  1206. <div
  1207. class={[
  1208. styles.goodsItem,
  1209. styles.digitalize,
  1210. forms.joinType === 'digitalize' && styles.checked
  1211. ]}
  1212. onClick={() => {
  1213. //
  1214. if (checkForm()) {
  1215. showToast('请将资料填写完整');
  1216. return;
  1217. }
  1218. forms.joinType = 'digitalize';
  1219. nextTick(() => {
  1220. mstickyRef.value?.onChnageHeight();
  1221. setTimeout(() => {
  1222. window.scrollTo(0, 1000);
  1223. }, 50);
  1224. });
  1225. }}>
  1226. <div class={styles.goodsInner}>
  1227. <i class={styles.proposalTip}></i>
  1228. 数字化方式
  1229. </div>
  1230. </div>
  1231. <div
  1232. class={[
  1233. styles.goodsItem,
  1234. styles.tradition,
  1235. forms.joinType === 'tradition' && styles.checked1
  1236. ]}
  1237. onClick={() => {
  1238. if (checkForm()) {
  1239. showToast('请将资料填写完整');
  1240. return;
  1241. }
  1242. forms.joinType = 'tradition';
  1243. nextTick(() => {
  1244. mstickyRef.value?.onChnageHeight();
  1245. setTimeout(() => {
  1246. window.scrollTo(0, 1000);
  1247. }, 50);
  1248. });
  1249. }}>
  1250. <div class={styles.goodsInner}>传统方式</div>
  1251. </div>
  1252. </div>
  1253. </div>
  1254. {forms.joinType === 'digitalize' && (
  1255. <div class={[styles.goodsExtra]}>
  1256. <i class={styles.iconArrow}></i>
  1257. <Cell border={false} class={styles.goodsCell}>
  1258. {{
  1259. icon: () => (
  1260. <Image
  1261. class={styles.img}
  1262. src={forms.detailVip.goodsUrl || tuangou}
  1263. />
  1264. ),
  1265. title: () => (
  1266. <div class={styles.section}>
  1267. <div class={styles.sectionContent}>
  1268. <h2>
  1269. {/* {forms.detailVip.goodsName} */}
  1270. <img src={icon5} class={styles.goodsName} />
  1271. <Tag class={styles.brandName}>
  1272. {/* {forms.detailVip.brandName} */}
  1273. 12个月
  1274. </Tag>
  1275. </h2>
  1276. <p class={[styles.model]}>
  1277. {/* 解决学生不会练、不知练的对错、家长无法辅导、无需再额外请老师 */}
  1278. {/* {forms.detailVip.description} */}
  1279. <p>
  1280. <i></i>解决学生不会练、不知练的对错
  1281. </p>
  1282. <p>
  1283. <i></i>家长无法辅导、无需再额外请老师
  1284. </p>
  1285. </p>
  1286. {/* <span class={styles.sendInstrument}>赠送课堂乐器</span> */}
  1287. <img src={icon6} class={styles.sendInstrument} />
  1288. </div>
  1289. </div>
  1290. )
  1291. }}
  1292. </Cell>
  1293. {forms.detailVip.membershipDays ? (
  1294. <div class={styles.memberNumer}>
  1295. <img src={iconGift} class={styles.iconGift} />
  1296. <p>
  1297. 现在购买赠送乐器AI学练工具
  1298. <span>{forms.detailVip.membershipDays || 0}</span>天有效期
  1299. </p>
  1300. </div>
  1301. ) : (
  1302. ''
  1303. )}
  1304. </div>
  1305. )}
  1306. {forms.joinType === 'tradition' && (
  1307. <div class={styles.goodsTradition}>
  1308. <i class={styles.iconArrow}></i>
  1309. <div class={styles.goodsTitle}></div>
  1310. <div class={styles.steps}>
  1311. <div class={styles.step}>
  1312. <span class={styles.nums}>
  1313. <span class={styles.numInner}>1</span>
  1314. </span>
  1315. <div class={styles.stepContent}>
  1316. <span>AI工具标准:</span>
  1317. 可以学练音乐教材中的乐曲,通过手机应用商店准备。
  1318. </div>
  1319. </div>
  1320. {['Panpipes', 'Ocarina', 'Tenor Recorder', 'Woodwind'].includes(
  1321. forms.instrumentCode
  1322. ) && (
  1323. <div class={styles.step}>
  1324. <span class={styles.nums}>
  1325. <span class={styles.numInner}>2</span>
  1326. </span>
  1327. <div class={styles.stepContent}>
  1328. <span>
  1329. {forms.instrumentCode === 'Panpipes' && '排箫'}
  1330. {forms.instrumentCode === 'Ocarina' && '陶笛'}
  1331. {forms.instrumentCode === 'Tenor Recorder' && '竖笛'}
  1332. {forms.instrumentCode === 'Woodwind' && '葫芦丝'}
  1333. 标准:
  1334. </span>
  1335. {forms.instrumentCode === 'Panpipes' &&
  1336. '管数不限,建议20管以上C调加嘴排箫(不需要重复更换),黑色,选择单一原调(调性多很难掌握);'}
  1337. {forms.instrumentCode === 'Ocarina' &&
  1338. 'C调、蓝色、十二孔高音、树脂或陶土均可;'}
  1339. {forms.instrumentCode === 'Tenor Recorder' &&
  1340. 'C调、木质、高音德式八孔;'}
  1341. {forms.instrumentCode === 'Woodwind' &&
  1342. 'C调、红木色、树脂或木质;'}
  1343. {/* 管数不限,建议20管以上C调加嘴排箫(音域宽,能演奏更多复杂乐曲,不需要重复更换),黑色,要选择单一原调(调性多学生很难掌握),价格由学生根据自身情况确定。 */}
  1344. </div>
  1345. </div>
  1346. )}
  1347. </div>
  1348. </div>
  1349. )}
  1350. {forms.joinType && (
  1351. <MSticky position="bottom" ref={mstickyRef}>
  1352. <div class={styles.paymentContainer}>
  1353. {forms.joinType === 'digitalize' && (
  1354. <>
  1355. <div class={styles.payemntPrice}>
  1356. <img src={giftTip} class={styles.giftTip} />
  1357. <div>
  1358. <span class={styles.needPrice}>
  1359. <i style="font-style: normal">¥ </i>
  1360. <span>{moneyFormat(calcPrice.value.amount)}</span>
  1361. <i class={styles.unit} style="font-style: normal">
  1362. /年
  1363. </i>
  1364. </span>
  1365. {calcPrice.value.originAmount >
  1366. calcPrice.value.amount ? (
  1367. <del class={styles.allPrice}>
  1368. ¥ {moneyFormat(calcPrice.value.originAmount)}
  1369. </del>
  1370. ) : (
  1371. ''
  1372. )}
  1373. </div>
  1374. </div>
  1375. <div
  1376. class={styles.paymentBtn}
  1377. onClick={() => {
  1378. onSubmit();
  1379. }}>
  1380. <Button
  1381. round
  1382. disabled={forms.submitLoading}
  1383. loading={forms.submitLoading}>
  1384. 立即支付
  1385. </Button>
  1386. </div>
  1387. </>
  1388. )}
  1389. {forms.joinType === 'tradition' && (
  1390. <div
  1391. class={styles.traditionBtn}
  1392. onClick={() => {
  1393. onSubmit();
  1394. }}>
  1395. <Button
  1396. round
  1397. disabled={forms.submitLoading}
  1398. loading={forms.submitLoading}>
  1399. 提交报名
  1400. </Button>
  1401. </div>
  1402. )}
  1403. </div>
  1404. </MSticky>
  1405. )}
  1406. </div>
  1407. {forms.imgCodeStatus ? (
  1408. <MImgCode
  1409. v-model:value={forms.imgCodeStatus}
  1410. phone={studentInfo.username}
  1411. type="REGISTER"
  1412. onClose={() => {
  1413. forms.imgCodeStatus = false;
  1414. }}
  1415. onSendCode={onCodeSend}
  1416. />
  1417. ) : null}
  1418. {/* 年级 */}
  1419. <Popup
  1420. v-model:show={forms.gradeStatus}
  1421. position="bottom"
  1422. round
  1423. safeAreaInsetBottom
  1424. lazyRender={false}
  1425. class={'popupBottomSearch'}>
  1426. <Picker
  1427. showToolbar
  1428. v-model={forms.gradePopupIndex}
  1429. columns={forms.gradeList}
  1430. onCancel={() => (forms.gradeStatus = false)}
  1431. onConfirm={(val: any) => {
  1432. const selectedOption = val.selectedOptions[0];
  1433. studentInfo.extra.currentGradeNum = selectedOption.value;
  1434. forms.gradeNumText = selectedOption.text;
  1435. forms.gradeStatus = false;
  1436. if (['SCHOOL', 'GRADE'].includes(forms.schoolInstrumentSetType)) {
  1437. forms.instrumentCode = selectedOption.instrumentCode;
  1438. }
  1439. if (forms.schoolInstrumentSetType === 'CLASS') {
  1440. forms.classList = selectedOption.classList;
  1441. }
  1442. if (['CLASS', 'GRADE'].includes(forms.schoolInstrumentSetType)) {
  1443. forms.currentClassText = '';
  1444. studentInfo.extra.currentClass = '';
  1445. }
  1446. }}
  1447. />
  1448. </Popup>
  1449. {/* 班级 */}
  1450. <Popup
  1451. v-model:show={forms.classStatus}
  1452. position="bottom"
  1453. round
  1454. class={'popupBottomSearch'}>
  1455. <Picker
  1456. showToolbar
  1457. v-model={forms.classPopupIndex}
  1458. columns={forms.classList}
  1459. onCancel={() => (forms.classStatus = false)}
  1460. onConfirm={(val: any) => {
  1461. const selectedOption = val.selectedOptions[0];
  1462. studentInfo.extra.currentClass = selectedOption.value;
  1463. forms.currentClassText = selectedOption.text;
  1464. forms.classStatus = false;
  1465. if (['CLASS'].includes(forms.schoolInstrumentSetType)) {
  1466. forms.instrumentCode = selectedOption.instrumentCode;
  1467. }
  1468. }}
  1469. />
  1470. </Popup>
  1471. {/* 已经购买过样品 */}
  1472. <MDialog
  1473. title="提示"
  1474. v-model:show={forms.dialogConfirmStatus}
  1475. message={'已购买会员,是否确认购买?'}
  1476. primaryColor="#FF8057"
  1477. allowHtml={true}
  1478. confirmButtonText="确定"
  1479. showCancelButton
  1480. onConfirm={async () => {
  1481. await paymentContinue();
  1482. }}
  1483. onCancel={() => {
  1484. //取消支付,判断是否有结束时间,是否已经结束
  1485. if (forms.registerExpireTime && forms.activeOverStatus) {
  1486. applyOver();
  1487. }
  1488. }}
  1489. />
  1490. {/* <MDialog
  1491. title="提示"
  1492. v-model:show={forms.dialogStatusVisible}
  1493. message={forms.dialogStatusMessage}
  1494. allowHtml={true}
  1495. primaryColor="#FF8057"
  1496. confirmButtonText="继续支付"
  1497. onConfirm={async () => {
  1498. countDown.pause();
  1499. const paymentConfig = forms.dialogConfig.paymentConfig;
  1500. state.config = paymentConfig?.paymentConfig;
  1501. state.orderNo = paymentConfig?.orderNo;
  1502. await lastSubmit();
  1503. }}
  1504. onCancel={(val: any) => {
  1505. countDown.pause();
  1506. //取消支付,判断是否有结束时间,是否已经结束
  1507. if (forms.registerExpireTime && forms.activeOverStatus) {
  1508. applyOver();
  1509. }
  1510. }}
  1511. /> */}
  1512. <MDialog
  1513. title="提示"
  1514. v-model:show={forms.dialogStatus}
  1515. message={forms.dialogMessage}
  1516. allowHtml={true}
  1517. primaryColor="#FF8057"
  1518. showCancelButton={true}
  1519. messageAlign={forms.messageAlign}
  1520. confirmButtonText={forms.confirmButtonText}
  1521. cancelButtonText={forms.cancelButtonText}
  1522. onConfirm={async () => {
  1523. if (forms.joinType === 'tradition') {
  1524. //
  1525. await cancelPaymentOrder();
  1526. //取消支付,判断是否有结束时间,是否已经结束
  1527. if (forms.registerExpireTime && forms.activeOverStatus) {
  1528. applyOver();
  1529. }
  1530. }
  1531. if (forms.joinType === 'digitalize') {
  1532. // 继续支付
  1533. const paymentConfig = forms.dialogConfig;
  1534. state.config = paymentConfig?.paymentConfig;
  1535. state.orderNo = paymentConfig?.orderNo;
  1536. await lastSubmit();
  1537. }
  1538. }}
  1539. onCancel={(val: any) => {
  1540. // countDown.pause();
  1541. if (forms.joinType === 'tradition') {
  1542. forms.dialogStatus = false;
  1543. //取消支付,判断是否有结束时间,是否已经结束
  1544. if (forms.registerExpireTime && forms.activeOverStatus) {
  1545. applyOver();
  1546. }
  1547. }
  1548. if (forms.joinType === 'digitalize') {
  1549. // 重新下单 - 先关闭订单
  1550. resetOrderPayment();
  1551. }
  1552. }}
  1553. />
  1554. <Popup
  1555. show={state.paymentStatus}
  1556. closeOnClickOverlay={false}
  1557. position="bottom"
  1558. round
  1559. closeOnPopstate
  1560. safeAreaInsetBottom
  1561. style={{ minHeight: '30%' }}>
  1562. <Payment
  1563. paymentConfig={state.orderInfo}
  1564. onClose={() => (state.paymentStatus = false)}
  1565. onBackOut={onBackOut}
  1566. onConfirm={(val: any) => onConfirm(val)}
  1567. />
  1568. </Popup>
  1569. <Popup
  1570. v-model:show={state.showQrcode}
  1571. round
  1572. onClose={() => {
  1573. // 二维码关闭时清除定时器
  1574. clearInterval(state.orderTimer);
  1575. }}>
  1576. <QrcodePayment
  1577. url={state.qrCodeUrl}
  1578. pay_channel={state.pay_channel}
  1579. orderType={orderType.value}
  1580. />
  1581. </Popup>
  1582. <MPopup v-model:modelValue={state.authShow}>
  1583. <UserAuth onSuccess={onAuthSuccess} hideHeader={!browser().isApp} />
  1584. </MPopup>
  1585. {/* 是否在微信中打开 */}
  1586. <OWxTip
  1587. show={forms.showTips}
  1588. message={forms.showMessage}
  1589. showButton={forms.showButton}
  1590. buttonText="刷新"
  1591. onConfirm={() => window.location.reload()}
  1592. />
  1593. </div>
  1594. );
  1595. }
  1596. });