index.tsx 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. import { defineComponent, onMounted, onUnmounted, reactive } from 'vue'
  2. import styles from './index.module.less'
  3. import signinTips from './images/signin-tips.png'
  4. import { Button, CellGroup, Field, Picker, Popup, closeToast, showToast } from 'vant'
  5. import { useRoute, useRouter } from 'vue-router'
  6. import OWxTip from '@/components/o-wx-tip'
  7. import { browser, getUrlCode } from '@/helpers/utils'
  8. import qs from 'query-string'
  9. import request from '@/helpers/request'
  10. import { goWechatAuth } from '@/state'
  11. import { useInterval, useIntervalFn } from '@vueuse/core'
  12. const classList: any[] = []
  13. for (let i = 1; i <= 40; i++) {
  14. classList.push({ text: i + '班', value: i })
  15. }
  16. export default defineComponent({
  17. name: 'pre-register',
  18. setup() {
  19. // 页面定时
  20. const pageTimer = useInterval(1000, { controls: true })
  21. pageTimer.pause()
  22. const router = useRouter()
  23. const route = useRoute()
  24. const forms = reactive({
  25. loading: true,
  26. orchestraId: route.query.id,
  27. code: null,
  28. currentGradeList: [
  29. { text: '一年级', value: 1 },
  30. { text: '二年级', value: 2 },
  31. { text: '三年级', value: 3 },
  32. { text: '四年级', value: 4 },
  33. { text: '五年级', value: 5 }
  34. ], // 年级数组列表
  35. showPicker: false,
  36. classPicker: false,
  37. nameReg: /^[\u4E00-\u9FA5]+$/,
  38. openId: '' as any,
  39. id: null,
  40. videoBrowseData: null,
  41. videoBrowsePoint: null,
  42. username: '',
  43. currentGrade: '', // 年级
  44. currentClass: '', // 班级
  45. intervalFnRef: null as any,
  46. applyStatus: false,
  47. isPageHide: false
  48. })
  49. const message = (value: string) => {
  50. if (!value) {
  51. return '请填写学生真实姓名'
  52. } else if (!forms.nameReg.test(value)) {
  53. return '学员姓名必须为中文'
  54. } else if (value.length < 2 || value.length > 15) {
  55. return '学员姓名必须为2~15个字'
  56. }
  57. }
  58. const onSubmit = async () => {
  59. try {
  60. if (forms.applyStatus) {
  61. showToast('家长会调查问卷已结束')
  62. return
  63. }
  64. if (message(forms.username)) {
  65. showToast(message(forms.username))
  66. return
  67. }
  68. if (!forms.currentGrade) {
  69. showToast('请选择年级')
  70. return
  71. }
  72. if (!forms.currentClass) {
  73. showToast('请选择班级')
  74. return
  75. }
  76. // 暂停回调
  77. forms.intervalFnRef?.pause()
  78. // 页面计时暂停
  79. pageTimer.pause()
  80. await request.post('/api-student/open/studentBrowseRecord/updateStat', {
  81. data: {
  82. id: forms.id,
  83. pageBrowseTime: pageTimer.counter.value,
  84. username: forms.username,
  85. currentGrade: forms.currentGrade,
  86. currentClass: forms.currentClass ? Number(forms.currentClass) : null
  87. }
  88. })
  89. router.push({
  90. path: '/pre-register-video',
  91. query: {
  92. saveId: forms.id,
  93. id: forms.orchestraId, // 乐团编号
  94. openId: forms.openId //
  95. }
  96. })
  97. } catch {
  98. // 还原
  99. forms.intervalFnRef?.resume()
  100. pageTimer.resume()
  101. }
  102. // router.push('/pre-register-video')
  103. }
  104. const formatterClass = (value: any, list: any[]) => {
  105. let txt = ''
  106. list.forEach((listItem: any) => {
  107. if (listItem.value == value) {
  108. txt = listItem.text
  109. }
  110. })
  111. return txt
  112. }
  113. // 更新时间
  114. const updateStat = async (pageBrowseTime = 10) => {
  115. try {
  116. await request.post('/api-student/open/studentBrowseRecord/updateStat', {
  117. data: {
  118. id: forms.id,
  119. pageBrowseTime // 固定10秒
  120. }
  121. })
  122. } catch {
  123. //
  124. }
  125. }
  126. onMounted(async () => {
  127. try {
  128. if (!forms.orchestraId) {
  129. showToast('信息获取失败,请联系老师')
  130. }
  131. const { data } = await request.get(
  132. '/api-student/open/orchestra/detail/' + forms.orchestraId
  133. )
  134. const schoolSystem = data.schoolSystem || 'sixYearSystem'
  135. if (schoolSystem === 'sixYearSystem') {
  136. forms.currentGradeList.push({ text: '六年级', value: 6 })
  137. }
  138. // 判断是否获取微信code码
  139. if (!forms.code) return
  140. if (data.status !== 'PRE_REGISTER') {
  141. showToast('家长会调查问卷已结束')
  142. forms.applyStatus = true
  143. return
  144. }
  145. const recordAdd = await request.post('/api-student/open/studentBrowseRecord/add', {
  146. data: {
  147. orchestraId: forms.orchestraId,
  148. code: forms.code,
  149. openId: forms.openId
  150. }
  151. })
  152. const recordObj = recordAdd.data
  153. forms.currentClass = recordObj.currentClass
  154. forms.currentGrade = recordObj.currentGrade
  155. forms.openId = recordObj.openId
  156. forms.username = recordObj.username
  157. forms.videoBrowseData = recordObj.videoBrowseData
  158. forms.videoBrowsePoint = recordObj.videoBrowsePoint
  159. forms.id = recordObj.id
  160. sessionStorage.setItem('active-open-id', recordObj.openId)
  161. pageTimer.resume()
  162. // 间隔10秒更新停留时间
  163. forms.intervalFnRef = useIntervalFn(() => {
  164. // 页面时间恢复
  165. pageTimer.counter.value = 0
  166. pageTimer.resume()
  167. updateStat()
  168. }, 10000)
  169. } catch {
  170. //
  171. }
  172. })
  173. const getAppIdAndCode = async (url?: string) => {
  174. try {
  175. const { data } = await request.get('/api-school/open/paramConfig/wechatAppId')
  176. // 判断是否有微信appId
  177. if (data) {
  178. closeToast()
  179. goWechatAuth(data, url)
  180. }
  181. } catch {
  182. //
  183. }
  184. }
  185. if (browser().weixin) {
  186. //授权
  187. const openId = sessionStorage.getItem('active-open-id')
  188. forms.openId = openId
  189. const code = getUrlCode()
  190. if (!code) {
  191. const newUrl =
  192. window.location.origin +
  193. window.location.pathname +
  194. '#' +
  195. route.path +
  196. '?' +
  197. qs.stringify({
  198. ...route.query
  199. })
  200. getAppIdAndCode(newUrl)
  201. return ''
  202. } else {
  203. forms.code = code
  204. }
  205. }
  206. const onPageShow = () => {
  207. console.log(forms.isPageHide, 'showInfo')
  208. if (forms.isPageHide) {
  209. window.location.reload()
  210. }
  211. }
  212. // 处理监听页面返回不刷新的问题
  213. window.addEventListener('pageshow', onPageShow)
  214. const onPageHide = () => {
  215. console.log(forms.isPageHide, 'showInfo')
  216. forms.isPageHide = true
  217. }
  218. window.addEventListener('pagehide', onPageHide)
  219. onUnmounted(() => {
  220. window.removeEventListener('pageshow', onPageShow)
  221. window.removeEventListener('pagehide', onPageHide)
  222. })
  223. return () => (
  224. <div class={styles['per-register-active']}>
  225. <div class={styles.flowPath}>
  226. <i class={styles.flowPathTitle}></i>
  227. <div class={styles.flowPathContent}>
  228. 一、请所有家长进行<span>签到</span>
  229. <br />
  230. 二、<span>观看</span>管乐团家长会议
  231. <br />
  232. 1、学校领导讲话(5分钟)
  233. <br />
  234. 2、基金会老师介绍乐团事项(20分钟)
  235. <br />
  236. <p
  237. style={{
  238. 'padding-left': '1em'
  239. }}
  240. >
  241. *乐团组建背景及政策
  242. <br />
  243. *乐团发展规划与乐器知识讲解
  244. <br />
  245. *学校/基金会/家长各方职责与投入
  246. <br />
  247. *入团流程讲解
  248. </p>
  249. 三、会后,家长可点击<span>“乐团报名”</span>或扫码进行正式报名
  250. </div>
  251. </div>
  252. <div class={styles.signin}>
  253. <div class={styles.tips}>
  254. <img src={signinTips} class={styles.signinTips} />
  255. <p>
  256. 请先进行<span>签到</span>,再观看<span>管乐团家长会视频</span>
  257. </p>
  258. </div>
  259. <CellGroup class={styles.cellGroup} border={false}>
  260. <Field
  261. label="学生姓名"
  262. labelAlign="top"
  263. placeholder="请输入学生姓名"
  264. autocomplete="off"
  265. v-model={forms.username}
  266. />
  267. <Field
  268. label="年级"
  269. labelAlign="top"
  270. placeholder="请选择年级"
  271. isLink
  272. readonly
  273. modelValue={formatterClass(forms.currentGrade, forms.currentGradeList)}
  274. clickable={false}
  275. onClick={() => (forms.showPicker = true)}
  276. />
  277. <Field
  278. label="班级"
  279. labelAlign="top"
  280. placeholder="请选择班级"
  281. isLink
  282. readonly
  283. modelValue={formatterClass(forms.currentClass, classList)}
  284. clickable={false}
  285. onClick={() => (forms.classPicker = true)}
  286. />
  287. <Button class={styles.submitBtn} onClick={onSubmit}></Button>
  288. </CellGroup>
  289. </div>
  290. {/* 是否在微信中打开 */}
  291. <OWxTip />
  292. {/* 年级 */}
  293. <Popup v-model:show={forms.showPicker} position="bottom" round>
  294. <Picker
  295. columns={forms.currentGradeList}
  296. onCancel={() => (forms.showPicker = false)}
  297. onConfirm={({ selectedValues }) => {
  298. forms.currentGrade = selectedValues[0]
  299. forms.showPicker = false
  300. }}
  301. />
  302. </Popup>
  303. {/* 班级 */}
  304. <Popup v-model:show={forms.classPicker} position="bottom" round>
  305. <Picker
  306. columns={classList}
  307. onCancel={() => (forms.classPicker = false)}
  308. onConfirm={({ selectedValues }) => {
  309. forms.currentClass = selectedValues[0]
  310. forms.classPicker = false
  311. }}
  312. />
  313. </Popup>
  314. </div>
  315. )
  316. }
  317. })