manage-teacher-register.tsx 17 KB

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