index.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. import { defineComponent, onMounted, onUnmounted, reactive, ref } from 'vue';
  2. import styles from './index.module.less';
  3. // import signinTips from './images/signin-tips.png';
  4. import {
  5. Button,
  6. CellGroup,
  7. Field,
  8. Picker,
  9. Popup,
  10. closeToast,
  11. showToast
  12. } from 'vant';
  13. import { useRoute, useRouter } from 'vue-router';
  14. import threeMan from './images/update/three-man.png'
  15. import OWxTip from '@/components/m-wx-tip';
  16. import { browser, getHttpOrigin, getUrlCode } from '@/helpers/utils';
  17. import qs from 'query-string';
  18. import request from '@/helpers/request';
  19. import { useInterval, useIntervalFn } from '@vueuse/core';
  20. import MMessageTip from '@/components/m-message-tip';
  21. import useAuthCode from '@/hooks/useAuthCode';
  22. const classList: any = [];
  23. for (let i = 1; i <= 40; i++) {
  24. classList.push({ text: i + '班', value: i });
  25. }
  26. const GRADE_ENUM = {
  27. '1': '一年级',
  28. '2': '二年级',
  29. '3': '三年级',
  30. '4': '四年级',
  31. '5': '五年级',
  32. '6': '六年级',
  33. '7': '七年级',
  34. '8': '八年级',
  35. '9': '九年级'
  36. } as any;
  37. const getGradeList = (gradeYear: string, instrumentCode?: string) => {
  38. let tempList: any = [];
  39. const five = [
  40. { text: '一年级', value: 1, instrumentCode },
  41. { text: '二年级', value: 2, instrumentCode },
  42. { text: '三年级', value: 3, instrumentCode },
  43. { text: '四年级', value: 4, instrumentCode },
  44. { text: '五年级', value: 5, instrumentCode }
  45. ];
  46. const one = [{ text: '六年级', value: 6, instrumentCode }];
  47. const three = [
  48. { text: '七年级', value: 7, instrumentCode },
  49. { text: '八年级', value: 8, instrumentCode },
  50. { text: '九年级', value: 9, instrumentCode }
  51. ];
  52. if (gradeYear === 'FIVE_YEAR_SYSTEM') {
  53. tempList.push(...[...five]);
  54. } else if (gradeYear === 'SIX_YEAR_SYSTEM') {
  55. tempList.push(...[...five, ...one]);
  56. } else if (gradeYear === 'THREE_YEAR_SYSTEM') {
  57. tempList.push(...[...three]);
  58. } else if (gradeYear === 'FORE_YEAR_SYSTEM') {
  59. tempList.push(...[...one, ...three]);
  60. } else {
  61. tempList.push(...[...five, ...one, ...three]);
  62. }
  63. return tempList;
  64. };
  65. export default defineComponent({
  66. name: 'pre-register',
  67. setup() {
  68. // 页面定时
  69. const pageTimer = useInterval(1000, { controls: true });
  70. pageTimer.pause();
  71. const router = useRouter();
  72. const route = useRoute();
  73. const authCode = useAuthCode();
  74. const forms = reactive({
  75. loading: true,
  76. schoolId: route.query.id,
  77. code: null,
  78. showPicker: false,
  79. classPicker: false,
  80. gradeStatus: false,
  81. classStatus: false,
  82. gradePopupShow: false,
  83. gradePopupIndex: [] as any, // 年级下拉索引
  84. classPopupShow: false,
  85. classPopupIndex: [] as any, // 班级下拉索引
  86. gradeList: [] as any,
  87. classList: [] as any,
  88. schoolInstrumentSetType: null as any,
  89. nameReg: /^[\u4E00-\u9FA5]+$/,
  90. openId: '' as any,
  91. id: null,
  92. videoBrowseData: null,
  93. videoBrowsePoint: null,
  94. username: '',
  95. currentGrade: '', // 年级
  96. currentClass: '', // 班级
  97. intervalFnRef: null as any,
  98. applyStatus: false,
  99. isPageHide: false,
  100. parentConferencesAgenda: ''
  101. });
  102. const showPopup = ref(false);
  103. const showPopupMessage = ref('');
  104. const message = (value: string) => {
  105. if (!value) {
  106. return '请填写学生真实姓名';
  107. } else if (!forms.nameReg.test(value)) {
  108. return '学员姓名必须为中文';
  109. } else if (value.length < 2 || value.length > 15) {
  110. return '学员姓名必须为2~15个字';
  111. }
  112. };
  113. const onSubmit = async () => {
  114. try {
  115. if (forms.applyStatus) {
  116. showToast('家长会调查问卷已结束');
  117. return;
  118. }
  119. if (message(forms.username)) {
  120. showToast(message(forms.username));
  121. return;
  122. }
  123. if (!forms.currentGrade) {
  124. showToast('请选择年级');
  125. return;
  126. }
  127. if (!forms.currentClass) {
  128. showToast('请选择班级');
  129. return;
  130. }
  131. // 暂停回调
  132. forms.intervalFnRef?.pause();
  133. // 页面计时暂停
  134. pageTimer.pause();
  135. await request.post('/edu-app/open/studentBrowseRecord/updateStat', {
  136. data: {
  137. id: forms.id,
  138. pageBrowseTime: pageTimer.counter.value,
  139. username: forms.username,
  140. currentGrade: forms.currentGrade,
  141. currentClass: forms.currentClass ? Number(forms.currentClass) : null
  142. }
  143. });
  144. router.push({
  145. path: '/pre-register-video',
  146. query: {
  147. saveId: forms.id,
  148. id: forms.schoolId, // 乐团编号
  149. openId: forms.openId //
  150. }
  151. });
  152. } catch {
  153. // 还原
  154. forms.intervalFnRef?.resume();
  155. pageTimer.resume();
  156. }
  157. // router.push('/pre-register-video')
  158. };
  159. const formatterClass = (value: any, list: any[]) => {
  160. let txt = '';
  161. list.forEach((listItem: any) => {
  162. if (listItem.value == value) {
  163. txt = listItem.text;
  164. }
  165. });
  166. return txt;
  167. };
  168. // 更新时间
  169. const updateStat = async (pageBrowseTime = 10) => {
  170. try {
  171. await request.post('/edu-app/open/studentBrowseRecord/updateStat', {
  172. data: {
  173. id: forms.id,
  174. pageBrowseTime // 固定10秒
  175. }
  176. });
  177. } catch {
  178. //
  179. }
  180. };
  181. onMounted(async () => {
  182. // forms.openId = await authCode.getOpenId(
  183. // getHttpOrigin() +
  184. // window.location.pathname +
  185. // '#' +
  186. // route.path +
  187. // '?' +
  188. // qs.stringify({
  189. // ...route.query
  190. // })
  191. // );
  192. forms.openId = authCode.onWeChatCatchOpenId('GET');
  193. try {
  194. if (!forms.schoolId) {
  195. showToast('信息获取失败,请联系老师');
  196. }
  197. const { data } = await request.get(
  198. '/edu-app/open/schoolExtend/detail?id=' + forms.schoolId
  199. );
  200. const schoolExtend = data.schoolExtend;
  201. forms.parentConferencesAgenda = schoolExtend.parentConferencesAgenda;
  202. forms.schoolInstrumentSetType = data.school?.instrumentSetType;
  203. const schoolInstrumentList = data.school?.schoolInstrumentList || [];
  204. if (forms.schoolInstrumentSetType === 'SCHOOL') {
  205. const instrumentCode = schoolInstrumentList[0]?.instrumentCode;
  206. forms.gradeList = getGradeList(data.school?.gradeYear, instrumentCode);
  207. forms.classList = classList;
  208. } else if (forms.schoolInstrumentSetType === 'GRADE') {
  209. schoolInstrumentList.forEach((item: any) => {
  210. forms.gradeList.push({
  211. text: GRADE_ENUM[item.gradeNum],
  212. value: item.gradeNum,
  213. instrumentId: item.instrumentId,
  214. instrumentCode: item.instrumentCode
  215. });
  216. });
  217. forms.gradeList.sort((a: any, b: any) => a.value - b.value);
  218. forms.classList = classList;
  219. } else if (forms.schoolInstrumentSetType === 'CLASS') {
  220. // 班级
  221. const tempGradeList: any[] = [];
  222. schoolInstrumentList.forEach((item: any) => {
  223. if (!tempGradeList.includes(item.gradeNum)) {
  224. tempGradeList.push(item.gradeNum);
  225. }
  226. });
  227. const lastGradeList: any[] = [];
  228. tempGradeList.forEach((temp: any) => {
  229. const list = {
  230. text: GRADE_ENUM[temp],
  231. value: temp,
  232. instrumentId: '',
  233. instrumentCode: '',
  234. instrumentName: '',
  235. classList: [] as any
  236. };
  237. schoolInstrumentList.forEach((item: any) => {
  238. if (temp === item.gradeNum) {
  239. list.instrumentId = item.instrumentId;
  240. list.instrumentCode = item.instrumentCode;
  241. list.instrumentName = item.instrumentName;
  242. list.classList.push({
  243. text: item.classNum + '班',
  244. value: item.classNum,
  245. instrumentCode: item.instrumentCode
  246. });
  247. }
  248. });
  249. // 排序班级
  250. list.classList.sort((a: any, b: any) => a.value - b.value);
  251. lastGradeList.push(list);
  252. });
  253. lastGradeList.sort((a: any, b: any) => a.value - b.value);
  254. forms.gradeList = lastGradeList;
  255. forms.classList = [];
  256. } else {
  257. forms.gradeList = getGradeList(data.school.gradeYear);
  258. forms.classList = classList;
  259. }
  260. // 判断是否获取微信code码
  261. // if (!forms.code) return;
  262. // // 乐团注册
  263. // if (data.status !== 'PRE_REGISTER') {
  264. // showToast('家长会调查问卷已结束')
  265. // forms.applyStatus = true
  266. // return
  267. // }
  268. // 家长会注册
  269. // 'DOING' | 'DONE'
  270. // if (
  271. // data.orchestraRegisterType === 'PARENT_CONFERENCES' &&
  272. // data.status !== 'PARENT_TEACHER_REGISTRATION' &&
  273. // data.status !== 'DOING' &&
  274. // data.status !== 'DONE'
  275. // ) {
  276. // showToast('家长会调查问卷已结束')
  277. // forms.applyStatus = true
  278. // return
  279. // }
  280. // if (!forms.schoolId) {
  281. // // 提示乐团报名失败
  282. // showPopupMessage.value = '二维码已过期';
  283. // showPopup.value = true;
  284. // return;
  285. // }
  286. const recordAdd = await request.post(
  287. '/edu-app/open/studentBrowseRecord/add',
  288. {
  289. data: {
  290. schoolId: forms.schoolId,
  291. // code: forms.code,
  292. openId: forms.openId
  293. }
  294. }
  295. );
  296. const recordObj = recordAdd.data;
  297. forms.currentClass = recordObj.currentClass;
  298. forms.currentGrade = recordObj.currentGrade;
  299. forms.openId = recordObj.openId;
  300. forms.username = recordObj.username;
  301. forms.videoBrowseData = recordObj.videoBrowseData;
  302. forms.videoBrowsePoint = recordObj.videoBrowsePoint;
  303. forms.id = recordObj.id;
  304. // sessionStorage.setItem('active-open-id', recordObj.openId);
  305. // sessionStorage.removeItem('isWxcode');
  306. // console.log(forms, 'forms')
  307. pageTimer.resume();
  308. // 间隔10秒更新停留时间
  309. forms.intervalFnRef = useIntervalFn(() => {
  310. // 页面时间恢复
  311. pageTimer.counter.value = 0;
  312. pageTimer.resume();
  313. updateStat();
  314. }, 10000);
  315. } catch {
  316. //
  317. }
  318. });
  319. // const getAppIdAndCode = async (url?: string) => {
  320. // try {
  321. // const { data } = await request.get(
  322. // '/edu-app/open/paramConfig/wechatAppId'
  323. // );
  324. // // 判断是否有微信appId
  325. // if (data) {
  326. // sessionStorage.setItem('isWxcode', '1');
  327. // closeToast();
  328. // goWechatAuth(data, url);
  329. // }
  330. // } catch(e) {
  331. // //
  332. // console.log(e)
  333. // }
  334. // };
  335. // if (browser().weixin) {
  336. // //授权
  337. // const openId = sessionStorage.getItem('active-open-id');
  338. // forms.openId = openId;
  339. // const code = getUrlCode();
  340. // console.log(code, 'code')
  341. // const isWxcode = sessionStorage.getItem('isWxcode');
  342. // if (!code || isWxcode !== '1') {
  343. // const newUrl =
  344. // getHttpOrigin() +
  345. // window.location.pathname +
  346. // '#' +
  347. // route.path +
  348. // '?' +
  349. // qs.stringify({
  350. // ...route.query
  351. // });
  352. // getAppIdAndCode(newUrl);
  353. // return '';
  354. // } else {
  355. // forms.code = code;
  356. // }
  357. // }
  358. const onPageShow = () => {
  359. console.log(forms.isPageHide, 'showInfo');
  360. if (forms.isPageHide) {
  361. window.location.reload();
  362. }
  363. };
  364. // 处理监听页面返回不刷新的问题
  365. window.addEventListener('pageshow', onPageShow);
  366. const onPageHide = () => {
  367. console.log(forms.isPageHide, 'showInfo');
  368. forms.isPageHide = true;
  369. };
  370. window.addEventListener('pagehide', onPageHide);
  371. onUnmounted(() => {
  372. window.removeEventListener('pageshow', onPageShow);
  373. window.removeEventListener('pagehide', onPageHide);
  374. });
  375. return () => (
  376. <div class={styles['per-register-active']}>
  377. <img class={styles.imgMan} src={threeMan} />
  378. <div class={styles.flowPath}>
  379. <i class={styles.flowPathTitle}></i>
  380. <div
  381. class={styles.flowPathContent}
  382. v-html={forms.parentConferencesAgenda}></div>
  383. </div>
  384. <div class={styles.signin}>
  385. <i class={styles.signinTitle}></i>
  386. <CellGroup class={styles.cellGroup} border={false}>
  387. <Field
  388. label="学生姓名"
  389. required
  390. labelAlign="top"
  391. placeholder="请输入学生姓名"
  392. autocomplete="off"
  393. v-model={forms.username}
  394. border={false}
  395. />
  396. <Field
  397. label="年级"
  398. required
  399. labelAlign="top"
  400. placeholder="请选择年级"
  401. rightIcon={!forms.gradeStatus ? "arrow-down" : "arrow-up"}
  402. readonly
  403. border={false}
  404. modelValue={formatterClass(forms.currentGrade, forms.gradeList)}
  405. clickable={false}
  406. onClick={() => {
  407. forms.gradePopupIndex = [forms.currentGrade];
  408. forms.gradeStatus = true;
  409. }}
  410. />
  411. <Field
  412. label="班级"
  413. required
  414. labelAlign="top"
  415. placeholder="请选择班级"
  416. rightIcon={!forms.classStatus ? "arrow-down" : "arrow-up"}
  417. readonly
  418. border={false}
  419. modelValue={formatterClass(forms.currentClass, forms.classList)}
  420. clickable={false}
  421. onClick={() => {
  422. if (
  423. forms.schoolInstrumentSetType === 'CLASS' &&
  424. forms.classList.length <= 0
  425. ) {
  426. showToast('请先选择年级');
  427. return;
  428. }
  429. forms.classPopupIndex = [forms.currentClass];
  430. forms.classStatus = true;
  431. }}
  432. />
  433. <div class={styles.submitBtn} onClick={onSubmit}></div>
  434. </CellGroup>
  435. </div>
  436. {/* 是否在微信中打开 */}
  437. <OWxTip />
  438. {/* 年级 */}
  439. <Popup
  440. v-model:show={forms.gradeStatus}
  441. position="bottom"
  442. round
  443. safeAreaInsetBottom
  444. lazyRender={false}
  445. class={'popupBottomSearch'}
  446. onOpen={() => {
  447. forms.gradePopupShow = true;
  448. }}
  449. onClosed={() => {
  450. forms.gradePopupShow = false;
  451. }}>
  452. {forms.gradePopupShow && (
  453. <Picker
  454. showToolbar
  455. v-model={forms.gradePopupIndex}
  456. columns={forms.gradeList}
  457. onCancel={() => (forms.gradeStatus = false)}
  458. onConfirm={(val: any) => {
  459. const selectedOption = val.selectedOptions[0];
  460. forms.currentGrade = selectedOption.value;
  461. forms.gradeStatus = false;
  462. if (forms.schoolInstrumentSetType === 'CLASS') {
  463. forms.classList = selectedOption.classList;
  464. }
  465. if (
  466. ['CLASS', 'GRADE'].includes(forms.schoolInstrumentSetType)
  467. ) {
  468. forms.currentClass = '';
  469. }
  470. }}
  471. />
  472. )}
  473. </Popup>
  474. {/* 班级 */}
  475. <Popup
  476. v-model:show={forms.classStatus}
  477. position="bottom"
  478. round
  479. class={'popupBottomSearch'}
  480. onOpen={() => {
  481. forms.classPopupShow = true;
  482. }}
  483. onClosed={() => {
  484. forms.classPopupShow = false;
  485. }}>
  486. {forms.classPopupShow && (
  487. <Picker
  488. showToolbar
  489. v-model={forms.classPopupIndex}
  490. columns={forms.classList}
  491. onCancel={() => (forms.classStatus = false)}
  492. onConfirm={({ selectedValues }) => {
  493. forms.currentClass = selectedValues[0];
  494. forms.classStatus = false;
  495. }}
  496. />
  497. )}
  498. </Popup>
  499. {/* <Popup
  500. v-model:show={showPopup.value}
  501. round
  502. style={{ width: '88%' }}
  503. closeOnClickOverlay={false}
  504. class={styles.wxPopupDialog}>
  505. <div class={styles.popupContainer}>
  506. <p class={styles.title}>温馨提示</p>
  507. <p class={styles.popupTips} v-html={showPopupMessage.value}></p>
  508. </div>
  509. </Popup> */}
  510. <MMessageTip show={showPopup.value} title='温馨提示' message={showPopupMessage.value} showCloseButton={false} showConfirmButton={false} />
  511. </div>
  512. );
  513. }
  514. });