manage-teacher-register.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. import { areas } from '@/helpers/area'
  2. import request from '@/helpers/request'
  3. import {
  4. CellGroup,
  5. Form,
  6. Field,
  7. RadioGroup,
  8. Tag,
  9. Icon,
  10. Checkbox,
  11. Radio,
  12. Button,
  13. showToast,
  14. showDialog,
  15. showLoadingToast,
  16. closeToast,
  17. Picker,
  18. Popup,
  19. CountDown
  20. } from 'vant'
  21. import { defineComponent, onMounted, reactive } from 'vue'
  22. import { useRoute } from 'vue-router'
  23. import styles from './manage-teacher-register.module.less'
  24. import ImgCode from '@/components/o-img-code'
  25. import schoolLogo from './images/school-logo.png'
  26. import iconClose from './images/icon-close.png'
  27. import topBanner1 from './images/top-banner.png'
  28. import { checkPhone } from '@/helpers/validate'
  29. import dayjs from 'dayjs'
  30. import { browser, getUrlCode } from '@/helpers/utils'
  31. import OUpload from '@/components/o-upload'
  32. import qs from 'query-string'
  33. export default defineComponent({
  34. name: 'companion-teacher-register',
  35. setup() {
  36. const route = useRoute()
  37. const state = reactive({
  38. showPicker: false,
  39. showSubject: false,
  40. submitStatus: false,
  41. id: route.query.id,
  42. name: route.query.name,
  43. t: route.query.t as any, // 过期时间
  44. qrCodeStatus: false, // 二维码是否失效
  45. qrCodeMessage: '',
  46. pattern: /^1(3|4|5|6|7|8|9)\d{9}$/,
  47. columns: [] as any,
  48. pickerType: null, // 下拉类型
  49. forms: {
  50. realName: '',
  51. phone: null,
  52. gender: 1,
  53. idCardNo: null,
  54. smsValidCode: '',
  55. idcardFrontImg: '',
  56. idcardBackImg: '' // 身份证反面照
  57. },
  58. btnLoading: false,
  59. checkPhone: false,
  60. checked: true,
  61. columnSubject: [] as any,
  62. countDownStatus: true, // 是否发送验证码
  63. countDownTime: 120, // 倒计时时间
  64. // countDownRef: null as any, // 倒计时实例
  65. imgCodeStatus: false,
  66. showPopup: false,
  67. code: ''
  68. })
  69. const onSubmit = async () => {
  70. if (state.qrCodeStatus) {
  71. showDialog({
  72. title: '提示',
  73. message: state.qrCodeMessage,
  74. theme: 'round-button',
  75. confirmButtonColor: '#ff8057'
  76. })
  77. return
  78. }
  79. if (!state.checked) {
  80. showToast('请阅读并同意协议')
  81. return
  82. }
  83. state.btnLoading = true
  84. try {
  85. const forms = state.forms
  86. await request.post('/api-school/open/schoolStaff/registerTeacher', {
  87. data: {
  88. ...forms,
  89. schoolId: state.id
  90. }
  91. })
  92. // state.submitStatus = true
  93. window.location.href =
  94. 'https://mp.weixin.qq.com/s?__biz=MzkxMDMwOTI5Nw==&mid=2247485261&idx=1&sn=70c79a832a609bf9fae01c9e90fb4f69&chksm=c12c2593f65bac85d26362bca470f6abc2bfc087d9f4dcf87c00094420bdf5a3acb1b870199b#rd'
  95. } catch {
  96. //
  97. }
  98. state.btnLoading = false
  99. }
  100. const onSendCode = () => {
  101. // 发送验证码
  102. if (!checkPhone(state.forms.phone as any)) {
  103. return showToast('请输入正确的手机号码')
  104. }
  105. state.imgCodeStatus = true
  106. }
  107. const onCodeSend = () => {
  108. state.countDownStatus = false
  109. const clearTimer = setInterval(() => {
  110. state.countDownTime = state.countDownTime - 1
  111. if (state.countDownTime <= 0) {
  112. state.countDownTime = 120
  113. state.countDownStatus = true
  114. clearInterval(clearTimer)
  115. }
  116. }, 1000)
  117. }
  118. const onFinished = () => {
  119. state.countDownStatus = true
  120. // ;(this.$refs.countDownRef as any).reset()
  121. }
  122. onMounted(async () => {
  123. if (!state.id) {
  124. showToast('信息获取失败,请联系老师')
  125. }
  126. // 判断是否是微信,只能微信中打开
  127. // if (!browser().weixin) {
  128. // state.showPopup = true
  129. // return
  130. // } else {
  131. // //授权
  132. // const code = getUrlCode()
  133. // if (!code) {
  134. // const newUrl =
  135. // window.location.origin +
  136. // window.location.pathname +
  137. // '#' +
  138. // route.path +
  139. // '?' +
  140. // qs.stringify({
  141. // ...route.query
  142. // })
  143. // getAppIdAndCode(newUrl)
  144. // return
  145. // } else {
  146. // state.code = code
  147. // }
  148. // }
  149. // t: route.query.t, // 过期时间
  150. try {
  151. const res = await request.post('/api-school/open/schoolTeacherStudent/queryQrCodeStatus', {
  152. data: {
  153. schoolId: state.id,
  154. qrCodeEffectiveStartTime: state.t
  155. ? dayjs(Number(state.t)).format('YYYY-MM-DD HH:mm:ss')
  156. : null
  157. }
  158. })
  159. if (res.code === 999) {
  160. showDialog({
  161. title: '提示',
  162. message: res.message,
  163. theme: 'round-button',
  164. confirmButtonColor: '#FF8057'
  165. })
  166. state.qrCodeStatus = true
  167. state.qrCodeMessage = res.message
  168. }
  169. } catch (e: any) {
  170. //
  171. console.log(e)
  172. }
  173. try {
  174. const tempareas: any = []
  175. areas.forEach((item) => {
  176. const temp = {
  177. name: item.name,
  178. code: item.code,
  179. areas: [] as any
  180. }
  181. if (item.areas && item.areas.length > 0) {
  182. item.areas.forEach((child) => {
  183. temp.areas.push({
  184. name: child.name,
  185. code: child.code
  186. })
  187. })
  188. }
  189. tempareas.push(temp)
  190. })
  191. state.columns = tempareas || []
  192. const { data } = await request.post(
  193. '/api-school/open/orchestraSubjectConfig/pageByOrchestraId',
  194. {
  195. data: {
  196. orchestraId: state.id,
  197. page: 1,
  198. rows: 50
  199. }
  200. }
  201. )
  202. const rows = data.rows || []
  203. const tempSubjects: any = []
  204. rows.forEach((item) => {
  205. tempSubjects.push({
  206. text: item.name,
  207. value: item.subjectId
  208. })
  209. })
  210. state.columnSubject = tempSubjects
  211. } catch {
  212. showDialog({
  213. message: '信息获取失败,请联系老师',
  214. theme: 'round-button',
  215. confirmButtonColor: '#FF8057'
  216. })
  217. }
  218. })
  219. const getAppIdAndCode = async (url?: string) => {
  220. try {
  221. const { data } = await request.get('/api-school/open/paramConfig/wechatAppId')
  222. // 判断是否有微信appId
  223. if (data) {
  224. closeToast()
  225. goAuth(data, url)
  226. }
  227. } catch {
  228. //
  229. }
  230. }
  231. const goAuth = (wxAppId: string, urlString?: string) => {
  232. // 用户授权
  233. console.log(urlString || window.location.href, 'urlString || window.location.href')
  234. const urlNow = encodeURIComponent(urlString || window.location.href)
  235. console.log(urlNow, 'urlNow')
  236. const scope = 'snsapi_base' //snsapi_userinfo //静默授权 用户无感知
  237. const appid = wxAppId || 'wx8654c671631cfade'
  238. const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${urlNow}&response_type=code&scope=${scope}&state=STATE&connect_redirect=1#wechat_redirect`
  239. window.location.replace(url)
  240. }
  241. const onPreview = (type: string) => {
  242. if (type === 'REGISTER') {
  243. window.open(
  244. window.location.origin + window.location.pathname + '#/preview-protocol',
  245. '_blank'
  246. )
  247. } else if (type === 'PRIVACY') {
  248. window.open(
  249. window.location.origin + window.location.pathname + '#/privacyProtocol',
  250. '_blank'
  251. )
  252. } else if (type === 'WITHDRAW') {
  253. //
  254. window.open(window.location.origin + window.location.pathname + '#/cashProtocol', '_blank')
  255. }
  256. }
  257. return () => (
  258. <div class={styles.register}>
  259. <div class={styles.title}>
  260. <p class={styles.tips}>
  261. <img src={schoolLogo} />
  262. <span>{state.name}</span>
  263. </p>
  264. </div>
  265. <Form validateFirst scrollToError onSubmit={onSubmit} ref="form" class={styles.form}>
  266. <CellGroup inset class={styles['cell-group']}>
  267. <Field
  268. label="真实姓名"
  269. v-model={state.forms.realName}
  270. rules={[{ required: true, message: '请填写真实姓名' }]}
  271. name="realName"
  272. placeholder="请填写真实姓名"
  273. maxlength="5"
  274. ></Field>
  275. <Field
  276. label="手机号码"
  277. v-model={state.forms.phone}
  278. rules={[
  279. { required: true, message: '请输入手机号码' },
  280. { pattern: state.pattern, message: '输入手机号码有误' }
  281. ]}
  282. name="phone"
  283. placeholder="请输入手机号码"
  284. maxlength={11}
  285. type="tel"
  286. ></Field>
  287. <div class={styles.phoneTips}>
  288. <Icon name="warning" size="16" />
  289. 提示:手机号码将成为您管乐团管理端登录账号
  290. </div>
  291. <Field
  292. label="身份证号码"
  293. v-model={state.forms.idCardNo}
  294. rules={[
  295. { required: true, message: '请输入身份证号' },
  296. {
  297. pattern:
  298. /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
  299. message: '请输入正确的身份证号'
  300. }
  301. ]}
  302. name="idCardNo"
  303. placeholder="请输入身份证号码"
  304. ></Field>
  305. <div class={[styles.fieldGroup, 'van-hairline--bottom']}>
  306. <Field
  307. label="身份证照片正面"
  308. v-model={state.forms.idcardFrontImg}
  309. readonly
  310. border={false}
  311. name="idcardFrontImg"
  312. rules={[{ required: true, message: '请上传身份证正面', trigger: 'onChange' }]}
  313. placeholder="请上传身份证正面"
  314. >
  315. {{
  316. input: () => (
  317. <OUpload
  318. style={{ width: '100%' }}
  319. tips="上传身份证正面"
  320. bucket="gyt"
  321. path="/user/"
  322. v-model:modelValue={state.forms.idcardFrontImg}
  323. />
  324. )
  325. }}
  326. </Field>
  327. <Field
  328. label={'上传身份证反面'}
  329. labelClass={styles.fieldTitle}
  330. v-model={state.forms.idcardBackImg}
  331. readonly
  332. border={false}
  333. name="idcardBackImg"
  334. rules={[{ required: true, message: '请上传身份证反面', trigger: 'onChange' }]}
  335. placeholder="请上传身份证反面"
  336. >
  337. {{
  338. input: () => (
  339. <OUpload
  340. style={{ width: '100%' }}
  341. tips="上传身份证反面"
  342. bucket="gyt"
  343. path="/user/"
  344. v-model:modelValue={state.forms.idcardBackImg}
  345. />
  346. )
  347. }}
  348. </Field>
  349. </div>
  350. <Field label="性别" name="gender" rules={[{ required: true, message: '请选择性别' }]}>
  351. {{
  352. input: () => (
  353. <RadioGroup
  354. checked-color="#FF8057"
  355. v-model={state.forms.gender}
  356. direction="horizontal"
  357. >
  358. <Tag
  359. size="large"
  360. type="primary"
  361. color={!(state.forms.gender === 1) ? '#EAEAEA' : '#FF8057'}
  362. textColor={!(state.forms.gender === 1) ? '#AAA' : '#FFF'}
  363. class={styles.radioSection}
  364. round
  365. >
  366. <Radio class={styles.radioItem} name={1}></Radio>男
  367. </Tag>
  368. <Tag
  369. size="large"
  370. type="primary"
  371. color={!(state.forms.gender === 0) ? '#EAEAEA' : '#FF8057'}
  372. textColor={!(state.forms.gender === 0) ? '#AAA' : '#FFF'}
  373. class={styles.radioSection}
  374. round
  375. >
  376. <Radio class={styles.radioItem} name={0}></Radio>女
  377. </Tag>
  378. </RadioGroup>
  379. )
  380. }}
  381. </Field>
  382. <Field
  383. label="验证码"
  384. v-model={state.forms.smsValidCode}
  385. name="smsValidCode"
  386. rules={[{ required: true, message: '请输入验证码', trigger: 'onChange' }]}
  387. placeholder="请输入验证码"
  388. maxlength={6}
  389. type="tel"
  390. >
  391. {{
  392. button: () =>
  393. state.countDownStatus ? (
  394. <Button type="primary" round size="small" color="#FF8057" onClick={onSendCode}>
  395. 发送验证码
  396. </Button>
  397. ) : (
  398. <Button
  399. type="default"
  400. round
  401. size="small"
  402. disabled
  403. style={{ minWidth: '60px' }}
  404. onClick={onSendCode}
  405. >
  406. {state.countDownTime + 's'}
  407. </Button>
  408. )
  409. }}
  410. </Field>
  411. </CellGroup>
  412. <div class={styles.protocol}>
  413. <Checkbox
  414. v-model={state.checked}
  415. icon-size="16"
  416. style="margin-right: 6px"
  417. checked-color="#FF8057"
  418. ></Checkbox>
  419. <div>
  420. <span
  421. onClick={() => {
  422. state.checked = !state.checked
  423. }}
  424. >
  425. 请认真阅读并勾选
  426. </span>
  427. <span class={styles.c} onClick={() => onPreview('REGISTER')}>
  428. 《管乐团用户注册协议》
  429. </span>
  430. <span class={styles.c} onClick={() => onPreview('PRIVACY')}>
  431. 《隐私协议》
  432. </span>
  433. <span class={styles.c} onClick={() => onPreview('WITHDRAW')}>
  434. 《共享经济平台注册经营者协议》
  435. </span>
  436. </div>
  437. </div>
  438. <Button
  439. size="large"
  440. block
  441. round
  442. class={styles['btn-submit']}
  443. color="#FF8057"
  444. loading={state.btnLoading}
  445. native-type="submit"
  446. >
  447. 完成
  448. </Button>
  449. </Form>
  450. <Popup v-model:show={state.submitStatus} round style="width: 75%" closeOnClickOverlay>
  451. <div class={styles.stautsS}>
  452. <img src={topBanner1} class={styles['submit-img']} />
  453. <div class={styles['submit-container']}>
  454. <p class={styles['submit-title']}>恭喜您已成功登记为</p>
  455. <p class={styles['submit-o']}>
  456. {state.name} <br />
  457. <span>【管理老师】</span>
  458. </p>
  459. <p class={styles['submit-tips']}>请下载管乐团管理端APP</p>
  460. <Button
  461. type="primary"
  462. color="#FF8057"
  463. block
  464. round
  465. onClick={() => {
  466. state.submitStatus = false
  467. window.location.href =
  468. window.location.origin + '/orchestra-student/#/download?type=manage'
  469. }}
  470. >
  471. 立即下载
  472. </Button>
  473. </div>
  474. </div>
  475. </Popup>
  476. {state.imgCodeStatus ? (
  477. <ImgCode
  478. v-model:value={state.imgCodeStatus}
  479. phone={state.forms.phone as any}
  480. type="REGISTER"
  481. onClose={() => {
  482. state.imgCodeStatus = false
  483. }}
  484. onSendCode={onCodeSend}
  485. />
  486. ) : null}
  487. <Popup
  488. v-model:show={state.showPopup}
  489. round
  490. style={{ width: '88%' }}
  491. closeOnClickOverlay={false}
  492. class={styles.wxPopupDialog}
  493. >
  494. <div class={styles.popupContainer}>
  495. <p class={styles.title1}>温馨提示</p>
  496. <p class={styles.popupTips}>请使用微信打开</p>
  497. </div>
  498. </Popup>
  499. </div>
  500. )
  501. }
  502. })