index.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. import { defineComponent, onMounted, reactive } from 'vue';
  2. import styles from './index.module.less';
  3. import MHeader from '@/components/m-header';
  4. import { Area, Button, CellGroup, Field, Form, Popup, showToast } from 'vant';
  5. import icon_school from './images/icon_school.png';
  6. import icon_person from './images/icon_person.png';
  7. import icon_submit from './images/icon_submit.png';
  8. import icon_logo from './images/logo.png';
  9. import icon_p1 from './images/icon_p1.png';
  10. import icon_p2 from './images/icon_p2.png';
  11. import {
  12. api_openSendSms,
  13. api_schoolAdd,
  14. api_sysAreaQueryAllProvince
  15. } from './api';
  16. import { useRoute } from 'vue-router';
  17. import MImgCode from '@/components/m-img-code';
  18. export default defineComponent({
  19. name: 'SchoolRegister',
  20. setup() {
  21. const route = useRoute();
  22. const formOptions = {
  23. /** 性质 */
  24. nature: [
  25. { label: '公立', value: 'PUBLIC' },
  26. { label: '私立', value: 'PRIVATE' }
  27. ],
  28. types: [
  29. { label: '小学', value: 'PRIMARY' },
  30. { label: '初中', value: 'JUNIOR' },
  31. { label: '小初一体', value: 'PRIMARY_JUNIOR' }
  32. ],
  33. grades: [
  34. { label: '六年制', value: 'SIX_YEAR_SYSTEM' },
  35. { label: '五年制', value: 'FIVE_YEAR_SYSTEM' }
  36. ],
  37. genaral: [
  38. { label: '男', value: '1' },
  39. { label: '女', value: '0' }
  40. ]
  41. };
  42. const forms = reactive({
  43. name: '', // 学校名称
  44. regionCode: '', // 所属区域
  45. cityCode: '', // 所属城市
  46. provinceCode: '', // 所属省份
  47. schoolNature: 'PUBLIC' as 'PUBLIC' | 'PRIVATE' | string, // 学校性质
  48. schoolType: 'PRIMARY_JUNIOR' as 'PRIMARY' | 'JUNIOR' | 'PRIMARY_JUNIOR' | string, // 学校类型
  49. gradeYear: 'SIX_YEAR_SYSTEM' as
  50. | 'FIVE_YEAR_SYSTEM'
  51. | 'SIX_YEAR_SYSTEM'
  52. | string, // 学年制
  53. emergencyContact: '', // 校长姓名
  54. emergencyContactPhone: '', // 校长联系方式
  55. educationalAdministrationUsername: '', // 负责人姓名
  56. educationalAdministrationPhone: '', // 负责人联系方式
  57. genaral: '1', // 性别
  58. code: '', // 验证码
  59. buyGoods: true, // 是否购买商品
  60. tenantId: route.query.id || '', // 机构
  61. sourceForm: 'TEACHER'
  62. });
  63. const data = reactive({
  64. cityName: '', // 所属城市
  65. showArea: false,
  66. success: false,
  67. areaList: {} as any,
  68. sendMsg: '发送验证码',
  69. imgCodeStatus: false
  70. });
  71. const formateArea = (area: any[]) => {
  72. const province_list: { [_: string]: string } = {};
  73. const city_list: { [_: string]: string } = {};
  74. const county_list: { [_: string]: string } = {};
  75. area.forEach((item: any) => {
  76. province_list[item.code] = item.name;
  77. });
  78. area.forEach((item: any) => {
  79. item.areas?.forEach((city: any) => {
  80. city_list[city.code] = city.name;
  81. });
  82. });
  83. area.forEach((item: any) => {
  84. item.areas?.forEach((city: any) => {
  85. city.areas?.forEach((county: any) => {
  86. county_list[county.code] = county.name;
  87. });
  88. });
  89. });
  90. return {
  91. province_list,
  92. city_list,
  93. county_list
  94. };
  95. };
  96. const getAreaList = () => {
  97. api_sysAreaQueryAllProvince().then(res => {
  98. if (res?.code === 200) {
  99. data.areaList = formateArea(res.data);
  100. console.log('🚀 ~ data.areaList:', data.areaList);
  101. }
  102. });
  103. };
  104. onMounted(() => {
  105. getAreaList();
  106. });
  107. /** 发送验证码 */
  108. const onSendSms = async () => {
  109. try {
  110. await api_openSendSms({
  111. clientId: 'cooleshow-student',
  112. type: 'REGISTER',
  113. mobile: forms.educationalAdministrationPhone
  114. });
  115. onCountDown();
  116. showToast('验证码已发送');
  117. } catch {
  118. data.sendMsg = '重新发送';
  119. }
  120. };
  121. const onCountDown = () => {
  122. data.sendMsg = '30s';
  123. let count = 30;
  124. setInterval(() => {
  125. count--;
  126. data.sendMsg = `${count}s后重新发送`;
  127. if (count <= 0) {
  128. data.sendMsg = '重新发送';
  129. }
  130. }, 1000);
  131. };
  132. const handleSubmit = async () => {
  133. const res = await api_schoolAdd({ ...forms });
  134. if (res?.code === 200) {
  135. data.success = true;
  136. }
  137. };
  138. return () => (
  139. <div class={styles.container}>
  140. <img class={styles.titleIcon} src={icon_logo} />
  141. <div class={styles.title}>{route.query.name}</div>
  142. <div class={styles.tagWrap}>
  143. <div class={styles.tag}>
  144. <span>·</span> 课堂乐器学校登记 <span>·</span>
  145. </div>
  146. </div>
  147. <div class={styles.contentWrap}>
  148. <div class={styles.content}>
  149. <Form onSubmit={() => handleSubmit()}>
  150. <CellGroup class={styles.group}>
  151. <img src={icon_school} class={styles.icon} />
  152. <Field
  153. border
  154. name="name"
  155. label="学校全称"
  156. rows="1"
  157. autosize
  158. type="textarea"
  159. placeholder="请输入学校全称"
  160. inputAlign="right"
  161. v-model={forms.name}
  162. maxlength={20}
  163. rules={[{ required: true, message: '请输入学校全称' }]}
  164. />
  165. <Field
  166. isLink
  167. border
  168. label="所属城市"
  169. placeholder="请选择"
  170. readonly
  171. inputAlign="right"
  172. v-model={data.cityName}
  173. onClick={() => (data.showArea = true)}
  174. rules={[{ required: true, message: '请选择' }]}></Field>
  175. <Field center border name="schoolNature" label="办学性质">
  176. {{
  177. input: () => (
  178. <>
  179. {formOptions.nature.map(item => {
  180. return (
  181. <Button
  182. class={styles.radio}
  183. size="small"
  184. color={
  185. item.value === forms.schoolNature
  186. ? '#198CFE'
  187. : ''
  188. }
  189. onClick={() => (forms.schoolNature = item.value)}>
  190. {item.label}
  191. </Button>
  192. );
  193. })}
  194. </>
  195. )
  196. }}
  197. </Field>
  198. <Field center border label="学年制">
  199. {{
  200. input: () => (
  201. <>
  202. {formOptions.grades.map(item => {
  203. return (
  204. <Button
  205. class={styles.radio}
  206. size="small"
  207. color={
  208. item.value === forms.gradeYear ? '#198CFE' : ''
  209. }
  210. onClick={() => (forms.gradeYear = item.value)}>
  211. {item.label}
  212. </Button>
  213. );
  214. })}
  215. </>
  216. )
  217. }}
  218. </Field>
  219. </CellGroup>
  220. <CellGroup class={styles.group}>
  221. <img src={icon_person} class={styles.icon} />
  222. <Field
  223. border
  224. name="emergencyContact"
  225. label="校长姓名"
  226. placeholder="请输入校长姓名"
  227. inputAlign="right"
  228. maxlength={6}
  229. v-model={forms.emergencyContact}
  230. rules={[{ required: true, message: '请输入校长姓名' }]}
  231. />
  232. <Field
  233. border
  234. name="emergencyContactPhone"
  235. label="校长联系方式"
  236. maxlength={11}
  237. placeholder="请输入校长手机号码"
  238. inputAlign="right"
  239. v-model={forms.emergencyContactPhone}
  240. rules={[
  241. { required: true, message: '请输入校长手机号码' },
  242. {
  243. pattern: /^1[3456789]\d{9}$/,
  244. message: '请输入正确的手机号码'
  245. }
  246. ]}
  247. />
  248. <Field
  249. border
  250. name="educationalAdministrationUsername"
  251. label="负责人姓名"
  252. placeholder="请输入负责人姓名"
  253. inputAlign="right"
  254. maxlength={6}
  255. v-model={forms.educationalAdministrationUsername}
  256. rules={[{ required: true, message: '请输入负责人姓名' }]}
  257. />
  258. <Field
  259. border
  260. name="educationalAdministrationPhone"
  261. label="负责人联系方式"
  262. labelWidth="40%"
  263. inputAlign="right"
  264. placeholder="请输入负责人手机号码"
  265. maxlength={11}
  266. v-model={forms.educationalAdministrationPhone}
  267. rules={[
  268. { required: true, message: '请输入负责人手机号码' },
  269. {
  270. pattern: /^1[3456789]\d{9}$/,
  271. message: '请输入正确的手机号码'
  272. }
  273. ]}
  274. />
  275. <Field center border label="性别">
  276. {{
  277. input: () => (
  278. <>
  279. {formOptions.genaral.map(item => {
  280. return (
  281. <Button
  282. class={styles.radio}
  283. size="small"
  284. color={
  285. item.value === forms.genaral ? '#198CFE' : ''
  286. }
  287. onClick={() => (forms.genaral = item.value)}>
  288. {item.label}
  289. </Button>
  290. );
  291. })}
  292. </>
  293. )
  294. }}
  295. </Field>
  296. <Field
  297. class={styles.codeWrap}
  298. border
  299. name="code"
  300. label="验证码"
  301. placeholder="请输入验证码"
  302. v-model={forms.code}
  303. maxlength={6}
  304. rules={[{ required: true, message: '请输入验证码' }]}>
  305. {{
  306. button: () => (
  307. <Button
  308. size="small"
  309. type="primary"
  310. color="#198CFE"
  311. onClick={() => {
  312. if (!forms.educationalAdministrationPhone) {
  313. showToast('请输入负责人手机号码');
  314. return;
  315. }
  316. if (
  317. !/^1[3456789]\d{9}$/.test(
  318. forms.educationalAdministrationPhone
  319. )
  320. ) {
  321. showToast('手机号码格式不正确');
  322. return;
  323. }
  324. data.imgCodeStatus = true;
  325. }}>
  326. {data.sendMsg}
  327. </Button>
  328. )
  329. }}
  330. </Field>
  331. <div style={{ padding: '10px 16px' }}>
  332. <div class={styles.tips}>
  333. 负责人即为该学校酷乐秀课堂乐器老师端管理员,手机号即为酷乐秀课堂乐器老师端账号,默认密码为:ktyq+手机号后四位
  334. </div>
  335. </div>
  336. </CellGroup>
  337. <Button class={styles.submit} round block native-type="submit">
  338. <img class={styles.submitIcon} src={icon_submit} />
  339. </Button>
  340. </Form>
  341. <Popup v-model:show={data.showArea} position="bottom">
  342. <Area
  343. areaList={data.areaList}
  344. onCancel={() => (data.showArea = false)}
  345. onConfirm={({ selectedOptions }) => {
  346. forms.provinceCode = selectedOptions[0].value;
  347. forms.cityCode = selectedOptions[1].value;
  348. forms.regionCode = selectedOptions[2].value;
  349. data.cityName = selectedOptions
  350. .map((item: any) => item.text)
  351. .join('-');
  352. data.showArea = false;
  353. }}
  354. />
  355. </Popup>
  356. <Popup
  357. class="popup-custom van-scale"
  358. transition="van-scale"
  359. closeOnClickOverlay={false}
  360. v-model:show={data.success}>
  361. <div class={styles.successWrap}>
  362. <img class={styles.p1} src={icon_p1} />
  363. <img class={styles.p2} src={icon_p2} />
  364. <div class={styles.btnWrap}>
  365. <div class={styles.btnTitle}>您已成功登记</div>
  366. <div class={styles.btnDes}>欢迎您使用酷乐秀课堂乐器~</div>
  367. <Button class={styles.btn} type="primary" round>
  368. 我知道了
  369. </Button>
  370. </div>
  371. </div>
  372. </Popup>
  373. {data.imgCodeStatus ? (
  374. <MImgCode
  375. v-model:value={data.imgCodeStatus}
  376. phone={forms.educationalAdministrationPhone}
  377. onClose={() => {
  378. data.imgCodeStatus = false;
  379. }}
  380. onSendCode={onSendSms}
  381. />
  382. ) : null}
  383. </div>
  384. </div>
  385. </div>
  386. );
  387. }
  388. });