new-index.tsx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. import {
  2. Tag,
  3. Button,
  4. Popup,
  5. Form,
  6. Field,
  7. RadioGroup,
  8. Radio,
  9. showToast,
  10. CountDown,
  11. Area,
  12. Picker
  13. } from 'vant';
  14. import {
  15. computed,
  16. defineComponent,
  17. nextTick,
  18. onBeforeMount,
  19. onMounted,
  20. onUnmounted,
  21. reactive,
  22. ref,
  23. watch
  24. } from 'vue';
  25. import styles from './new-index.module.less';
  26. import MSticky from '@/components/m-sticky';
  27. // import MVideo from '@/components/m-video';
  28. import { useRoute, useRouter } from 'vue-router';
  29. import request from '@/helpers/request';
  30. import loginSuccess from './images/login-success.png';
  31. import bannerBg from './images/banner1.png';
  32. import SelectStudent from '@/views/student-register/modal/select-student';
  33. import { checkPhone } from '@/helpers/utils';
  34. import MImgCode from '@/components/m-img-code';
  35. import { api_sysAreaQueryAllProvince } from '@/views/school-register/api';
  36. import MSearch from '@/components/m-search';
  37. const classList: any = [];
  38. for (let i = 1; i <= 40; i++) {
  39. classList.push({ text: i + '班', value: i });
  40. }
  41. const GRADE_ENUM = {
  42. '1': '一年级',
  43. '2': '二年级',
  44. '3': '三年级',
  45. '4': '四年级',
  46. '5': '五年级',
  47. '6': '六年级',
  48. '7': '七年级',
  49. '8': '八年级',
  50. '9': '九年级'
  51. } as any;
  52. const getGradeList = (gradeYear?: string, instrumentCode?: string) => {
  53. let tempList: any = [];
  54. const five = [
  55. { text: '一年级', value: 1, instrumentCode },
  56. { text: '二年级', value: 2, instrumentCode },
  57. { text: '三年级', value: 3, instrumentCode },
  58. { text: '四年级', value: 4, instrumentCode },
  59. { text: '五年级', value: 5, instrumentCode }
  60. ];
  61. const one = [{ text: '六年级', value: 6, instrumentCode }];
  62. const three = [
  63. { text: '七年级', value: 7, instrumentCode },
  64. { text: '八年级', value: 8, instrumentCode },
  65. { text: '九年级', value: 9, instrumentCode }
  66. ];
  67. if (gradeYear === 'FIVE_YEAR_SYSTEM') {
  68. tempList.push(...[...five]);
  69. } else if (gradeYear === 'SIX_YEAR_SYSTEM') {
  70. tempList.push(...[...five, ...one]);
  71. } else if (gradeYear === 'THREE_YEAR_SYSTEM') {
  72. tempList.push(...[...three]);
  73. } else if (gradeYear === 'FORE_YEAR_SYSTEM') {
  74. tempList.push(...[...one, ...three]);
  75. } else {
  76. tempList.push(...[...five, ...one, ...three]);
  77. }
  78. return tempList;
  79. };
  80. export default defineComponent({
  81. name: 'activation-register',
  82. setup() {
  83. const countDownRef = ref();
  84. const forms = reactive({
  85. statusShow: false,
  86. countDownStatus: true,
  87. countDownTime: 1000 * 120, // 倒计时时间
  88. // modelValue: false, // 是否选中协议
  89. imgCodeStatus: false,
  90. submitLoading: false,
  91. schoolName: '',
  92. areaName: '',
  93. schoolAreaId: null, // 学校区域编号
  94. gradeNumText: '',
  95. currentClassText: '',
  96. gradeStatus: false,
  97. classStatus: false,
  98. schoolStatus: false,
  99. schoolPopupShow: false,
  100. schoolLoading: false,
  101. schoolPopupIndex: [] as any,
  102. schoolAreaList: [] as any,
  103. provinceCode: null,
  104. cityCode: null,
  105. regionCode: null,
  106. areaPopupIndex: null as any,
  107. showPicker: false,
  108. areaList: [] as any,
  109. gradeList: [] as any,
  110. classList: [] as any,
  111. gradePopupShow: false,
  112. gradePopupIndex: [] as any, // 年级下拉索引
  113. classPopupShow: false,
  114. classPopupIndex: [] as any, // 班级下拉索引
  115. registerFlag: false // 是否全部登记
  116. });
  117. const studentInfo = reactive({
  118. phone: '',
  119. password: '',
  120. nickname: '',
  121. currentGradeNum: '' as any,
  122. currentClass: '' as any,
  123. gender: 1 as any
  124. });
  125. const btnText = computed(() => {
  126. if (forms.registerFlag) {
  127. return '已登记';
  128. }
  129. return '登记';
  130. });
  131. const onCodeSend = () => {
  132. forms.countDownStatus = false;
  133. nextTick(() => {
  134. countDownRef.value.start();
  135. });
  136. };
  137. const onSendCode = () => {
  138. // 发送验证码
  139. if (!checkPhone(studentInfo.phone)) {
  140. return showToast('请输入正确的手机号码');
  141. }
  142. forms.imgCodeStatus = true;
  143. };
  144. const validatePhone = computed(() => {
  145. return checkPhone(studentInfo.phone) ? true : false;
  146. });
  147. const onFinished = () => {
  148. forms.countDownStatus = true;
  149. countDownRef.value.reset();
  150. };
  151. const getUserInfos = async () => {
  152. if (studentInfo.password.length !== 6 || !checkPhone(studentInfo.phone)) {
  153. return;
  154. }
  155. try {
  156. const { data } = await request.get(
  157. `/edu-app/open/instrumentRegister/recordQuery?phone=${studentInfo.phone}&code=${studentInfo.password}`
  158. );
  159. if (data?.id) {
  160. forms.registerFlag = true;
  161. }
  162. } catch {
  163. //
  164. }
  165. };
  166. const phoneChangeEmptyInfo = () => {
  167. studentInfo.password = '';
  168. };
  169. const checkForm = (status = true) => {
  170. if (!studentInfo.nickname) {
  171. status && showToast('请输入学生姓名');
  172. return true;
  173. } else if (![0, 1].includes(studentInfo.gender)) {
  174. status && showToast('请选择性别');
  175. return true;
  176. } else if (!studentInfo.currentGradeNum) {
  177. status && showToast('请选择所在年级');
  178. return true;
  179. } else if (!studentInfo.currentClass) {
  180. status && showToast('请选择所在班级');
  181. return true;
  182. } else if (!checkPhone(studentInfo.phone)) {
  183. status && showToast('请输入正确的手机号码');
  184. return true;
  185. } else if (!studentInfo.password) {
  186. status && showToast('请输入验证码');
  187. return true;
  188. }
  189. return false;
  190. };
  191. const onSubmit = async () => {
  192. forms.submitLoading = true;
  193. try {
  194. if (checkForm()) {
  195. forms.submitLoading = false;
  196. return;
  197. }
  198. await request.post('/edu-app/open/instrumentRegister/save', {
  199. data: {
  200. phone: studentInfo.phone,
  201. name: studentInfo.nickname,
  202. gender: studentInfo.gender,
  203. schoolAreaId: forms.schoolAreaId,
  204. currentGradeNum: studentInfo.currentGradeNum,
  205. currentClass: studentInfo.currentClass,
  206. code: studentInfo.password
  207. }
  208. });
  209. forms.statusShow = true;
  210. } catch {}
  211. forms.submitLoading = false;
  212. };
  213. const formateArea = (area: any[]) => {
  214. const province_list: { [_: string]: string } = {};
  215. const city_list: { [_: string]: string } = {};
  216. const county_list: { [_: string]: string } = {};
  217. area.forEach((item: any) => {
  218. province_list[item.code] = item.name;
  219. });
  220. area.forEach((item: any) => {
  221. item.areas?.forEach((city: any) => {
  222. city_list[city.code] = city.name;
  223. });
  224. });
  225. area.forEach((item: any) => {
  226. item.areas?.forEach((city: any) => {
  227. city.areas?.forEach((county: any) => {
  228. county_list[county.code] = county.name;
  229. });
  230. });
  231. });
  232. return {
  233. province_list,
  234. city_list,
  235. county_list
  236. };
  237. };
  238. const getAreaList = () => {
  239. api_sysAreaQueryAllProvince().then(res => {
  240. if (res?.code === 200) {
  241. forms.areaList = formateArea(res.data);
  242. }
  243. });
  244. };
  245. const getSchoolAreaList = async (name?: string) => {
  246. forms.schoolLoading = true;
  247. try {
  248. const { data } = await request.post('/edu-app/open/schoolArea/list', {
  249. data: {
  250. name,
  251. testFlag: true,
  252. provinceCode: forms.provinceCode,
  253. cityCode: forms.cityCode,
  254. regionCode: forms.regionCode
  255. }
  256. });
  257. forms.schoolAreaList = data;
  258. } catch {
  259. //
  260. }
  261. forms.schoolLoading = false;
  262. };
  263. watch(
  264. () => [
  265. studentInfo.phone,
  266. studentInfo.nickname,
  267. studentInfo.gender,
  268. forms.schoolAreaId,
  269. forms.gradeNumText,
  270. forms.schoolName,
  271. forms.areaName,
  272. forms.provinceCode,
  273. forms.cityCode,
  274. forms.regionCode,
  275. forms.currentClassText,
  276. studentInfo.currentGradeNum,
  277. studentInfo.currentClass
  278. ],
  279. () => {
  280. // 缓存数据到 localStorage
  281. localStorage.setItem(
  282. 'activationRegistration-form',
  283. JSON.stringify({
  284. phone: studentInfo.phone,
  285. name: studentInfo.nickname,
  286. gender: studentInfo.gender,
  287. schoolAreaId: forms.schoolAreaId,
  288. gradeNumText: forms.gradeNumText,
  289. schoolName: forms.schoolName,
  290. areaName: forms.areaName,
  291. provinceCode: forms.provinceCode,
  292. cityCode: forms.cityCode,
  293. regionCode: forms.regionCode,
  294. currentClassText: forms.currentClassText,
  295. currentGradeNum: studentInfo.currentGradeNum,
  296. currentClass: studentInfo.currentClass
  297. })
  298. );
  299. }
  300. );
  301. onMounted(() => {
  302. forms.gradeList = getGradeList();
  303. forms.classList = classList;
  304. getAreaList();
  305. let localForm: any = localStorage.getItem('activationRegistration-form');
  306. if (localForm) {
  307. localForm = JSON.parse(localForm);
  308. studentInfo.phone = localForm.phone;
  309. studentInfo.nickname = localForm.name;
  310. studentInfo.gender = localForm.gender;
  311. forms.schoolAreaId = localForm.schoolAreaId;
  312. forms.gradeNumText = localForm.gradeNumText;
  313. forms.schoolName = localForm.schoolName;
  314. forms.areaName = localForm.areaName;
  315. forms.provinceCode = localForm.provinceCode;
  316. forms.cityCode = localForm.cityCode;
  317. forms.regionCode = localForm.regionCode;
  318. forms.currentClassText = localForm.currentClassText;
  319. studentInfo.currentGradeNum = localForm.currentGradeNum;
  320. studentInfo.currentClass = localForm.currentClass;
  321. if (forms.cityCode && forms.regionCode && forms.provinceCode) {
  322. getSchoolAreaList();
  323. }
  324. }
  325. });
  326. return () => (
  327. <div class={[styles['student-register']]}>
  328. <img src={bannerBg} class={styles.bannerBg} />
  329. <div class={styles.studentRegisterContainer}>
  330. <div class={[styles.studentSection]}>
  331. <Form labelAlign="left" class={styles.registerForm}>
  332. <Field
  333. clearable={false}
  334. required
  335. inputAlign="right"
  336. label="学生姓名"
  337. placeholder="请输入学生姓名"
  338. autocomplete="off"
  339. maxlength={14}
  340. v-model={studentInfo.nickname}></Field>
  341. <Field
  342. clearable={false}
  343. required
  344. inputAlign="right"
  345. label="学生性别"
  346. placeholder="请选择性别"
  347. autocomplete="off">
  348. {{
  349. input: () => (
  350. <RadioGroup
  351. checked-color="linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)"
  352. v-model={studentInfo.gender}
  353. direction="horizontal">
  354. <Tag
  355. size="large"
  356. type="primary"
  357. color={
  358. !(studentInfo.gender === 1)
  359. ? '#F5F6FA'
  360. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  361. }
  362. textColor={
  363. !(studentInfo.gender === 1) ? '#626264' : '#fff'
  364. }
  365. class={styles.radioSection}>
  366. <Radio class={styles.radioItem} name={1}></Radio>男
  367. </Tag>
  368. <Tag
  369. size="large"
  370. type="primary"
  371. color={
  372. !(studentInfo.gender === 0)
  373. ? '#F5F6FA'
  374. : 'linear-gradient( 135deg, #31C7FF 0%, #007AFE 100%)'
  375. }
  376. textColor={
  377. !(studentInfo.gender === 0) ? '#626264' : '#fff'
  378. }
  379. class={styles.radioSection}>
  380. <Radio class={styles.radioItem} name={0}></Radio>女
  381. </Tag>
  382. </RadioGroup>
  383. )
  384. }}
  385. </Field>
  386. <Field
  387. clearable={false}
  388. required
  389. inputAlign="right"
  390. label="所在地区"
  391. placeholder="请选择地区"
  392. isLink
  393. readonly
  394. clickable={false}
  395. modelValue={forms.areaName}
  396. onClick={() => {
  397. forms.showPicker = true;
  398. forms.areaPopupIndex =
  399. forms.regionCode || forms.cityCode || forms.provinceCode;
  400. }}
  401. />
  402. <Field
  403. clearable={false}
  404. required
  405. inputAlign="right"
  406. label="互通学校"
  407. placeholder="请选择互通学校"
  408. isLink
  409. readonly
  410. clickable={false}
  411. modelValue={forms.schoolName}
  412. onClick={() => {
  413. if (!forms.areaName) {
  414. showToast('请选择地区');
  415. return;
  416. }
  417. if (forms.schoolAreaId) {
  418. forms.schoolPopupIndex = [forms.schoolAreaId];
  419. }
  420. forms.schoolStatus = true;
  421. }}
  422. />
  423. <Field
  424. clearable={false}
  425. required
  426. inputAlign="right"
  427. label="所在年级"
  428. placeholder="请选择年级"
  429. readonly
  430. isLink
  431. clickable={false}
  432. modelValue={forms.gradeNumText}
  433. onClick={() => {
  434. forms.gradePopupIndex = [studentInfo.currentGradeNum];
  435. forms.gradeStatus = true;
  436. }}
  437. />
  438. <Field
  439. clearable={false}
  440. required
  441. inputAlign="right"
  442. label="所在班级"
  443. placeholder="请选择班级"
  444. readonly
  445. isLink
  446. clickable={false}
  447. modelValue={forms.currentClassText}
  448. onClick={() => {
  449. forms.classPopupIndex = [studentInfo.currentClass];
  450. forms.classStatus = true;
  451. }}
  452. />
  453. <Field
  454. clearable={false}
  455. label="联系方式"
  456. placeholder="请输入手机号码"
  457. type="digit"
  458. required
  459. autocomplete="off"
  460. inputAlign="right"
  461. v-model={studentInfo.phone}
  462. maxlength={11}
  463. onUpdate:modelValue={() => {
  464. forms.registerFlag = false;
  465. phoneChangeEmptyInfo();
  466. }}></Field>
  467. <Field
  468. center
  469. clearable={false}
  470. required
  471. inputAlign="right"
  472. label="验证码"
  473. placeholder="请输入验证码"
  474. autocomplete="off"
  475. type="number"
  476. v-model={studentInfo.password}
  477. maxlength={6}
  478. onUpdate:modelValue={(val: any) => {
  479. getUserInfos();
  480. }}>
  481. {{
  482. button: () =>
  483. forms.countDownStatus ? (
  484. <span
  485. class={[
  486. styles.codeText,
  487. !validatePhone.value ? styles.codeTextDisabled : ''
  488. ]}
  489. onClick={onSendCode}>
  490. 获取验证码
  491. </span>
  492. ) : (
  493. <CountDown
  494. ref={(el: any) => (countDownRef.value = el)}
  495. auto-start={false}
  496. class={styles.countDown}
  497. time={forms.countDownTime}
  498. onFinish={onFinished}
  499. format="ss秒后重试"
  500. />
  501. )
  502. }}
  503. </Field>
  504. </Form>
  505. </div>
  506. <MSticky position="bottom">
  507. <div class={styles.paymentContainer}>
  508. <Button
  509. onClick={() => {
  510. onSubmit();
  511. }}
  512. round
  513. block
  514. disabled={forms.submitLoading || forms.registerFlag}
  515. loading={forms.submitLoading}>
  516. {btnText.value}
  517. </Button>
  518. </div>
  519. </MSticky>
  520. </div>
  521. {/* 互通学校 */}
  522. <Popup
  523. v-model:show={forms.schoolStatus}
  524. position="bottom"
  525. round
  526. safeAreaInsetBottom
  527. lazyRender={false}
  528. class={'popupBottomSearch'}
  529. onOpen={() => {
  530. forms.schoolPopupShow = true;
  531. }}
  532. onClosed={() => {
  533. forms.schoolPopupShow = false;
  534. }}>
  535. {forms.schoolPopupShow && (
  536. <div>
  537. <Picker
  538. showToolbar
  539. v-model={forms.schoolPopupIndex}
  540. columns={forms.schoolAreaList}
  541. loading={forms.schoolLoading}
  542. columnsFieldNames={{
  543. text: 'name',
  544. value: 'id'
  545. }}
  546. onCancel={() => (forms.schoolStatus = false)}
  547. onConfirm={(val: any) => {
  548. const selectedOption = val.selectedOptions[0];
  549. // forms.schoolId = selectedOption.schoolId || null;
  550. forms.schoolAreaId = selectedOption.id;
  551. forms.schoolName = selectedOption.name;
  552. forms.schoolStatus = false;
  553. // forms.gradeNumText = '';
  554. // studentInfo.extra.currentGradeNum = null;
  555. // forms.currentClassText = '';
  556. // studentInfo.extra.currentClass = null;
  557. // getSchoolAreaDetail();
  558. }}>
  559. {{
  560. 'columns-top': (
  561. <MSearch
  562. placeholder="请输入学校名称"
  563. onSearch={(val: any) => {
  564. getSchoolAreaList(val);
  565. }}
  566. />
  567. )
  568. }}
  569. </Picker>
  570. </div>
  571. )}
  572. </Popup>
  573. {/* 年级 */}
  574. <Popup
  575. v-model:show={forms.gradeStatus}
  576. position="bottom"
  577. round
  578. safeAreaInsetBottom
  579. lazyRender={false}
  580. class={'popupBottomSearch'}
  581. onOpen={() => {
  582. forms.gradePopupShow = true;
  583. }}
  584. onClosed={() => {
  585. forms.gradePopupShow = false;
  586. }}>
  587. {forms.gradePopupShow && (
  588. <Picker
  589. showToolbar
  590. v-model={forms.gradePopupIndex}
  591. columns={forms.gradeList}
  592. onCancel={() => (forms.gradeStatus = false)}
  593. onConfirm={(val: any) => {
  594. const selectedOption = val.selectedOptions[0];
  595. studentInfo.currentGradeNum = selectedOption.value;
  596. forms.gradeNumText = selectedOption.text;
  597. forms.gradeStatus = false;
  598. }}
  599. />
  600. )}
  601. </Popup>
  602. {/* 班级 */}
  603. <Popup
  604. v-model:show={forms.classStatus}
  605. position="bottom"
  606. round
  607. class={'popupBottomSearch'}
  608. onOpen={() => {
  609. forms.classPopupShow = true;
  610. }}
  611. onClosed={() => {
  612. forms.classPopupShow = false;
  613. }}>
  614. {forms.classPopupShow && (
  615. <Picker
  616. showToolbar
  617. v-model={forms.classPopupIndex}
  618. columns={forms.classList}
  619. onCancel={() => (forms.classStatus = false)}
  620. onConfirm={(val: any) => {
  621. const selectedOption = val.selectedOptions[0];
  622. studentInfo.currentClass = selectedOption.value;
  623. forms.currentClassText = selectedOption.text;
  624. forms.classStatus = false;
  625. }}
  626. />
  627. )}
  628. </Popup>
  629. <Popup
  630. v-model:show={forms.showPicker}
  631. position="bottom"
  632. round
  633. class={'popupBottomSearch'}>
  634. <Area
  635. v-model={forms.areaPopupIndex}
  636. areaList={forms.areaList}
  637. onCancel={() => (forms.showPicker = false)}
  638. onConfirm={({ selectedOptions }) => {
  639. forms.provinceCode = selectedOptions[0].value;
  640. forms.cityCode = selectedOptions[1].value;
  641. forms.regionCode = selectedOptions[2]?.value;
  642. forms.areaName = selectedOptions
  643. .map((item: any) => item?.text)
  644. .join(' ');
  645. forms.showPicker = false;
  646. // forms.schoolId = null;
  647. forms.schoolAreaId = null;
  648. forms.schoolName = '';
  649. getSchoolAreaList();
  650. }}
  651. />
  652. </Popup>
  653. {/* <Popup
  654. v-model:show={forms.showSelectStudent}
  655. round
  656. position="bottom"
  657. safeAreaInsetBottom
  658. closeable>
  659. <SelectStudent
  660. showAdd={false}
  661. studentItem={forms.studentItem}
  662. list={forms.studentList}
  663. onClose={() => (forms.showSelectStudent = false)}
  664. onConfirm={(val: any) => {
  665. console.log(val, 'val');
  666. formatData(val);
  667. forms.studentItem = val;
  668. }}
  669. />
  670. </Popup> */}
  671. {forms.imgCodeStatus ? (
  672. <MImgCode
  673. v-model:value={forms.imgCodeStatus}
  674. phone={studentInfo.phone}
  675. type="INSTRUMENT"
  676. onClose={() => {
  677. forms.imgCodeStatus = false;
  678. }}
  679. onSendCode={onCodeSend}
  680. />
  681. ) : null}
  682. <Popup
  683. show={forms.statusShow}
  684. style={{
  685. background: 'transparent',
  686. overflow: 'visible !important'
  687. }}>
  688. <div class={styles.popupContainer}>
  689. {/* <img class={styles.title} src={loginSuccess} /> */}
  690. <div class={styles.content} style={{ textAlign: 'center' }}>
  691. 乐器的实际发放将以
  692. <span>
  693. 最终的
  694. <br />
  695. 审核结果
  696. </span>
  697. 为准。
  698. </div>
  699. <div class={styles.pBtnGroup}>
  700. <div
  701. class={styles.btnSubmit}
  702. onClick={() => {
  703. forms.registerFlag = true;
  704. forms.statusShow = false;
  705. }}></div>
  706. </div>
  707. </div>
  708. </Popup>
  709. </div>
  710. );
  711. }
  712. });