index.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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' 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. if (data.sendMsg.includes('s')) return;
  110. onCountDown();
  111. showToast('验证码已发送');
  112. };
  113. const onCountDown = () => {
  114. data.sendMsg = '60s';
  115. let count = 60;
  116. let timer = setInterval(() => {
  117. count--;
  118. data.sendMsg = `${count}s`;
  119. if (count <= 0) {
  120. data.sendMsg = '重新发送';
  121. clearInterval(timer);
  122. }
  123. }, 1000);
  124. };
  125. const handleSubmit = async () => {
  126. forms.name = forms.name.trim();
  127. const res = await api_schoolAdd({ ...forms });
  128. if (res?.code === 200) {
  129. data.success = true;
  130. }
  131. };
  132. return () => (
  133. <div class={styles.container}>
  134. <div class={styles.containerBg}>
  135. <img class={styles.titleIcon} src={icon_logo} />
  136. <div class={styles.title}>{route.query.name}</div>
  137. <div class={styles.tagWrap}>
  138. <div class={styles.tag}>
  139. <span>·</span> 音乐数字课堂学校登记 <span>·</span>
  140. </div>
  141. </div>
  142. <div class={styles.contentWrap}>
  143. <div class={styles.content}>
  144. <Form onSubmit={() => handleSubmit()}>
  145. <CellGroup class={styles.group}>
  146. <img src={icon_school} class={styles.icon} />
  147. <Field
  148. border
  149. name="name"
  150. label="学校全称"
  151. rows="1"
  152. autosize
  153. // type="textarea"
  154. placeholder="请输入学校全称"
  155. inputAlign="right"
  156. v-model={forms.name}
  157. autocomplete="off"
  158. maxlength={20}
  159. rules={[{ required: true, message: '请输入学校全称' }]}
  160. />
  161. <Field
  162. isLink
  163. border
  164. label="所属城市"
  165. placeholder="请选择"
  166. readonly
  167. inputAlign="right"
  168. v-model={data.cityName}
  169. onClick={() => (data.showArea = true)}
  170. rules={[{ required: true, message: '请选择' }]}></Field>
  171. <Field center border name="schoolNature" label="办学性质">
  172. {{
  173. input: () => (
  174. <>
  175. {formOptions.nature.map(item => {
  176. return (
  177. <Button
  178. class={styles.radio}
  179. size="small"
  180. color={
  181. item.value === forms.schoolNature
  182. ? '#198CFE'
  183. : ''
  184. }
  185. onClick={() =>
  186. (forms.schoolNature = item.value)
  187. }>
  188. {item.label}
  189. </Button>
  190. );
  191. })}
  192. </>
  193. )
  194. }}
  195. </Field>
  196. <Field center border label="学校类型" labelWidth="70px">
  197. {{
  198. input: () => (
  199. <>
  200. {formOptions.types.map(item => {
  201. return (
  202. <Button
  203. class={styles.radio}
  204. size="small"
  205. color={
  206. item.value === forms.schoolType
  207. ? '#198CFE'
  208. : ''
  209. }
  210. onClick={() => {
  211. forms.schoolType = item.value;
  212. forms.gradeYear =
  213. item.value === 'PRIMARY_JUNIOR'
  214. ? 'NINE_YEAR_SYSTEM'
  215. : 'SIX_YEAR_SYSTEM';
  216. }}>
  217. {item.label}
  218. </Button>
  219. );
  220. })}
  221. </>
  222. )
  223. }}
  224. </Field>
  225. {forms.schoolType === 'PRIMARY_JUNIOR' ? null : (
  226. <Field center border label="学年制">
  227. {{
  228. input: () => (
  229. <>
  230. {formOptions.grades.map(item => {
  231. return (
  232. <Button
  233. class={styles.radio}
  234. size="small"
  235. color={
  236. item.value === forms.gradeYear
  237. ? '#198CFE'
  238. : ''
  239. }
  240. onClick={() =>
  241. (forms.gradeYear = item.value)
  242. }>
  243. {item.label}
  244. </Button>
  245. );
  246. })}
  247. </>
  248. )
  249. }}
  250. </Field>
  251. )}
  252. </CellGroup>
  253. <CellGroup class={styles.group}>
  254. <img src={icon_person} class={styles.icon} />
  255. <Field
  256. border
  257. name="emergencyContact"
  258. label="校长姓名"
  259. placeholder="请输入校长姓名"
  260. inputAlign="right"
  261. maxlength={6}
  262. v-model={forms.emergencyContact}
  263. rules={[{ required: true, message: '请输入校长姓名' }]}
  264. />
  265. <Field
  266. border
  267. name="emergencyContactPhone"
  268. label="校长联系方式"
  269. maxlength={11}
  270. placeholder="请输入校长手机号码"
  271. inputAlign="right"
  272. v-model={forms.emergencyContactPhone}
  273. rules={[
  274. { required: true, message: '请输入校长手机号码' },
  275. {
  276. pattern: /^1[3456789]\d{9}$/,
  277. message: '请输入正确的手机号码'
  278. }
  279. ]}
  280. />
  281. <Field
  282. border
  283. name="educationalAdministrationUsername"
  284. label="负责人姓名"
  285. placeholder="请输入负责人姓名"
  286. inputAlign="right"
  287. maxlength={6}
  288. v-model={forms.educationalAdministrationUsername}
  289. rules={[{ required: true, message: '请输入负责人姓名' }]}
  290. />
  291. <Field
  292. border
  293. name="educationalAdministrationPhone"
  294. label="负责人联系方式"
  295. labelWidth="40%"
  296. inputAlign="right"
  297. placeholder="请输入负责人手机号码"
  298. maxlength={11}
  299. v-model={forms.educationalAdministrationPhone}
  300. rules={[
  301. { required: true, message: '请输入负责人手机号码' },
  302. {
  303. pattern: /^1[3456789]\d{9}$/,
  304. message: '请输入正确的手机号码'
  305. }
  306. ]}
  307. />
  308. <Field center border label="性别">
  309. {{
  310. input: () => (
  311. <>
  312. {formOptions.genaral.map(item => {
  313. return (
  314. <Button
  315. class={styles.radio}
  316. size="small"
  317. color={
  318. item.value === forms.genaral ? '#198CFE' : ''
  319. }
  320. onClick={() => (forms.genaral = item.value)}>
  321. {item.label}
  322. </Button>
  323. );
  324. })}
  325. </>
  326. )
  327. }}
  328. </Field>
  329. <Field
  330. class={styles.codeWrap}
  331. border
  332. name="code"
  333. label="验证码"
  334. placeholder="请输入验证码"
  335. v-model={forms.code}
  336. maxlength={6}
  337. rules={[{ required: true, message: '请输入验证码' }]}>
  338. {{
  339. button: () => (
  340. <Button
  341. disabled={data.sendMsg.includes('s')}
  342. class={styles.sendBtn}
  343. size="small"
  344. type="primary"
  345. color="#198CFE"
  346. onClick={() => {
  347. if (!forms.educationalAdministrationPhone) {
  348. showToast('请输入负责人手机号码');
  349. return;
  350. }
  351. if (
  352. !/^1[3456789]\d{9}$/.test(
  353. forms.educationalAdministrationPhone
  354. )
  355. ) {
  356. showToast('手机号码格式不正确');
  357. return;
  358. }
  359. data.imgCodeStatus = true;
  360. }}>
  361. {data.sendMsg}
  362. </Button>
  363. )
  364. }}
  365. </Field>
  366. <div style={{ padding: '10px 16px' }}>
  367. <div class={styles.tips}>
  368. 负责人即为该学校音乐数字课堂老师端管理员,手机号即为音乐数字课堂老师端账号,默认密码为:yyszkt+手机号后四位
  369. </div>
  370. </div>
  371. </CellGroup>
  372. <Button class={styles.submit} round block native-type="submit">
  373. <img class={styles.submitIcon} src={icon_submit} />
  374. </Button>
  375. </Form>
  376. <Popup v-model:show={data.showArea} position="bottom">
  377. <Area
  378. areaList={data.areaList}
  379. onCancel={() => (data.showArea = false)}
  380. onConfirm={({ selectedOptions }) => {
  381. forms.provinceCode = selectedOptions[0].value;
  382. forms.cityCode = selectedOptions[1].value;
  383. forms.regionCode = selectedOptions[2].value;
  384. data.cityName = selectedOptions
  385. .map((item: any) => item.text)
  386. .join('-');
  387. data.showArea = false;
  388. }}
  389. />
  390. </Popup>
  391. <Popup
  392. class="popup-custom van-scale"
  393. transition="van-scale"
  394. closeOnClickOverlay={false}
  395. v-model:show={data.success}>
  396. <div class={styles.successWrap}>
  397. <img class={styles.p1} src={icon_p1} />
  398. <img class={styles.p2} src={icon_p2} />
  399. <div class={styles.btnWrap}>
  400. <div class={styles.btnTitle}>您已成功登记</div>
  401. <div class={styles.btnDes}>欢迎您使用音乐数字课堂~</div>
  402. <Button class={styles.btn} type="primary" round>
  403. 我知道了
  404. </Button>
  405. </div>
  406. </div>
  407. </Popup>
  408. {data.imgCodeStatus ? (
  409. <MImgCode
  410. v-model:value={data.imgCodeStatus}
  411. phone={forms.educationalAdministrationPhone}
  412. onClose={() => {
  413. data.imgCodeStatus = false;
  414. }}
  415. onSendCode={onSendSms}
  416. />
  417. ) : null}
  418. </div>
  419. </div>
  420. </div>
  421. </div>
  422. );
  423. }
  424. });