index.tsx 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363
  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. Popover,
  16. Area,
  17. CellGroup,
  18. showConfirmDialog
  19. } from 'vant';
  20. import {
  21. computed,
  22. defineComponent,
  23. nextTick,
  24. onMounted,
  25. onUnmounted,
  26. reactive,
  27. ref
  28. } from 'vue';
  29. import qs from 'query-string';
  30. import {
  31. state as baseState,
  32. goWechatAuth,
  33. setLogin,
  34. setLoginInit
  35. } from '@/state';
  36. import styles from './index.module.less';
  37. import MSticky from '@/components/m-sticky';
  38. // import MVideo from '@/components/m-video';
  39. import { useRoute, useRouter } from 'vue-router';
  40. import { useStudentRegisterStore } from '@/store/modules/student-register-store';
  41. import request from '@/helpers/request';
  42. import { browser, checkPhone, getUrlCode, moneyFormat } from '@/helpers/utils';
  43. import deepClone from '@/helpers/deep-clone';
  44. import OWxTip from '@/components/m-wx-tip';
  45. import MDialog from '@/components/m-dialog';
  46. // import f1 from './images/new/f-1.png';
  47. // import f2 from './images/new/f-2.png';
  48. // import f3 from './images/new/f-3.png';
  49. // import iconTip2 from './images/new/icon-tip2.png';
  50. // import functionBg from './images/new/function-bg.png';
  51. // import tuangou from './images/new/tuangou.png';
  52. // import icon3 from './images/new/icon-3.png';
  53. // import icon5 from './images/new/icon-5.png';
  54. // import icon10 from './images/new/icon-10.png';
  55. // import icon6 from './images/new/icon-6.png';
  56. // import giftTip from './images/new/icon-9.png';
  57. // import iconGift from './images/new/icon-gift.png';
  58. // import vipGiftTIps from './images/new/vip_gift_tips.png';
  59. import dayjs from 'dayjs';
  60. // import MMessageTip from '@/components/m-message-tip';
  61. import { CurrentTime, useCountDown } from '@vant/use';
  62. import MImgCode from '@/components/m-img-code';
  63. import { useInterval, useIntervalFn } from '@vueuse/core';
  64. import MMessageTip from '@/components/m-message-tip';
  65. import SelectStudent from '@/views/student-register/modal/select-student';
  66. import { api_sysAreaQueryAllProvince } from '@/views/school-register/api';
  67. import CodeDialog from '../modal/code-dialog';
  68. import MSearch from '@/components/m-search';
  69. const classList: any = [];
  70. for (let i = 1; i <= 40; i++) {
  71. classList.push({ text: i + '班', value: i });
  72. }
  73. const GRADE_ENUM = {
  74. '1': '一年级',
  75. '2': '二年级',
  76. '3': '三年级',
  77. '4': '四年级',
  78. '5': '五年级',
  79. '6': '六年级',
  80. '7': '七年级',
  81. '8': '八年级',
  82. '9': '九年级'
  83. } as any;
  84. const getGradeList = (gradeYear?: string, instrumentCode?: string) => {
  85. let tempList: any = [];
  86. const five = [
  87. { text: '一年级', value: 1, instrumentCode },
  88. { text: '二年级', value: 2, instrumentCode },
  89. { text: '三年级', value: 3, instrumentCode },
  90. { text: '四年级', value: 4, instrumentCode },
  91. { text: '五年级', value: 5, instrumentCode }
  92. ];
  93. const one = [{ text: '六年级', value: 6, instrumentCode }];
  94. const three = [
  95. { text: '七年级', value: 7, instrumentCode },
  96. { text: '八年级', value: 8, instrumentCode },
  97. { text: '九年级', value: 9, instrumentCode }
  98. ];
  99. if (gradeYear === 'FIVE_YEAR_SYSTEM') {
  100. tempList.push(...[...five]);
  101. } else if (gradeYear === 'SIX_YEAR_SYSTEM') {
  102. tempList.push(...[...five, ...one]);
  103. } else if (gradeYear === 'THREE_YEAR_SYSTEM') {
  104. tempList.push(...[...three]);
  105. } else if (gradeYear === 'FORE_YEAR_SYSTEM') {
  106. tempList.push(...[...one, ...three]);
  107. } else {
  108. tempList.push(...[...five, ...one, ...three]);
  109. }
  110. return tempList;
  111. };
  112. export default defineComponent({
  113. name: 'activation-register',
  114. setup() {
  115. const route = useRoute();
  116. const studentRegisterStore = useStudentRegisterStore();
  117. const router = useRouter();
  118. // 初始化学校编号
  119. // studentRegisterStore.setShoolId(route.query.sId as any);
  120. const countDownRef = ref();
  121. const forms = reactive({
  122. schoolId: null as any,
  123. schoolAreaId: null, // 学校区域编号
  124. activationCode: route.query.code as any, // 互通码
  125. paymentType: '', // 支付类型
  126. paymentChannel: '',
  127. multi_user_limit: 1, // 限制注册学生数量
  128. // popupShow: false,
  129. registerDetails: {} as any,
  130. details: [] as any[],
  131. // schoolType: '', // 学校类型
  132. gradeYear: '', // 学制
  133. schoolInstrumentSetType: null as any,
  134. // bugGoods: false, // 是否购买AI
  135. isRegister: 'create' as 'create' | 'update' | '', // 是否注册学生
  136. isDisabled: false,
  137. isTipRegister: false, // 是否显示名字不一致 - 默认显示
  138. isChangeSchool: false, // 是否切换学校
  139. schoolStatus: false,
  140. schoolPopupShow: false,
  141. schoolLoading: false,
  142. schoolAreaList: [] as any,
  143. provinceCode: null,
  144. cityCode: null,
  145. regionCode: null,
  146. showResultPopup: false,
  147. reslutPopupType: '' as any,
  148. resultPopupContent: '',
  149. registerType: '', // 报名类型
  150. detailVip: {} as any,
  151. giftVipDay: 0, // 赠送天数
  152. submitLoading: false,
  153. // showMore: true,
  154. showTips: false,
  155. showButton: false,
  156. showMessage: '请使用微信扫描二维码',
  157. countDownStatus: true,
  158. countDownTime: 1000 * 120, // 倒计时时间
  159. // modelValue: false, // 是否选中协议
  160. imgCodeStatus: false,
  161. gradeNumText: '',
  162. currentClassText: '',
  163. schoolName: '',
  164. areaName: '',
  165. gradeStatus: false,
  166. classStatus: false,
  167. loading: false,
  168. showConfirmPopup: false, // 二次确认用户信息
  169. showPicker: false,
  170. areaList: [] as any,
  171. tipStatus: true,
  172. dialogConfirmStatus: false,
  173. contract_sign: false, // 是否实名认证
  174. countDownTimePay: 60 * 1000,
  175. dialogConfig: {} as any,
  176. showSelectStudent: false, // 选择学生
  177. studentList: [], // 手机号关联学生列表
  178. studentItem: {} as any, // 选择的学生
  179. joinType: 'digitalize' as 'digitalize' | 'tradition',
  180. gradeList: [] as any,
  181. classList: [] as any,
  182. saveUserId: null as any,
  183. saveId: null as any,
  184. openId: null as any,
  185. code: null as any,
  186. registerExpireTime: null as any, // 结束时间
  187. instrumentCode: null as any, // 乐器编码
  188. activeOverTime: 0, // 活动结束时间
  189. activeOverStatus: true, // 活动是否结束 默认已结束
  190. gradePopupShow: false,
  191. gradePopupIndex: [] as any, // 年级下拉索引
  192. classPopupShow: false,
  193. classPopupIndex: [] as any // 班级下拉索引
  194. });
  195. const otherParams = reactive({
  196. showOtherSchool: false,
  197. showCloseButton: true, // 是否显示关闭按钮
  198. showOtherMessage: '',
  199. /** limit 超限制,change 更换学生,nickname 名称不一致 member 会员购买, payment 支付方式 */
  200. otherType: '' as 'limit' | 'change' | 'nickname' | 'member' | 'payment',
  201. showCancelButton: true,
  202. cancelButtonColor: '',
  203. cancelButtonText: '取消',
  204. showConfirmButton: true,
  205. confirmButtonColor: '',
  206. confirmButtonText: '确定',
  207. messageAlign: 'left' as 'center' | 'left' | 'right'
  208. });
  209. const state = reactive({
  210. showQrcode: false,
  211. qrCodeUrl: '',
  212. pay_channel: '',
  213. orderInfo: {} as any, // 订单信息
  214. authShow: false,
  215. orderNo: null as any,
  216. config: {} as any,
  217. paymentStatus: false,
  218. orderTimer: null as any
  219. });
  220. /*
  221. 新用户:
  222. autoRegister: true
  223. loginType: 'SMS'
  224. 已存在用户:
  225. autoRegister: false
  226. loginType: 'TOKEN'
  227. password: xxx
  228. */
  229. const studentInfo = reactive({
  230. autoRegister: true,
  231. multiUser: true, // 是否为多用户
  232. client_id: 'cooleshow-student',
  233. client_secret: 'cooleshow-student',
  234. extra: {
  235. nickname: '',
  236. currentGradeNum: '' as any,
  237. currentClass: '' as any,
  238. gender: 1 as any,
  239. registerType: null as any, // 报名类型
  240. giftVipDay: 0 // 赠送会员天数
  241. },
  242. grant_type: 'password',
  243. loginType: 'SMS',
  244. password: '',
  245. username: ''
  246. });
  247. // 页面定时
  248. const pageTimer = useInterval(1000, { controls: true });
  249. pageTimer.pause();
  250. const overCountDown = useCountDown({
  251. time: forms.activeOverTime,
  252. onFinish() {
  253. forms.activeOverStatus = true;
  254. if (forms.submitLoading) return;
  255. applyOver();
  256. }
  257. });
  258. /** 报名结束提示 */
  259. const applyOver = () => {
  260. forms.showTips = true;
  261. // forms.showMessage = '团购时间已截止,感谢您的参与';
  262. forms.showMessage =
  263. '<p style="color: #F44541">报名已截止,感谢您的参与</p>';
  264. forms.showButton = false;
  265. };
  266. const onCodeSend = () => {
  267. forms.countDownStatus = false;
  268. nextTick(() => {
  269. countDownRef.value.start();
  270. });
  271. };
  272. const onSendCode = () => {
  273. // 发送验证码
  274. if (!checkPhone(studentInfo.username)) {
  275. return showToast('请输入正确的手机号码');
  276. }
  277. forms.imgCodeStatus = true;
  278. };
  279. const validatePhone = computed(() => {
  280. return checkPhone(studentInfo.username) ? true : false;
  281. });
  282. const onFinished = () => {
  283. forms.countDownStatus = true;
  284. countDownRef.value.reset();
  285. };
  286. // 格式化提示状态
  287. const changeTipStatus = (register: boolean, school: boolean) => {
  288. forms.isTipRegister = register;
  289. forms.isChangeSchool = school;
  290. };
  291. const checkForm = (status = true) => {
  292. if (!checkPhone(studentInfo.username)) {
  293. status && showToast('请输入正确的手机号码');
  294. return true;
  295. } else if (!studentInfo.password) {
  296. status && showToast('请输入验证码');
  297. return true;
  298. } else if (!studentInfo.extra.nickname) {
  299. status && showToast('请输入学生姓名');
  300. return true;
  301. } else if (![0, 1].includes(studentInfo.extra.gender)) {
  302. status && showToast('请选择性别');
  303. return true;
  304. } else if (!studentInfo.extra.currentGradeNum) {
  305. status && showToast('请选择所在年级');
  306. return true;
  307. } else if (!studentInfo.extra.currentClass) {
  308. status && showToast('请选择所在班级');
  309. return true;
  310. } else if (!forms.activationCode) {
  311. status && showToast('请输入互通码');
  312. return true;
  313. }
  314. return false;
  315. };
  316. //
  317. const checkSubmit = () => {
  318. const { extra } = studentInfo;
  319. if (
  320. forms.studentItem.nickname !== extra.nickname &&
  321. forms.isTipRegister
  322. ) {
  323. otherParams.showOtherMessage =
  324. '学生姓名与上次提交信息不一致,请确认修改学生信息或创建新的学生账号';
  325. otherParams.showOtherSchool = true;
  326. otherParams.showCancelButton = true;
  327. otherParams.showCloseButton = true;
  328. otherParams.cancelButtonColor =
  329. 'linear-gradient( 224deg, #3FE1E6 0%, #00CDD4 100%)';
  330. otherParams.cancelButtonText = '新建学生';
  331. otherParams.confirmButtonColor =
  332. 'linear-gradient( 305deg, #40C8FF 0%, #3192FF 100%)';
  333. otherParams.confirmButtonText = '修改信息';
  334. otherParams.otherType = 'nickname';
  335. otherParams.messageAlign = 'left';
  336. return true;
  337. }
  338. // 判断新建学员是否上限了
  339. if (
  340. forms.isRegister === 'create' &&
  341. forms.studentList.length >= forms.multi_user_limit
  342. ) {
  343. otherParams.showOtherMessage = `同一手机号最多创建${forms.multi_user_limit}个学生`;
  344. otherParams.showOtherSchool = true;
  345. otherParams.showCancelButton = false;
  346. otherParams.showCloseButton = true;
  347. otherParams.confirmButtonColor =
  348. 'linear-gradient( 305deg, #40C8FF 0%, #3192FF 100%)';
  349. otherParams.confirmButtonText = '我知道了';
  350. otherParams.otherType = 'limit';
  351. otherParams.messageAlign = 'center';
  352. return true;
  353. }
  354. return false;
  355. };
  356. /**
  357. * 登记成功之后购买
  358. */
  359. const onSubmit = async () => {
  360. forms.submitLoading = true;
  361. try {
  362. if (checkForm() || checkSubmit()) {
  363. forms.submitLoading = false;
  364. return;
  365. }
  366. const { extra, loginType, autoRegister, password, multiUser, ...res } =
  367. studentInfo;
  368. /*
  369. 新用户:
  370. autoRegister: true
  371. loginType: 'SMS'
  372. 已存在用户:
  373. autoRegister: false
  374. loginType: 'TOKEN'
  375. password: xxx
  376. */
  377. let tLoginType = loginType,
  378. tAutoRegister = autoRegister,
  379. tPassword = password,
  380. tMultiUser = multiUser;
  381. if (forms.isRegister === 'update') {
  382. tLoginType = 'TOKEN';
  383. tAutoRegister = false;
  384. tPassword = forms.studentItem.token;
  385. tMultiUser = false;
  386. }
  387. const result = await request.post('/edu-app/userlogin', {
  388. requestType: 'form',
  389. data: {
  390. loginType: tLoginType,
  391. autoRegister: tAutoRegister,
  392. password: tPassword,
  393. multiUser: tMultiUser,
  394. ...res,
  395. extra: JSON.stringify({
  396. ...extra,
  397. // giftVipDay:
  398. // forms.detailVip.membershipDays || 0 + forms.giftVipDay || 0,
  399. schoolId: forms.schoolId
  400. })
  401. }
  402. });
  403. if (result.code !== 200) {
  404. if (result.code === 5436) {
  405. forms.showTips = true;
  406. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  407. forms.showButton = false;
  408. } else if (result.code === 5435) {
  409. forms.showTips = true;
  410. forms.showMessage = result.message;
  411. forms.showButton = true;
  412. }
  413. // else if (result.code === 5437) {
  414. // forms.showTips = true;
  415. // forms.showMessage =
  416. // '<p style="color: #F44541">报名已截止,感谢您的参与</p>'; //result.message;
  417. // forms.showButton = false;
  418. // }
  419. } else {
  420. studentRegisterStore.setToken(
  421. result.data.token_type + ' ' + result.data.access_token
  422. );
  423. setLoginInit();
  424. // let joinType = 'NOT_REGISTER';
  425. // if (forms.joinType === 'digitalize') {
  426. // joinType = 'SELECT_INSTRUMENT';
  427. // }
  428. // if (forms.joinType === 'tradition') {
  429. // joinType = 'NOT_BUY_INSTRUMENT';
  430. // }
  431. // 获取用户信息
  432. const res = await request.get('/edu-app/user/getUserInfo', {
  433. requestType: 'form'
  434. });
  435. setLogin(res.data);
  436. // await onRegisterSubmit();
  437. await updateStudentInfo();
  438. }
  439. } catch {
  440. // 重置信息 - 如果是新建则不提示
  441. changeTipStatus(forms.isRegister === 'create' ? false : true, false);
  442. } finally {
  443. forms.submitLoading = false;
  444. }
  445. };
  446. const updateStudentInfo = async () => {
  447. try {
  448. const { extra, username } = studentInfo;
  449. const registerResult = await request.post('/edu-app/student/register', {
  450. data: {
  451. clientType: 'STUDENT',
  452. ...extra,
  453. activationCode: forms.activationCode,
  454. schoolId: forms.schoolId,
  455. schoolAreaId: forms.schoolAreaId,
  456. // giftVipFlag: forms.registerDetails.giftVipFlag || false,
  457. // giftVipDay: forms.giftVipDay || 0,
  458. schoolVerify: false,
  459. // firstVipDay: forms.detailVip.membershipDays || 0,
  460. mobile: username,
  461. newRegUser: forms.isRegister === 'create' ? true : false
  462. }
  463. });
  464. if (registerResult.code !== 200) {
  465. if (registerResult.code === 5436) {
  466. forms.showTips = true;
  467. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  468. forms.showButton = false;
  469. } else if (registerResult.code === 5435) {
  470. forms.showTips = true;
  471. forms.showMessage = registerResult.message;
  472. forms.showButton = true;
  473. } else if (registerResult.code === 5437) {
  474. forms.showTips = true;
  475. forms.showMessage =
  476. '<p style="color: #F44541">报名已截止,感谢您的参与</p>'; //result.message;
  477. forms.showButton = false;
  478. } else if (registerResult.code === 5442) {
  479. forms.showResultPopup = true;
  480. forms.reslutPopupType = 'EXPIRED';
  481. forms.resultPopupContent = registerResult.message;
  482. } else if (registerResult.code === 5443) {
  483. forms.showResultPopup = true;
  484. forms.reslutPopupType = 'CANCELLED';
  485. forms.resultPopupContent = registerResult.message;
  486. }
  487. return false;
  488. } else {
  489. forms.showResultPopup = true;
  490. forms.reslutPopupType = 'ACTIVATING';
  491. return true;
  492. }
  493. } catch {}
  494. };
  495. const getUserInfos = async () => {
  496. if (
  497. studentInfo.password.length !== 6 ||
  498. !checkPhone(studentInfo.username)
  499. ) {
  500. return;
  501. }
  502. try {
  503. // 15907120131;
  504. const { data } = await request.get(
  505. `/edu-app/open/student/studentInfo?mobile=${studentInfo.username}&code=${studentInfo.password}&type=REGISTER`
  506. );
  507. forms.studentList = data || [];
  508. if (forms.studentList.length > 0) {
  509. const firstStudent: any = forms.studentList[0];
  510. forms.studentItem = firstStudent;
  511. studentInfo.extra.nickname = firstStudent.nickname;
  512. const tempArea = [] as any;
  513. if (firstStudent.provinceName) {
  514. tempArea.push(firstStudent.provinceName);
  515. forms.provinceCode = firstStudent.provinceCode;
  516. }
  517. if (firstStudent.cityName) {
  518. tempArea.push(firstStudent.cityName);
  519. forms.cityCode = firstStudent.cityCode;
  520. }
  521. if (firstStudent.regionName) {
  522. tempArea.push(firstStudent.regionName);
  523. forms.regionCode = firstStudent.regionCode;
  524. }
  525. forms.areaName = tempArea.join(' ');
  526. forms.schoolName = firstStudent.schoolName;
  527. forms.schoolId = firstStudent.schoolId;
  528. forms.schoolAreaId = firstStudent.schoolAreaId;
  529. const tempGrade: any = forms.gradeList || [];
  530. tempGrade?.forEach((i: any) => {
  531. if (i.value === firstStudent.currentGradeNum) {
  532. forms.instrumentCode = i.instrumentCode;
  533. forms.gradeNumText = i.text;
  534. studentInfo.extra.currentGradeNum = firstStudent.currentGradeNum;
  535. if (forms.schoolInstrumentSetType === 'CLASS') {
  536. forms.classList = i.classList;
  537. }
  538. }
  539. });
  540. forms.classList.forEach((i: any) => {
  541. if (i.value === firstStudent.currentClass) {
  542. forms.currentClassText = i.text;
  543. studentInfo.extra.currentClass = firstStudent.currentClass;
  544. }
  545. });
  546. studentInfo.extra.gender = firstStudent.gender;
  547. forms.isRegister = 'update';
  548. changeTipStatus(true, false);
  549. } else {
  550. forms.isRegister = 'create';
  551. changeTipStatus(false, false);
  552. forms.studentItem = [];
  553. }
  554. } catch {
  555. //
  556. }
  557. };
  558. /** 手机号变更时清空验证码信息,用户信息 */
  559. const phoneChangeEmptyInfo = () => {
  560. studentInfo.password = '';
  561. studentInfo.extra.nickname = '';
  562. studentInfo.extra.currentGradeNum = '';
  563. studentInfo.extra.currentClass = '';
  564. studentInfo.extra.gender = 1;
  565. forms.areaName = '';
  566. forms.schoolName = '';
  567. forms.currentClassText = '';
  568. forms.gradeNumText = '';
  569. forms.studentList = []; // 手机号关联学生列表
  570. forms.studentItem = {}; // 选择的学生
  571. forms.isRegister = 'create'; // 是否注册学生
  572. forms.isTipRegister = false; // 是否显示名字不一致 - 默认显示
  573. forms.isChangeSchool = false; // 是否切换学校
  574. };
  575. const formateArea = (area: any[]) => {
  576. const province_list: { [_: string]: string } = {};
  577. const city_list: { [_: string]: string } = {};
  578. const county_list: { [_: string]: string } = {};
  579. area.forEach((item: any) => {
  580. province_list[item.code] = item.name;
  581. });
  582. area.forEach((item: any) => {
  583. item.areas?.forEach((city: any) => {
  584. city_list[city.code] = city.name;
  585. });
  586. });
  587. area.forEach((item: any) => {
  588. item.areas?.forEach((city: any) => {
  589. city.areas?.forEach((county: any) => {
  590. county_list[county.code] = county.name;
  591. });
  592. });
  593. });
  594. return {
  595. province_list,
  596. city_list,
  597. county_list
  598. };
  599. };
  600. const getAreaList = () => {
  601. api_sysAreaQueryAllProvince().then(res => {
  602. if (res?.code === 200) {
  603. forms.areaList = formateArea(res.data);
  604. }
  605. });
  606. };
  607. const getSchoolAreaList = async (name?: string) => {
  608. forms.schoolLoading = true;
  609. try {
  610. const { data } = await request.post('/edu-app/schoolArea/list', {
  611. data: {
  612. name,
  613. provinceCode: forms.provinceCode,
  614. cityCode: forms.cityCode,
  615. regionCode: forms.regionCode
  616. }
  617. });
  618. forms.schoolAreaList = data;
  619. } catch {
  620. //
  621. }
  622. forms.schoolLoading = false;
  623. };
  624. onMounted(async () => {
  625. getAreaList();
  626. try {
  627. // 获取支付类型
  628. const { data } = await request.get(
  629. '/edu-app/open/paramConfig/queryByParamNameList',
  630. {
  631. requestType: 'form',
  632. params: {
  633. paramNames: 'multi_user_limit'
  634. }
  635. }
  636. );
  637. if (data && Array.isArray(data)) {
  638. data.forEach((item: any) => {
  639. if (item.paramName === 'multi_user_limit') {
  640. forms.multi_user_limit = item.paramValue
  641. ? Number(item.paramValue)
  642. : 1;
  643. }
  644. });
  645. }
  646. } catch {}
  647. forms.gradeList = getGradeList();
  648. forms.classList = classList;
  649. });
  650. return () => (
  651. <div class={styles['student-register']}>
  652. <div class={styles.studentRegisterContainer}>
  653. <div class={[styles.studentSection]}>
  654. <Form labelAlign="left" class={styles.registerForm}>
  655. <Field
  656. clearable={false}
  657. label="联系方式"
  658. placeholder="请输入手机号码"
  659. type="tel"
  660. required
  661. autocomplete="off"
  662. inputAlign="right"
  663. v-model={studentInfo.username}
  664. maxlength={11}
  665. onUpdate:modelValue={() => {
  666. phoneChangeEmptyInfo();
  667. }}></Field>
  668. <Field
  669. center
  670. clearable={false}
  671. required
  672. inputAlign="right"
  673. label="验证码"
  674. placeholder="请输入验证码"
  675. autocomplete="off"
  676. type="number"
  677. v-model={studentInfo.password}
  678. maxlength={6}
  679. onUpdate:modelValue={(val: any) => {
  680. getUserInfos();
  681. }}>
  682. {{
  683. button: () =>
  684. forms.countDownStatus ? (
  685. <span
  686. class={[
  687. styles.codeText,
  688. !validatePhone.value ? styles.codeTextDisabled : ''
  689. ]}
  690. onClick={onSendCode}>
  691. 获取验证码
  692. </span>
  693. ) : (
  694. <CountDown
  695. ref={(el: any) => (countDownRef.value = el)}
  696. auto-start={false}
  697. class={styles.countDown}
  698. time={forms.countDownTime}
  699. onFinish={onFinished}
  700. format="ss秒后重试"
  701. />
  702. )
  703. }}
  704. </Field>
  705. <Field
  706. clearable={false}
  707. required
  708. inputAlign="right"
  709. label="学生姓名"
  710. placeholder="请输入学生姓名"
  711. autocomplete="off"
  712. maxlength={14}
  713. v-model={studentInfo.extra.nickname}>
  714. {{
  715. extra: () =>
  716. forms.studentList.length > 1 && (
  717. <div
  718. class={[
  719. styles.selectStudentGroup,
  720. forms.showSelectStudent &&
  721. styles.selectStudentGroupChecked
  722. ]}
  723. onClick={() => (forms.showSelectStudent = true)}>
  724. <span>
  725. {forms.studentItem.userId ? '切换' : '新增'}
  726. </span>
  727. </div>
  728. )
  729. }}
  730. </Field>
  731. <Field
  732. clearable={false}
  733. required
  734. inputAlign="right"
  735. label="学生性别"
  736. placeholder="请选择性别"
  737. autocomplete="off">
  738. {{
  739. input: () => (
  740. <RadioGroup
  741. checked-color="linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)"
  742. v-model={studentInfo.extra.gender}
  743. direction="horizontal">
  744. <Tag
  745. size="large"
  746. type="primary"
  747. color={
  748. !(studentInfo.extra.gender === 1)
  749. ? '#F5F6FA'
  750. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  751. }
  752. textColor={
  753. !(studentInfo.extra.gender === 1) ? '#626264' : '#fff'
  754. }
  755. class={styles.radioSection}>
  756. <Radio class={styles.radioItem} name={1}></Radio>男
  757. </Tag>
  758. <Tag
  759. size="large"
  760. type="primary"
  761. color={
  762. !(studentInfo.extra.gender === 0)
  763. ? '#F5F6FA'
  764. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  765. }
  766. textColor={
  767. !(studentInfo.extra.gender === 0) ? '#626264' : '#fff'
  768. }
  769. class={styles.radioSection}>
  770. <Radio class={styles.radioItem} name={0}></Radio>女
  771. </Tag>
  772. </RadioGroup>
  773. )
  774. }}
  775. </Field>
  776. <Field
  777. clearable={false}
  778. required
  779. inputAlign="right"
  780. label="所在地区"
  781. placeholder="请选择所在地区"
  782. isLink={forms.isRegister !== 'update'}
  783. readonly
  784. clickable={false}
  785. modelValue={forms.areaName}
  786. onClick={() => {
  787. if (forms.isRegister !== 'update') forms.showPicker = true;
  788. // forms.gradePopupIndex = [studentInfo.extra.currentGradeNum];
  789. }}
  790. />
  791. <Field
  792. clearable={false}
  793. required
  794. inputAlign="right"
  795. label="互通学校"
  796. placeholder="请选择互通学校"
  797. isLink={forms.isRegister !== 'update'}
  798. readonly
  799. clickable={false}
  800. modelValue={forms.schoolName}
  801. onClick={() => {
  802. if (forms.isRegister === 'update') return;
  803. if (!forms.areaName) {
  804. showToast('请选择地区');
  805. return;
  806. }
  807. forms.schoolStatus = true;
  808. // forms.gradeStatus = true;
  809. // forms.gradePopupIndex = [studentInfo.extra.currentGradeNum];
  810. }}
  811. />
  812. <Field
  813. clearable={false}
  814. required
  815. inputAlign="right"
  816. label="所在年级"
  817. placeholder="请选择年级"
  818. isLink={forms.isRegister !== 'update'}
  819. readonly
  820. clickable={false}
  821. modelValue={forms.gradeNumText}
  822. onClick={() => {
  823. if (forms.isRegister !== 'update') {
  824. forms.gradePopupIndex = [studentInfo.extra.currentGradeNum];
  825. forms.gradeStatus = true;
  826. }
  827. }}
  828. />
  829. <Field
  830. clearable={false}
  831. required
  832. inputAlign="right"
  833. label="所在班级"
  834. placeholder="请选择班级"
  835. isLink={forms.isRegister !== 'update'}
  836. readonly
  837. clickable={false}
  838. modelValue={forms.currentClassText}
  839. onClick={() => {
  840. if (forms.isRegister == 'update') {
  841. return;
  842. }
  843. if (
  844. forms.schoolInstrumentSetType === 'CLASS' &&
  845. forms.classList.length <= 0
  846. ) {
  847. showToast('请先选择年级');
  848. return;
  849. }
  850. forms.classPopupIndex = [studentInfo.extra.currentClass];
  851. forms.classStatus = true;
  852. }}
  853. />
  854. <Field
  855. clearable={false}
  856. required
  857. inputAlign="right"
  858. label="互通码"
  859. placeholder="请选择互通码"
  860. readonly={route.query.code ? true : false}
  861. v-model={forms.activationCode}
  862. />
  863. </Form>
  864. </div>
  865. <MSticky position="bottom">
  866. <div class={styles.paymentContainer}>
  867. <Button
  868. onClick={() => {
  869. // onSubmit();
  870. if (checkForm() || checkSubmit()) {
  871. forms.submitLoading = false;
  872. return;
  873. }
  874. forms.showConfirmPopup = true;
  875. }}
  876. round
  877. block
  878. disabled={forms.submitLoading}
  879. loading={forms.submitLoading}>
  880. 提交
  881. </Button>
  882. </div>
  883. </MSticky>
  884. </div>
  885. {forms.imgCodeStatus ? (
  886. <MImgCode
  887. v-model:value={forms.imgCodeStatus}
  888. phone={studentInfo.username}
  889. type="REGISTER"
  890. onClose={() => {
  891. forms.imgCodeStatus = false;
  892. }}
  893. onSendCode={onCodeSend}
  894. />
  895. ) : null}
  896. {/* 互通学校 */}
  897. <Popup
  898. v-model:show={forms.schoolStatus}
  899. position="bottom"
  900. round
  901. safeAreaInsetBottom
  902. lazyRender={false}
  903. class={'popupBottomSearch'}
  904. onOpen={() => {
  905. forms.schoolPopupShow = true;
  906. }}
  907. onClosed={() => {
  908. forms.schoolPopupShow = false;
  909. }}>
  910. {forms.schoolPopupShow && (
  911. <div>
  912. <Picker
  913. showToolbar
  914. // v-model={forms.gradePopupIndex}
  915. columns={forms.schoolAreaList}
  916. loading={forms.schoolLoading}
  917. columnsFieldNames={{
  918. text: 'name',
  919. value: 'id'
  920. }}
  921. onCancel={() => (forms.schoolStatus = false)}
  922. onConfirm={(val: any) => {
  923. const selectedOption = val.selectedOptions[0];
  924. forms.schoolId = null;
  925. forms.schoolAreaId = selectedOption.id;
  926. forms.schoolName = selectedOption.name;
  927. forms.schoolStatus = false;
  928. }}>
  929. {{
  930. 'columns-top': (
  931. <MSearch
  932. placeholder="请输入学校名称"
  933. onSearch={(val: any) => {
  934. getSchoolAreaList(val);
  935. }}
  936. />
  937. )
  938. }}
  939. </Picker>
  940. </div>
  941. )}
  942. </Popup>
  943. {/* 年级 */}
  944. <Popup
  945. v-model:show={forms.gradeStatus}
  946. position="bottom"
  947. round
  948. safeAreaInsetBottom
  949. lazyRender={false}
  950. class={'popupBottomSearch'}
  951. onOpen={() => {
  952. forms.gradePopupShow = true;
  953. }}
  954. onClosed={() => {
  955. forms.gradePopupShow = false;
  956. }}>
  957. {forms.gradePopupShow && (
  958. <Picker
  959. showToolbar
  960. v-model={forms.gradePopupIndex}
  961. columns={forms.gradeList}
  962. onCancel={() => (forms.gradeStatus = false)}
  963. onConfirm={(val: any) => {
  964. const selectedOption = val.selectedOptions[0];
  965. studentInfo.extra.currentGradeNum = selectedOption.value;
  966. forms.gradeNumText = selectedOption.text;
  967. forms.gradeStatus = false;
  968. if (
  969. ['SCHOOL', 'GRADE'].includes(forms.schoolInstrumentSetType)
  970. ) {
  971. forms.instrumentCode = selectedOption.instrumentCode;
  972. }
  973. if (forms.schoolInstrumentSetType === 'CLASS') {
  974. forms.classList = selectedOption.classList;
  975. }
  976. if (
  977. ['CLASS', 'GRADE'].includes(forms.schoolInstrumentSetType)
  978. ) {
  979. forms.currentClassText = '';
  980. studentInfo.extra.currentClass = '';
  981. }
  982. }}
  983. />
  984. )}
  985. </Popup>
  986. {/* 班级 */}
  987. <Popup
  988. v-model:show={forms.classStatus}
  989. position="bottom"
  990. round
  991. class={'popupBottomSearch'}
  992. onOpen={() => {
  993. forms.classPopupShow = true;
  994. }}
  995. onClosed={() => {
  996. forms.classPopupShow = false;
  997. }}>
  998. {forms.classPopupShow && (
  999. <Picker
  1000. showToolbar
  1001. v-model={forms.classPopupIndex}
  1002. columns={forms.classList}
  1003. onCancel={() => (forms.classStatus = false)}
  1004. onConfirm={(val: any) => {
  1005. const selectedOption = val.selectedOptions[0];
  1006. studentInfo.extra.currentClass = selectedOption.value;
  1007. forms.currentClassText = selectedOption.text;
  1008. forms.classStatus = false;
  1009. if (['CLASS'].includes(forms.schoolInstrumentSetType)) {
  1010. forms.instrumentCode = selectedOption.instrumentCode;
  1011. }
  1012. }}
  1013. />
  1014. )}
  1015. </Popup>
  1016. {/* 是否在微信中打开 */}
  1017. <OWxTip
  1018. show={forms.showTips}
  1019. message={forms.showMessage}
  1020. showButton={forms.showButton}
  1021. buttonText="刷新"
  1022. onConfirm={() => window.location.reload()}
  1023. />
  1024. <MMessageTip
  1025. show={otherParams.showOtherSchool}
  1026. // showCloseButton={otherParams.showCloseButton}
  1027. messageAlign={otherParams.messageAlign}
  1028. message={otherParams.showOtherMessage}
  1029. showCancelButton={otherParams.showCancelButton}
  1030. cancelButtonColor={otherParams.cancelButtonColor}
  1031. cancelButtonText={otherParams.cancelButtonText}
  1032. confirmButtonColor={otherParams.confirmButtonColor}
  1033. confirmButtonText={otherParams.confirmButtonText}
  1034. onClose={() => (otherParams.showOtherSchool = false)}
  1035. onCancel={async () => {
  1036. otherParams.showOtherSchool = false;
  1037. if (otherParams.otherType === 'nickname') {
  1038. forms.isRegister = 'create'; // 新建
  1039. changeTipStatus(false, false);
  1040. onSubmit();
  1041. } else if (otherParams.otherType === 'member') {
  1042. const updateStatus = await updateStudentInfo();
  1043. if (!updateStatus) return;
  1044. //取消支付,判断是否有结束时间,是否已经结束
  1045. if (forms.registerExpireTime && forms.activeOverStatus) {
  1046. applyOver();
  1047. }
  1048. } else if (otherParams.otherType === 'payment') {
  1049. forms.joinType = 'tradition';
  1050. }
  1051. }}
  1052. onConfirm={async () => {
  1053. otherParams.showOtherSchool = false;
  1054. // 名字
  1055. if (otherParams.otherType === 'nickname') {
  1056. forms.isRegister = 'update'; // 修改
  1057. changeTipStatus(false, false);
  1058. // 直接注册
  1059. onSubmit();
  1060. } else if (otherParams.otherType === 'change') {
  1061. // 学校更换
  1062. forms.isChangeSchool = true;
  1063. // 直接注册
  1064. onSubmit();
  1065. } else if (otherParams.otherType === 'limit') {
  1066. // 人数超限制
  1067. changeTipStatus(
  1068. forms.isRegister === 'create' && !forms.studentItem.userId
  1069. ? false
  1070. : true,
  1071. false
  1072. );
  1073. } else if (otherParams.otherType === 'member') {
  1074. // await paymentContinue();
  1075. }
  1076. }}
  1077. />
  1078. <Popup
  1079. v-model:show={forms.showSelectStudent}
  1080. round
  1081. position="bottom"
  1082. safeAreaInsetBottom
  1083. closeable>
  1084. <SelectStudent
  1085. studentItem={forms.studentItem}
  1086. list={forms.studentList}
  1087. onClose={() => (forms.showSelectStudent = false)}
  1088. onConfirm={(val: any) => {
  1089. if (val.userId) {
  1090. forms.studentItem = val;
  1091. const firstStudent = val;
  1092. studentInfo.extra.nickname = firstStudent.nickname;
  1093. const tempGrade: any = forms.gradeList || [];
  1094. const tempArea = [] as any;
  1095. if (firstStudent.provinceName) {
  1096. tempArea.push(firstStudent.provinceName);
  1097. forms.provinceCode = firstStudent.provinceCode;
  1098. }
  1099. if (firstStudent.cityName) {
  1100. tempArea.push(firstStudent.cityName);
  1101. forms.cityCode = firstStudent.cityCode;
  1102. }
  1103. if (firstStudent.regionName) {
  1104. tempArea.push(firstStudent.regionName);
  1105. forms.regionCode = firstStudent.regionCode;
  1106. }
  1107. forms.areaName = tempArea.join(' ');
  1108. forms.schoolName = firstStudent.schoolName;
  1109. forms.schoolId = firstStudent.schoolId;
  1110. forms.schoolAreaId = firstStudent.schoolAreaId;
  1111. studentInfo.extra.currentGradeNum = null;
  1112. forms.gradeNumText = '';
  1113. forms.instrumentCode = '';
  1114. tempGrade?.forEach((i: any) => {
  1115. if (i.value === firstStudent.currentGradeNum) {
  1116. forms.instrumentCode = i.instrumentCode;
  1117. forms.gradeNumText = i.text;
  1118. studentInfo.extra.currentGradeNum =
  1119. firstStudent.currentGradeNum;
  1120. if (forms.schoolInstrumentSetType === 'CLASS') {
  1121. forms.classList = i.classList;
  1122. }
  1123. }
  1124. });
  1125. studentInfo.extra.currentClass = null;
  1126. forms.currentClassText = '';
  1127. forms.classList.forEach((i: any) => {
  1128. if (i.value === firstStudent.currentClass) {
  1129. forms.currentClassText = i.text;
  1130. studentInfo.extra.currentClass = firstStudent.currentClass;
  1131. }
  1132. });
  1133. studentInfo.extra.gender = firstStudent.gender;
  1134. forms.isRegister = 'update';
  1135. changeTipStatus(true, false);
  1136. forms.showSelectStudent = false;
  1137. } else {
  1138. // 判断新建学员是否上限了
  1139. if (forms.studentList.length >= forms.multi_user_limit) {
  1140. otherParams.showOtherMessage = `同一手机号最多创建${forms.multi_user_limit}个学生`;
  1141. otherParams.showOtherSchool = true;
  1142. otherParams.showCancelButton = false;
  1143. otherParams.showCloseButton = true;
  1144. otherParams.confirmButtonColor =
  1145. 'linear-gradient( 305deg, #40C8FF 0%, #3192FF 100%)';
  1146. otherParams.confirmButtonText = '我知道了';
  1147. otherParams.otherType = 'limit';
  1148. otherParams.messageAlign = 'center';
  1149. return true;
  1150. } else {
  1151. forms.studentItem = val;
  1152. forms.isRegister = 'create';
  1153. changeTipStatus(false, false);
  1154. studentInfo.extra.nickname = '';
  1155. studentInfo.extra.currentGradeNum = '';
  1156. studentInfo.extra.currentClass = '';
  1157. studentInfo.extra.gender = 1;
  1158. forms.currentClassText = '';
  1159. forms.gradeNumText = '';
  1160. forms.showSelectStudent = false;
  1161. }
  1162. }
  1163. }}
  1164. />
  1165. </Popup>
  1166. <Popup
  1167. v-model:show={forms.showPicker}
  1168. position="bottom"
  1169. round
  1170. class={'popupBottomSearch'}>
  1171. <Area
  1172. areaList={forms.areaList}
  1173. onCancel={() => (forms.showPicker = false)}
  1174. onConfirm={({ selectedOptions }) => {
  1175. forms.provinceCode = selectedOptions[0].value;
  1176. forms.cityCode = selectedOptions[1].value;
  1177. forms.regionCode = selectedOptions[2].value;
  1178. // data.cityName = selectedOptions
  1179. // .map((item: any) => item.text)
  1180. // .join(' ');
  1181. forms.areaName = selectedOptions
  1182. .map((item: any) => item.text)
  1183. .join(' ');
  1184. forms.showPicker = false;
  1185. forms.schoolAreaId = null;
  1186. forms.schoolName = '';
  1187. getSchoolAreaList();
  1188. }}
  1189. />
  1190. </Popup>
  1191. <Popup
  1192. show={forms.showConfirmPopup}
  1193. style={{
  1194. background: 'transparent',
  1195. overflow: 'visible !important'
  1196. }}>
  1197. <CodeDialog type="INFO" showButton={false}>
  1198. <div class={styles.studentInfo}>
  1199. <Cell
  1200. border={false}
  1201. title="学生姓名"
  1202. value={studentInfo.username}></Cell>
  1203. <Cell
  1204. border={false}
  1205. title="学生性别"
  1206. value={studentInfo.extra.gender === 1 ? '男' : '女'}></Cell>
  1207. <Cell
  1208. border={false}
  1209. title="所在地区"
  1210. value={forms.areaName}></Cell>
  1211. <Cell
  1212. border={false}
  1213. title="互通学校"
  1214. value={forms.schoolName}></Cell>
  1215. <Cell
  1216. border={false}
  1217. title="所在年级"
  1218. value={forms.gradeNumText}></Cell>
  1219. <Cell
  1220. border={false}
  1221. title="所在班级"
  1222. value={forms.currentClassText}></Cell>
  1223. {route.query.code && (
  1224. <Cell
  1225. border={false}
  1226. title="互通码"
  1227. value={forms.activationCode}></Cell>
  1228. )}
  1229. </div>
  1230. <div class={styles.studentBtnGroup}>
  1231. <Button
  1232. round
  1233. block
  1234. onClick={() => (forms.showConfirmPopup = false)}>
  1235. 取消
  1236. </Button>
  1237. <Button
  1238. round
  1239. block
  1240. disabled={forms.submitLoading}
  1241. loading={forms.submitLoading}
  1242. color="linear-gradient( 305deg, #40C8FF 0%, #3192FF 100%)"
  1243. onClick={() => {
  1244. forms.showConfirmPopup = false;
  1245. onSubmit();
  1246. }}>
  1247. 提交
  1248. </Button>
  1249. </div>
  1250. </CodeDialog>
  1251. </Popup>
  1252. <Popup
  1253. show={forms.showResultPopup}
  1254. style={{
  1255. background: 'transparent',
  1256. overflow: 'visible !important'
  1257. }}>
  1258. <CodeDialog
  1259. type={forms.reslutPopupType}
  1260. btnText={
  1261. forms.reslutPopupType === 'ACTIVATING'
  1262. ? '立即下载激活码'
  1263. : '我知道了'
  1264. }
  1265. onConfirm={() => {
  1266. //
  1267. if (forms.reslutPopupType === 'ACTIVATING') {
  1268. router.push('/download');
  1269. } else {
  1270. forms.showResultPopup = false;
  1271. }
  1272. }}>
  1273. {forms.reslutPopupType === 'ACTIVATING' && (
  1274. <p>
  1275. 请下载
  1276. <span style={{ color: '#2B85FF' }}>【音乐数字课堂App】</span>
  1277. ,使用手机号激活,实现音乐课堂互通互联
  1278. </p>
  1279. )}
  1280. {forms.reslutPopupType === 'CANCELLED' && (
  1281. <p style={{ textAlign: 'center' }}>{forms.resultPopupContent}</p>
  1282. )}
  1283. {forms.reslutPopupType === 'EXPIRED' && (
  1284. <p style={{ textAlign: 'center' }}>{forms.resultPopupContent}</p>
  1285. )}
  1286. </CodeDialog>
  1287. </Popup>
  1288. </div>
  1289. );
  1290. }
  1291. });