index.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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.post('/api-student/open/school/detail', {
  132. data: {
  133. orchestraId: forms.orchestraId
  134. }
  135. })
  136. const schoolSystem = data.schoolSystem || 'sixYearSystem'
  137. if (schoolSystem === 'sixYearSystem') {
  138. forms.currentGradeList.push({ text: '六年级', value: 6 })
  139. }
  140. // 判断是否获取微信code码
  141. if (!forms.code) return
  142. if (data.status !== 'PRE_REGISTER') {
  143. showToast('家长会调查问卷已结束')
  144. forms.applyStatus = true
  145. return
  146. }
  147. const recordAdd = await request.post('/api-student/open/studentBrowseRecord/add', {
  148. data: {
  149. orchestraId: forms.orchestraId,
  150. code: forms.code,
  151. openId: forms.openId
  152. }
  153. })
  154. const recordObj = recordAdd.data
  155. forms.currentClass = recordObj.currentClass
  156. forms.currentGrade = recordObj.currentGrade
  157. forms.openId = recordObj.openId
  158. forms.username = recordObj.username
  159. forms.videoBrowseData = recordObj.videoBrowseData
  160. forms.videoBrowsePoint = recordObj.videoBrowsePoint
  161. forms.id = recordObj.id
  162. sessionStorage.setItem('active-open-id', recordObj.openId)
  163. pageTimer.resume()
  164. // 间隔10秒更新停留时间
  165. forms.intervalFnRef = useIntervalFn(() => {
  166. // 页面时间恢复
  167. pageTimer.counter.value = 0
  168. pageTimer.resume()
  169. updateStat()
  170. }, 10000)
  171. } catch {
  172. //
  173. }
  174. })
  175. const getAppIdAndCode = async (url?: string) => {
  176. try {
  177. const { data } = await request.get('/api-school/open/paramConfig/wechatAppId')
  178. // 判断是否有微信appId
  179. if (data) {
  180. closeToast()
  181. goWechatAuth(data, url)
  182. }
  183. } catch {
  184. //
  185. }
  186. }
  187. if (browser().weixin) {
  188. //授权
  189. const openId = sessionStorage.getItem('active-open-id')
  190. forms.openId = openId
  191. const code = getUrlCode()
  192. if (!code) {
  193. const newUrl =
  194. window.location.origin +
  195. window.location.pathname +
  196. '#' +
  197. route.path +
  198. '?' +
  199. qs.stringify({
  200. ...route.query
  201. })
  202. getAppIdAndCode(newUrl)
  203. return ''
  204. } else {
  205. forms.code = code
  206. }
  207. }
  208. const onPageShow = () => {
  209. console.log(forms.isPageHide, 'showInfo')
  210. if (forms.isPageHide) {
  211. window.location.reload()
  212. }
  213. }
  214. // 处理监听页面返回不刷新的问题
  215. window.addEventListener('pageshow', onPageShow)
  216. const onPageHide = () => {
  217. console.log(forms.isPageHide, 'showInfo')
  218. forms.isPageHide = true
  219. }
  220. window.addEventListener('pagehide', onPageHide)
  221. onUnmounted(() => {
  222. window.removeEventListener('pageshow', onPageShow)
  223. window.removeEventListener('pagehide', onPageHide)
  224. })
  225. return () => (
  226. <div class={styles['per-register-active']}>
  227. <div class={styles.flowPath}>
  228. <i class={styles.flowPathTitle}></i>
  229. <div class={styles.flowPathContent}>
  230. 一、请所有家长进行<span>签到</span>
  231. <br />
  232. 二、<span>观看</span>管乐团家长会议
  233. <br />
  234. 1、学校领导讲话(5分钟)
  235. <br />
  236. 2、基金会老师介绍乐团事项(20分钟)
  237. <br />
  238. <p
  239. style={{
  240. 'padding-left': '1em'
  241. }}
  242. >
  243. *乐团组建背景及政策
  244. <br />
  245. *乐团发展规划与乐器知识讲解
  246. <br />
  247. *学校/基金会/家长各方职责与投入
  248. <br />
  249. *入团流程讲解
  250. </p>
  251. 三、请
  252. <span>“有意向”</span>让孩子加入乐团的家长点击
  253. <span>“乐团报名”</span>完成信息填报
  254. </div>
  255. </div>
  256. <div class={styles.signin}>
  257. <div class={styles.tips}>
  258. <img src={signinTips} class={styles.signinTips} />
  259. <p>
  260. 请先进行<span>签到</span>,再观看<span>管乐团家长会视频</span>
  261. </p>
  262. </div>
  263. <CellGroup class={styles.cellGroup} border={false}>
  264. <Field
  265. label="学生姓名"
  266. labelAlign="top"
  267. placeholder="请输入学生姓名"
  268. autocomplete="off"
  269. v-model={forms.username}
  270. />
  271. <Field
  272. label="年级"
  273. labelAlign="top"
  274. placeholder="请选择年级"
  275. isLink
  276. readonly
  277. modelValue={formatterClass(forms.currentGrade, forms.currentGradeList)}
  278. clickable={false}
  279. onClick={() => (forms.showPicker = true)}
  280. />
  281. <Field
  282. label="班级"
  283. labelAlign="top"
  284. placeholder="请选择班级"
  285. isLink
  286. readonly
  287. modelValue={formatterClass(forms.currentClass, classList)}
  288. clickable={false}
  289. onClick={() => (forms.classPicker = true)}
  290. />
  291. <Button class={styles.submitBtn} onClick={onSubmit}></Button>
  292. </CellGroup>
  293. </div>
  294. {/* 是否在微信中打开 */}
  295. <OWxTip />
  296. {/* 年级 */}
  297. <Popup v-model:show={forms.showPicker} position="bottom" round>
  298. <Picker
  299. columns={forms.currentGradeList}
  300. onCancel={() => (forms.showPicker = false)}
  301. onConfirm={({ selectedValues }) => {
  302. forms.currentGrade = selectedValues[0]
  303. forms.showPicker = false
  304. }}
  305. />
  306. </Popup>
  307. {/* 班级 */}
  308. <Popup v-model:show={forms.classPicker} position="bottom" round>
  309. <Picker
  310. columns={classList}
  311. onCancel={() => (forms.classPicker = false)}
  312. onConfirm={({ selectedValues }) => {
  313. forms.currentClass = selectedValues[0]
  314. forms.classPicker = false
  315. }}
  316. />
  317. </Popup>
  318. </div>
  319. )
  320. }
  321. })