bind-profile.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. <template>
  2. <ie-page bg-color="#F6F8FA" :safeAreaInsetBottom="false">
  3. <ie-navbar title="完善信息"></ie-navbar>
  4. <uv-form labelPosition="left" :model="form" labelWidth="70px" ref="formRef">
  5. <content-card title="个人信息">
  6. <uv-form-item label="姓名" prop="name" borderBottom required>
  7. <uv-input v-model="form.nickName" border="none" placeholder="请输入姓名" placeholderClass="text-30"
  8. font-size="30rpx" :custom-style="customStyle">
  9. </uv-input>
  10. </uv-form-item>
  11. <uv-form-item label="所在省份" prop="location" borderBottom required>
  12. <ie-picker ref="pickerRef" v-model="examTypeForm.location" :list="provinceList"
  13. :placeholder="pickerPlaceholder" :custom-style="customStyle" key-label="areaName" key-value="shortName"
  14. :disabled="isProvinceDisabled">
  15. <template v-if="isProvinceDisabled" #right>
  16. <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
  17. </template>
  18. </ie-picker>
  19. </uv-form-item>
  20. <uv-form-item label="考生类别" prop="examType" borderBottom required>
  21. <ie-picker ref="pickerRef" v-model="examTypeForm.examType" :list="examTypeList" :disabled="isExamTypeDisabled"
  22. :placeholder="pickerPlaceholder" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
  23. @click="handlePreCheck('examType')" @change="handleExamTypeChange">
  24. <template v-if="isExamTypeDisabled" #right>
  25. <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
  26. </template>
  27. </ie-picker>
  28. </uv-form-item>
  29. <uv-form-item v-if="examTypeForm.examType === 'VHS'" label="专业类别" prop="majorType" borderBottom required>
  30. <ie-picker ref="pickerRef" v-model="examTypeForm.majorType" :list="examMajorList"
  31. :disabled="!examTypeForm.examType" :placeholder="pickerPlaceholder" :custom-style="customStyle"
  32. key-label="dictLabel" key-value="dictValue"></ie-picker>
  33. </uv-form-item>
  34. <uv-form-item label="单招年份" prop="year" required>
  35. <ie-picker ref="pickerRef" v-model="examTypeForm.endYear" :list="endYearList"
  36. :disabled="!examTypeForm.examType" :placeholder="pickerPlaceholder" :custom-style="customStyle"
  37. key-label="dictLabel" key-value="dictValue" @click="handlePreCheck('endYear')"></ie-picker>
  38. </uv-form-item>
  39. </content-card>
  40. <content-card title="邀请信息">
  41. <uv-form-item label="邀请码" prop="form.inviteCode">
  42. <uv-input v-model="form.inviteCode" border="none" placeholder="请输入邀请码(非必填)" font-size="30rpx"
  43. :custom-style="customStyle">
  44. </uv-input>
  45. </uv-form-item>
  46. </content-card>
  47. <content-card v-if="showCulture" title="文化素质">
  48. <uv-form-item label="语文" prop="form.scores.chinese" borderBottom :required="isScoreRequired">
  49. <uv-input v-model.number="scoresForm.chinese" border="none" type="number" :placeholder="inputPlaceholder"
  50. font-size="30rpx" :custom-style="customStyle">
  51. </uv-input>
  52. </uv-form-item>
  53. <uv-form-item label="数学" prop="form.score.mathematics" borderBottom :required="isScoreRequired">
  54. <uv-input v-model.number="scoresForm.mathematics" border="none" type="number" :placeholder="inputPlaceholder"
  55. font-size="30rpx" :custom-style="customStyle">
  56. </uv-input>
  57. </uv-form-item>
  58. <uv-form-item label="外语" prop="form.scores.foreign" borderBottom :required="isScoreRequired">
  59. <uv-input v-model.number="scoresForm.foreign" border="none" type="number" :placeholder="inputPlaceholder"
  60. font-size="30rpx" :custom-style="customStyle">
  61. </uv-input>
  62. </uv-form-item>
  63. <uv-form-item label="物理" prop="form.scores.physics" borderBottom :required="isScoreRequired">
  64. <uv-input v-model.number="scoresForm.physics" border="none" type="number" :placeholder="inputPlaceholder"
  65. font-size="30rpx" :custom-style="customStyle">
  66. </uv-input>
  67. </uv-form-item>
  68. <uv-form-item label="政治" prop="form.scores.political" :required="isScoreRequired">
  69. <uv-input v-model.number="scoresForm.political" border="none" type="number" :placeholder="inputPlaceholder"
  70. font-size="30rpx" :custom-style="customStyle">
  71. </uv-input>
  72. </uv-form-item>
  73. </content-card>
  74. <content-card v-if="showSchoolInfo" title="学校信息">
  75. <template #right>
  76. <view class="text-26 text-primary underline" @click="handleNoSchool">没有我的学校班级?</view>
  77. </template>
  78. <uv-form-item label="学校名称" prop="form.name" borderBottom :required="isBindMode">
  79. <ie-picker ref="pickerRef" v-model="form.schoolName" disabled :placeholder="pickerPlaceholder"
  80. :custom-style="customStyle" :custom-label="form.schoolName" @click="handleSchoolSelect">
  81. <template v-if="isSchoolDisabled" #right>
  82. <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
  83. </template>
  84. </ie-picker>
  85. </uv-form-item>
  86. <uv-form-item label="所在班级" prop="form.name" :required="isBindMode">
  87. <ie-picker ref="pickerRef" v-model="form.classId" :list="classList" :disabled="!form.schoolId" title="选择班级"
  88. placeholder="请选择" :custom-style="customStyle" key-label="name" key-value="classId"
  89. @click="handlePreCheck('classId')">
  90. <template v-if="isClassDisabled" #right>
  91. <ie-image src="/static/image/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
  92. </template>
  93. </ie-picker>
  94. </uv-form-item>
  95. </content-card>
  96. </uv-form>
  97. <ie-safe-toolbar :height="84" :shadow="false">
  98. <view class="px-46 pt-24">
  99. <ie-button @click="handleSubmit">确认提交</ie-button>
  100. </view>
  101. </ie-safe-toolbar>
  102. </ie-page>
  103. </template>
  104. <script lang="ts" setup>
  105. import ContentCard from '../../components/content-card.vue';
  106. import { useUserStore } from '@/store/userStore';
  107. import { registry, improve, improveWithToken } from '@/api/modules/login';
  108. import { useTransferPage } from '@/hooks/useTransferPage';
  109. import { useExamType } from '@/composables/useExamType';
  110. import { useAppStore } from '@/store/appStore';
  111. import { BindCardInfo, CardInfo, ClassItem, LoginInfo, RegisterInfo, SchoolItem, Scores, UserInfo } from '@/types/user';
  112. import { getClassList } from '@/api/modules/user';
  113. import { EnumBindScene, EnumExamRecordType, EnumExamType, EnumUserType } from '@/common/enum';
  114. type PrevDataInfo = {
  115. cardInfo: CardInfo;
  116. userInfo: UserInfo;
  117. registerInfo: RegisterInfo;
  118. scene: EnumBindScene;
  119. token: string; // 绑定已有账号时需要 token
  120. }
  121. const { form: examTypeForm, examTypeList, examMajorList, provinceList, endYearList } = useExamType();
  122. const userStore = useUserStore();
  123. const { prevData, transferTo, transferBack } = useTransferPage();
  124. const form = ref<Partial<BindCardInfo>>({});
  125. const scoresForm = ref<Scores>({})
  126. const formRef = ref();
  127. const customStyle = {
  128. paddingLeft: '26px'
  129. };
  130. // 普高-文化成绩必填,保存后锁定不可修改
  131. // 中职务-文化成绩不填,保存后可修改
  132. const isScoreRequired = computed(() => examTypeForm.value.examType === EnumExamType.OHS);
  133. const isBindMode = computed(() => [EnumBindScene.LOGIN_BIND, EnumBindScene.REGISTER_BIND].includes(prevData.value.scene));
  134. const isSchoolDisabled = computed(() => isBindMode.value && !!prevData.value.cardInfo.assignSchoolId);
  135. const isClassDisabled = computed(() => isBindMode.value && !!prevData.value.cardInfo.classId);
  136. const isProvinceDisabled = computed(() => isBindMode.value && !!prevData.value.cardInfo.assignLocation);
  137. const isExamTypeDisabled = computed(() => (isBindMode.value && !!prevData.value.cardInfo.assignExamType));
  138. const contactPhone = computed(() => userStore.orgInfo.contactPhone);
  139. const inputPlaceholder = computed(() => {
  140. return isBindMode.value ? '请输入(提交后不可修改)' : '请输入';
  141. });
  142. const pickerPlaceholder = computed(() => {
  143. return isBindMode.value ? '请选择(提交后不可修改)' : '请选择';
  144. });
  145. const showSchoolInfo = computed(() => {
  146. return isBindMode.value;
  147. })
  148. const classList = ref<ClassItem[]>([]);
  149. const showCulture = computed(() => {
  150. return examTypeForm.value.examType === EnumExamType.OHS;
  151. });
  152. const handleNoSchool = () => {
  153. if (!contactPhone.value) {
  154. uni.$ie.showToast('请联系客服处理');
  155. return;
  156. }
  157. uni.showActionSheet({
  158. title: '联系客服处理',
  159. itemList: [`拨打电话:${contactPhone.value}`],
  160. success: (res) => {
  161. uni.makePhoneCall({
  162. phoneNumber: contactPhone.value
  163. });
  164. }
  165. });
  166. }
  167. const handleSchoolSelect = () => {
  168. if (isSchoolDisabled.value) {
  169. return;
  170. }
  171. if (!examTypeForm.value.examType) {
  172. uni.$ie.showToast('请选择考生类别');
  173. return;
  174. }
  175. transferTo('/pagesSystem/pages/school-select/school-select', {
  176. data: {
  177. examType: examTypeForm.value.examType,
  178. }
  179. }).then(res => {
  180. if (res) {
  181. const school = res as SchoolItem;
  182. form.value.schoolId = school.id;
  183. form.value.schoolName = school.name;
  184. console.log(form.value)
  185. form.value.classId = undefined;
  186. classList.value = [];
  187. handleGetClassList();
  188. }
  189. });
  190. }
  191. const handleGetClassList = () => {
  192. if (!form.value.schoolId) {
  193. return;
  194. }
  195. getClassList({ schoolId: form.value.schoolId }).then(res => {
  196. classList.value = res.data;
  197. console.log(classList.value)
  198. });
  199. }
  200. const handlePreCheck = (type: string) => {
  201. switch (type) {
  202. case 'examType': {
  203. if (isExamTypeDisabled.value) {
  204. return true;
  205. }
  206. const { location } = examTypeForm.value;
  207. if (!location) {
  208. uni.$ie.showToast('请选择省份');
  209. return false;
  210. }
  211. return true;
  212. }
  213. case 'endYear': {
  214. const { examType } = examTypeForm.value;
  215. const result = handlePreCheck('examType');
  216. if (!result) {
  217. return false;
  218. }
  219. if (!examType) {
  220. uni.$ie.showToast('请选择考生类别');
  221. return false;
  222. }
  223. return true;
  224. }
  225. case 'classId': {
  226. const { schoolId } = form.value;
  227. if (!schoolId) {
  228. uni.$ie.showToast('请选择学校');
  229. return false;
  230. }
  231. return true;
  232. }
  233. }
  234. }
  235. const loginValidate = () => {
  236. form.value = {
  237. ...form.value,
  238. ...examTypeForm.value,
  239. }
  240. const { nickName, location, examType, endYear } = form.value;
  241. if (!nickName || nickName.trim() === '') {
  242. uni.$ie.showToast('请输入姓名');
  243. return false;
  244. }
  245. if (!location || location.trim() === '') {
  246. uni.$ie.showToast('请选择省份');
  247. return false;
  248. }
  249. if (!examType || examType.trim() === '') {
  250. uni.$ie.showToast('请选择考生类别');
  251. return false;
  252. }
  253. if (examType === 'VHS') {
  254. if (!form.value.majorType) {
  255. uni.$ie.showToast('请选择专业类别');
  256. return false;
  257. }
  258. }
  259. if (!endYear) {
  260. uni.$ie.showToast('请选择毕业年份');
  261. return false;
  262. }
  263. if (showCulture.value) {
  264. if (isScoreRequired.value) {
  265. if (!scoresForm.value.chinese) {
  266. uni.$ie.showToast('请输入语文成绩');
  267. return false;
  268. }
  269. }
  270. if (scoresForm.value?.chinese && (scoresForm.value.chinese < 0 || scoresForm.value.chinese > 100)) {
  271. uni.$ie.showToast('请输入正确的语文成绩');
  272. return false;
  273. }
  274. //
  275. if (isScoreRequired.value) {
  276. if (!scoresForm.value.mathematics) {
  277. uni.$ie.showToast('请输入数学成绩');
  278. return false;
  279. }
  280. }
  281. if (scoresForm.value?.mathematics && (scoresForm.value.mathematics < 0 || scoresForm.value.mathematics > 100)) {
  282. uni.$ie.showToast('请输入正确的数学成绩');
  283. return false;
  284. }
  285. //
  286. if (isScoreRequired.value) {
  287. if (!scoresForm.value.foreign) {
  288. uni.$ie.showToast('请输入外语成绩');
  289. return false;
  290. }
  291. }
  292. if (scoresForm.value?.foreign && (scoresForm.value.foreign < 0 || scoresForm.value.foreign > 100)) {
  293. uni.$ie.showToast('请输入正确的外语成绩');
  294. return false;
  295. }
  296. //
  297. if (isScoreRequired.value) {
  298. if (!scoresForm.value.physics) {
  299. uni.$ie.showToast('请输入物理成绩');
  300. return false;
  301. }
  302. }
  303. if (scoresForm.value?.physics && (scoresForm.value.physics < 0 || scoresForm.value.physics > 100)) {
  304. uni.$ie.showToast('请输入正确的物理成绩');
  305. return false;
  306. }
  307. //
  308. if (isScoreRequired.value) {
  309. if (!scoresForm.value.political) {
  310. uni.$ie.showToast('请输入政治成绩');
  311. return false;
  312. }
  313. }
  314. if (scoresForm.value?.political && (scoresForm.value.political < 0 || scoresForm.value.political > 100)) {
  315. uni.$ie.showToast('请输入正确的政治成绩');
  316. return false;
  317. }
  318. }
  319. if (isBindMode.value) {
  320. if (!form.value.schoolId) {
  321. uni.$ie.showToast('请选择学校');
  322. return false;
  323. }
  324. }
  325. if (isBindMode.value) {
  326. if (!form.value.classId) {
  327. uni.$ie.showToast('请选择班级');
  328. return false;
  329. }
  330. }
  331. return true;
  332. }
  333. const handleExamTypeChange = () => {
  334. scoresForm.value = {};
  335. }
  336. const handleSubmit = async () => {
  337. const valid = loginValidate();
  338. if (valid) {
  339. let params = {
  340. ...form.value,
  341. ...examTypeForm.value,
  342. scores: scoresForm.value,
  343. };
  344. // 接下来补充注册登录信息
  345. try {
  346. console.log('初步提交信息:', prevData.value.scene, params);
  347. if (prevData.value.scene === EnumBindScene.REGISTER) {
  348. startRegister(params as BindCardInfo);
  349. } else {
  350. if (prevData.value.scene === EnumBindScene.LOGIN_BIND) {
  351. startLoginBind(params as BindCardInfo);
  352. } else {
  353. startRegister(params as BindCardInfo);
  354. }
  355. }
  356. } catch (error) {
  357. console.error(error)
  358. }
  359. }
  360. }
  361. const startLoginBind = async (params: BindCardInfo) => {
  362. uni.$ie.showLoading();
  363. const token = prevData.value.token;
  364. try {
  365. await improveWithToken(params, token);
  366. uni.$ie.hideLoading();
  367. uni.$ie.showSuccess('绑定成功');
  368. const userStore = useUserStore();
  369. userStore.setToken(token);
  370. setTimeout(() => {
  371. userStore.getUserInfo();
  372. goHome();
  373. }, 50);
  374. } catch (error) {
  375. uni.$ie.hideLoading();
  376. uni.$ie.showToast('绑定失败');
  377. }
  378. }
  379. const startRegister = async (params: BindCardInfo) => {
  380. uni.$ie.showLoading();
  381. const { token } = await registry(params);
  382. if (token) {
  383. const { success } = await userStore.login(token);
  384. uni.$ie.hideLoading();
  385. uni.$ie.showSuccess('登录成功');
  386. if (success) {
  387. goHome();
  388. }
  389. }
  390. }
  391. const goHome = () => {
  392. setTimeout(() => {
  393. transferTo('/pagesMain/pages/index/index', {
  394. type: 'reLaunch'
  395. });
  396. }, 800);
  397. }
  398. const gatherInfo = () => {
  399. console.log('数据预览:', prevData.value)
  400. let { cardInfo = {} as CardInfo, userInfo = {} as UserInfo, registerInfo = {} as RegisterInfo, scene, token } = prevData.value as PrevDataInfo;
  401. form.value = {
  402. code: registerInfo.code,
  403. uuid: registerInfo.uuid,
  404. mobile: registerInfo.mobile,
  405. username: registerInfo.username,
  406. password: registerInfo.password,
  407. }
  408. // 注册时,如果以游客身份使用过,则从临时信息中获取省份和考试类型
  409. if (scene === EnumBindScene.REGISTER) {
  410. console.log('自动填写临时信息:', userStore.tempInfo)
  411. examTypeForm.value.location = userStore.tempInfo?.location;
  412. setTimeout(() => {
  413. examTypeForm.value.examType = userStore.tempInfo!.examType;
  414. }, 0);
  415. } else if ([EnumBindScene.LOGIN_BIND, EnumBindScene.REGISTER_BIND].includes(scene)) {
  416. // 已有卡信息,补充信息
  417. if (scene === EnumBindScene.LOGIN_BIND) {
  418. form.value = {
  419. ...form.value,
  420. ...userInfo,
  421. };
  422. }
  423. form.value = {
  424. ...form.value,
  425. schoolName: cardInfo.assignSchoolName,
  426. schoolId: cardInfo.assignSchoolId,
  427. classId: cardInfo.classId,
  428. };
  429. // 考生相关信息
  430. examTypeForm.value.location = cardInfo.assignLocation || userInfo.location || '';
  431. console.log(examTypeForm.value.location)
  432. setTimeout(() => {
  433. examTypeForm.value.examType = cardInfo.assignExamType || userInfo.examType || undefined;
  434. examTypeForm.value.endYear = cardInfo.endYear || userInfo.endYear;
  435. }, 0);
  436. examTypeForm.value.majorType = userInfo.majorType || '';
  437. //
  438. scoresForm.value = userInfo.scores || {};
  439. handleGetClassList();
  440. }
  441. }
  442. onLoad(() => {
  443. gatherInfo();
  444. });
  445. </script>
  446. <style lang="scss" scoped></style>