index.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. import {
  2. computed,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. reactive,
  7. ref
  8. } from 'vue';
  9. import styles from './index.module.less';
  10. // import infoTitle from '../images/info-title.png';
  11. import {
  12. Button,
  13. CountDown,
  14. Field,
  15. Form,
  16. Picker,
  17. Popup,
  18. Radio,
  19. RadioGroup,
  20. Tag,
  21. showToast
  22. } from 'vant';
  23. import OWxTip from '@/components/m-wx-tip';
  24. import MProtocol from '@/components/m-protocol';
  25. import MImgCode from '@/components/m-img-code';
  26. import { browser, checkPhone } from '@/helpers/utils';
  27. import request from '@/helpers/request';
  28. import { useStudentRegisterStore } from '@/store/modules/student-register-store';
  29. import { setLoginInit, state } from '@/state';
  30. import iconGift from '../images/icon-gift.png';
  31. import { useRoute, useRouter } from 'vue-router';
  32. import MSticky from '@/components/m-sticky';
  33. const classList: any = [];
  34. for (let i = 1; i <= 40; i++) {
  35. classList.push({ text: i + '班', value: i });
  36. }
  37. export default defineComponent({
  38. name: 'register-modal',
  39. emits: ['close', 'submit'],
  40. setup(props, { emit }) {
  41. const route = useRoute();
  42. const router = useRouter();
  43. const studentRegisterStore = useStudentRegisterStore();
  44. // 初始化学校编号
  45. studentRegisterStore.setShoolId(route.query.sId as any);
  46. const countDownRef = ref();
  47. const gradeList = computed(() => {
  48. let tempList: any = [];
  49. const five = [
  50. { text: '一年级', value: 1 },
  51. { text: '二年级', value: 2 },
  52. { text: '三年级', value: 3 },
  53. { text: '四年级', value: 4 },
  54. { text: '五年级', value: 5 }
  55. ];
  56. const one = [{ text: '六年级', value: 6 }];
  57. const three = [
  58. { text: '七年级', value: 7 },
  59. { text: '八年级', value: 8 },
  60. { text: '九年级', value: 9 }
  61. ];
  62. if (forms.gradeYear === 'FIVE_YEAR_SYSTEM') {
  63. tempList.push([...five]);
  64. } else if (forms.gradeYear === 'SIX_YEAR_SYSTEM') {
  65. tempList.push([...five, ...one]);
  66. } else if (forms.gradeYear === 'THREE_YEAR_SYSTEM') {
  67. tempList.push([...three]);
  68. } else if (forms.gradeYear === 'FORE_YEAR_SYSTEM') {
  69. tempList.push([...one, ...three]);
  70. } else {
  71. tempList.push([...five, ...one, ...three]);
  72. }
  73. return tempList;
  74. });
  75. const forms = reactive({
  76. countDownStatus: true,
  77. countDownTime: 1000 * 120, // 倒计时时间
  78. modelValue: false, // 是否选中协议
  79. imgCodeStatus: false,
  80. gradeNumText: '',
  81. currentClassText: '',
  82. gradeStatus: false,
  83. classStatus: false,
  84. loading: false,
  85. schoolId: route.query.sId as any,
  86. gradeYear: null,
  87. schoolType: null,
  88. giftVipDay: null,
  89. showTips: false,
  90. showButton: false,
  91. showMessage: '请使用微信打开'
  92. });
  93. const studentInfo = reactive({
  94. autoRegister: true,
  95. client_id: 'cooleshow-student',
  96. client_secret: 'cooleshow-student',
  97. extra: {
  98. nickname: '',
  99. currentGradeNum: '',
  100. currentClass: '',
  101. gender: 1,
  102. registerType: '', // 报名类型
  103. giftVipDay: 0 // 赠送会员天数
  104. },
  105. grant_type: 'password',
  106. loginType: 'SMS',
  107. password: '',
  108. username: ''
  109. });
  110. const onCodeSend = () => {
  111. forms.countDownStatus = false;
  112. nextTick(() => {
  113. countDownRef.value.start();
  114. });
  115. };
  116. const onSendCode = () => {
  117. // 发送验证码
  118. if (!checkPhone(studentInfo.username)) {
  119. return showToast('请输入正确的手机号码');
  120. }
  121. forms.imgCodeStatus = true;
  122. };
  123. const validatePhone = computed(() => {
  124. return checkPhone(studentInfo.username) ? true : false;
  125. });
  126. const onFinished = () => {
  127. forms.countDownStatus = true;
  128. countDownRef.value.reset();
  129. };
  130. const onSubmit = async () => {
  131. try {
  132. if (checkForm()) return;
  133. forms.loading = true;
  134. await request.get('/edu-app/open/student/schoolQuery', {
  135. params: {
  136. schoolId: forms.schoolId,
  137. mobile: studentInfo.username
  138. }
  139. });
  140. const { extra, ...res } = studentInfo;
  141. const result = await request.post('/edu-app/userlogin', {
  142. hideLoading: false,
  143. requestType: 'form',
  144. data: {
  145. ...res,
  146. extra: JSON.stringify({
  147. ...extra,
  148. schoolId: forms.schoolId
  149. })
  150. }
  151. });
  152. if (result.code === 5436) {
  153. forms.showTips = true;
  154. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  155. forms.showButton = false;
  156. } else if (result.code === 5435) {
  157. forms.showTips = true;
  158. forms.showMessage = '报名信息更新,请刷新后重新提交';
  159. forms.showButton = true;
  160. } else {
  161. setTimeout(() => {
  162. showToast('报名成功');
  163. router.push('/download');
  164. }, 100);
  165. }
  166. } catch {
  167. } finally {
  168. forms.loading = false;
  169. }
  170. };
  171. const checkForm = () => {
  172. if (!studentInfo.extra.nickname) {
  173. showToast('请输入学生姓名');
  174. return true;
  175. } else if (!studentInfo.extra.currentGradeNum) {
  176. showToast('请选择所在年级');
  177. return true;
  178. } else if (!studentInfo.extra.currentClass) {
  179. showToast('请选择所在班级');
  180. return true;
  181. } else if (!checkPhone(studentInfo.username)) {
  182. showToast('请输入正确的手机号码');
  183. return true;
  184. } else if (!studentInfo.password) {
  185. showToast('请输入验证码');
  186. return true;
  187. }
  188. return false;
  189. };
  190. const getRegisterGoods = async () => {
  191. try {
  192. const { data } = await request.get('/edu-app/open/school/detail', {
  193. params: {
  194. id: forms.schoolId
  195. },
  196. noAuthorization: true // 是否请求接口的时候添加toekn
  197. });
  198. forms.giftVipDay = data.giftVipDay;
  199. forms.schoolType = data.schoolType;
  200. forms.gradeYear = data.gradeYear;
  201. studentInfo.extra.giftVipDay = data.giftVipDay;
  202. studentInfo.extra.registerType = data.registerType;
  203. if (browser().weixin) {
  204. if (data.registerType !== 'GIFT_VIP_DAY' || data.status === 0) {
  205. forms.showTips = true;
  206. forms.showMessage = '二维码已经失效,详情请咨询学校老师';
  207. forms.showButton = false;
  208. }
  209. } else {
  210. forms.showTips = true;
  211. }
  212. } catch {}
  213. };
  214. onMounted(() => {
  215. getRegisterGoods();
  216. });
  217. return () => (
  218. <div class={styles.registerModal}>
  219. {forms.giftVipDay ? (
  220. <div class={styles.memberNumer}>
  221. <img src={iconGift} class={styles.iconGift} />
  222. <p>
  223. 现在报名立即赠送乐器AI学练工具有效期{' '}
  224. <span>{forms.giftVipDay}</span> 天
  225. </p>
  226. </div>
  227. ) : (
  228. ''
  229. )}
  230. <Form labelAlign="top" class={styles.registerForm}>
  231. <Field
  232. clearable
  233. label="学生姓名"
  234. placeholder="请输入学生姓名"
  235. autocomplete="off"
  236. maxlength={14}
  237. v-model={studentInfo.extra.nickname}
  238. />
  239. <Field
  240. clearable
  241. label="学生性别"
  242. placeholder="请选择性别"
  243. autocomplete="off"
  244. // v-model={studentInfo.extra.nickname}
  245. >
  246. {{
  247. input: () => (
  248. <RadioGroup
  249. checked-color="#ffcb75"
  250. v-model={studentInfo.extra.gender}
  251. direction="horizontal">
  252. <Tag
  253. size="large"
  254. type="primary"
  255. color={
  256. !(studentInfo.extra.gender === 1) ? '#EAEAEA' : '#ffcb75'
  257. }
  258. textColor={
  259. !(studentInfo.extra.gender === 1) ? '#AAA' : '#5B2C03'
  260. }
  261. class={styles.radioSection}
  262. round>
  263. <Radio class={styles.radioItem} name={1}></Radio>男
  264. </Tag>
  265. <Tag
  266. size="large"
  267. type="primary"
  268. color={
  269. !(studentInfo.extra.gender === 0) ? '#EAEAEA' : '#ffcb75'
  270. }
  271. textColor={
  272. !(studentInfo.extra.gender === 0) ? '#AAA' : '#5B2C03'
  273. }
  274. class={styles.radioSection}
  275. round>
  276. <Radio class={styles.radioItem} name={0}></Radio>女
  277. </Tag>
  278. </RadioGroup>
  279. )
  280. }}
  281. </Field>
  282. <Field
  283. clearable
  284. label="所在年级"
  285. placeholder="请选择年级"
  286. isLink
  287. readonly
  288. clickable={false}
  289. modelValue={forms.gradeNumText}
  290. onClick={() => (forms.gradeStatus = true)}
  291. />
  292. <Field
  293. clearable
  294. label="所在班级"
  295. placeholder="请选择班级"
  296. isLink
  297. readonly
  298. clickable={false}
  299. modelValue={forms.currentClassText}
  300. onClick={() => (forms.classStatus = true)}
  301. />
  302. <Field
  303. clearable
  304. label="联系方式(直接监护人)"
  305. placeholder="请输入手机号码"
  306. type="tel"
  307. autocomplete="off"
  308. v-model={studentInfo.username}
  309. maxlength={11}>
  310. {{
  311. label: () => (
  312. <div>
  313. 联系方式
  314. {/* (直接监护人) */}
  315. <p class={styles.tips}>手机号是音乐数字课堂的唯一登录账户</p>
  316. </div>
  317. )
  318. }}
  319. </Field>
  320. <Field
  321. center
  322. clearable
  323. label="验证码"
  324. placeholder="请输入验证码"
  325. autocomplete="off"
  326. type="number"
  327. v-model={studentInfo.password}
  328. maxlength={6}>
  329. {{
  330. button: () =>
  331. forms.countDownStatus ? (
  332. <span
  333. class={[
  334. styles.codeText,
  335. !validatePhone.value ? styles.codeTextDisabled : ''
  336. ]}
  337. onClick={onSendCode}>
  338. 获取验证码
  339. </span>
  340. ) : (
  341. <CountDown
  342. ref={(el: any) => (countDownRef.value = el)}
  343. auto-start={false}
  344. time={forms.countDownTime}
  345. onFinish={onFinished}
  346. format="ss秒"
  347. />
  348. )
  349. }}
  350. </Field>
  351. </Form>
  352. {/* <MProtocol
  353. center
  354. v-model:modelValue={forms.modelValue}
  355. prototcolType="REGISTER"
  356. /> */}
  357. <MSticky position="bottom">
  358. <Button
  359. type="primary"
  360. class={styles.submitBtn}
  361. color="linear-gradient(121deg, #FFD892 0%, #FFCB75 100%)"
  362. block
  363. onClick={onSubmit}
  364. disabled={forms.loading}
  365. loading={forms.loading}>
  366. 确认
  367. </Button>
  368. </MSticky>
  369. {forms.imgCodeStatus ? (
  370. <MImgCode
  371. v-model:value={forms.imgCodeStatus}
  372. phone={studentInfo.username}
  373. onClose={() => {
  374. forms.imgCodeStatus = false;
  375. }}
  376. onSendCode={onCodeSend}
  377. />
  378. ) : null}
  379. {/* 年级 */}
  380. <Popup
  381. v-model:show={forms.gradeStatus}
  382. position="bottom"
  383. round
  384. safeAreaInsetBottom
  385. lazyRender={false}
  386. class={'popupBottomSearch'}>
  387. <Picker
  388. showToolbar
  389. columns={gradeList.value as any}
  390. onCancel={() => (forms.gradeStatus = false)}
  391. onConfirm={(val: any) => {
  392. const selectedOption = val.selectedOptions[0];
  393. studentInfo.extra.currentGradeNum = selectedOption.value;
  394. forms.gradeNumText = selectedOption.text;
  395. forms.gradeStatus = false;
  396. }}
  397. />
  398. </Popup>
  399. {/* 班级 */}
  400. <Popup
  401. v-model:show={forms.classStatus}
  402. position="bottom"
  403. round
  404. class={'popupBottomSearch'}>
  405. <Picker
  406. showToolbar
  407. columns={classList}
  408. onCancel={() => (forms.classStatus = false)}
  409. onConfirm={(val: any) => {
  410. const selectedOption = val.selectedOptions[0];
  411. studentInfo.extra.currentClass = selectedOption.value;
  412. forms.currentClassText = selectedOption.text;
  413. forms.classStatus = false;
  414. }}
  415. />
  416. </Popup>
  417. {/* 是否在微信中打开 */}
  418. <OWxTip
  419. v-model:show={forms.showTips}
  420. message={forms.showMessage}
  421. showButton={forms.showButton}
  422. buttonText="刷新"
  423. onConfirm={async () => {
  424. forms.showTips = false;
  425. await getRegisterGoods();
  426. studentInfo.password = '';
  427. window.scrollTo({
  428. top: 0,
  429. behavior: 'smooth'
  430. });
  431. }}
  432. />
  433. </div>
  434. );
  435. }
  436. });