Procházet zdrojové kódy

重新梳理登录注册流程

shmily1213 před 4 týdny
rodič
revize
dd8a610dfe

+ 2 - 2
index.html

@@ -15,10 +15,10 @@
   <title></title>
   <!--preload-links-->
   <!--app-context-->
-  <!-- <script src="https://unpkg.com/vconsole@3.15.1/dist/vconsole.min.js"></script>
+  <script src="https://unpkg.com/vconsole@3.15.1/dist/vconsole.min.js"></script>
   <script>
     const vconsole = new VConsole();
-  </script> -->
+  </script>
 </head>
 
 <body>

+ 3 - 1
src/api/flyio.ts

@@ -21,7 +21,9 @@ refreshFly.config = requestConfig;
 fly.interceptors.request.use((request: any) => {
   const userStore = useUserStore();
   const token = userStore.accessToken;
-  if (token) {
+  if (request.headers['TempToken']) {
+    request.headers['Authorization'] = `Bearer ${request.headers['TempToken']}`;
+  } else if (token) {
     request.headers['Authorization'] = 'Bearer ' + token;
   }
   const examType = userStore.getExamType;

+ 28 - 2
src/api/modules/login.ts

@@ -1,4 +1,4 @@
-import { BindCardInfo, LoginInfo, MobileLoginRequestDTO, MobileLoginResponseDTO, RegisterInfo, UserInfo } from "@/types/user";
+import { BindCardInfo, LoginInfo, LoginRequestDTO, MobileLoginResponseDTO, RegisterInfo, UserInfo } from "@/types/user";
 import { ApiResponse } from "@/types";
 import flyio from "../flyio";
 
@@ -8,7 +8,7 @@ import flyio from "../flyio";
  * @param params 手机号登录参数
  * @returns 登录信息
  */
-export function mobileLogin(params: MobileLoginRequestDTO) {
+export function login(params: LoginRequestDTO) {
   return flyio.post('/front/user/userLogin', params) as Promise<ApiResponse<MobileLoginResponseDTO>>;
 }
 
@@ -30,6 +30,19 @@ export function improve(params: BindCardInfo) {
   return flyio.post('/improve', params) as Promise<ApiResponse<any>>;
 }
 
+/**
+ * 完善信息
+ * @param params 注册参数
+ * @returns 注册结果
+ */
+export function improveWithToken(params: BindCardInfo, token: string) {
+  return flyio.post('/improve', params, {
+    headers: {
+      'TempToken': `Bearer ${token}`
+    }
+  }) as Promise<ApiResponse<any>>;
+}
+
 /**
  * 获取用户信息
  * @returns 用户信息
@@ -38,6 +51,19 @@ export function getUserInfo() {
   return flyio.get('/front/user/getInfo') as Promise<ApiResponse<UserInfo>>;
 }
 
+/**
+ * 获取用户信息
+ * @returns 用户信息
+ */
+export function getUserInfoWithToken(token: string) {
+  return flyio.get('/front/user/getInfo', {}, {
+    headers: {
+      'TempToken': `Bearer ${token}`
+    }
+  }) as Promise<ApiResponse<UserInfo>>;
+}
+
+
 /**
  * 更新用户信息
  * @returns 用户信息

+ 4 - 2
src/api/modules/system.ts

@@ -34,8 +34,10 @@ export function sendSmsNoValidationNoToken(params: SmsRequestDTO) {
  * @param params 包含手机号等参数的对象
  * @returns 
  */
-export function sendSmsNoToken(params: SmsRequestDTO) {
-  return flyio.post('/front/comm/sendSmsNoToken', null, { params }) as Promise<ApiResponse<any>>;
+export function sendSmsNoToken(params: SmsRequestDTO, showToast = true) {
+  return flyio.post('/front/comm/sendSmsNoToken', null, { params }, {
+    showToast
+  }) as Promise<ApiResponse<any>>;
 }
 
 /**

+ 35 - 1
src/common/enum.ts

@@ -157,7 +157,7 @@ export enum EnumUserType {
 /**
  * 考试类型
  */
-export enum EnumExamType {
+export enum EnumExamRecordType {
   /**
    * 模拟考试
    */
@@ -166,4 +166,38 @@ export enum EnumExamType {
    * 组卷作业
    */
   HOMEWORK = 'homework'
+}
+
+
+/**
+ * 绑定场景
+ */
+export enum EnumBindScene {
+  /**
+   * 注册
+   */
+  REGISTER = 'register',
+  /**
+   * 注册绑定
+   */
+  REGISTER_BIND = 'register_bind',
+  /**
+   * 登录绑定
+   */
+  LOGIN_BIND = 'login_bind'
+}
+
+export enum EnumExamType {
+  /**
+   * 职高对口升学
+   */
+  VHS = 'VHS',
+  /**
+   * 单招(应届普高)
+   */
+  OHS = 'OHS',
+  /**
+   * 单招(中职)
+   */
+  SVS = 'SVS'
 }

+ 3 - 3
src/components/ie-page/ie-page.vue

@@ -61,10 +61,10 @@ const closeVipPopup = () => {
 }
 
 // provide 给 ie-page 内部的子组件(slot 内容)使用
-console.log('ie-page setup: providing OPEN_VIP_POPUP and CLOSE_VIP_POPUP');
+// console.log('ie-page setup: providing OPEN_VIP_POPUP and CLOSE_VIP_POPUP');
 provide(OPEN_VIP_POPUP, showVipPopup);
 provide(CLOSE_VIP_POPUP, closeVipPopup);
-console.log('ie-page setup: provided successfully');
+// console.log('ie-page setup: provided successfully');
 
 // 暴露方法给父组件通过 ref 调用
 defineExpose({
@@ -73,7 +73,7 @@ defineExpose({
 });
 
 onMounted(() => {
-  console.log('ie-page mounted, vipPopupRef.value:', vipPopupRef.value);
+  // console.log('ie-page mounted, vipPopupRef.value:', vipPopupRef.value);
   // uni.$on('showVipPopup', showVipPopup);
   // uni.$on('closeVipPopup', closeVipPopup);
 });

+ 5 - 3
src/components/ie-picker/ie-picker.vue

@@ -8,9 +8,11 @@
         </slot>
       </view>
       <view v-else class="flex-1 text-[#c0c4cc]" :style="getPlaceholderStyle">{{ placeholder }}</view>
-      <view v-if="!readonly && showArrow" class="transition-all duration-300">
-        <uv-icon :name="icon" size="15" color="#B3B3B3" />
-      </view>
+      <slot name="right">
+        <view v-if="!readonly && showArrow" class="transition-all duration-300">
+          <uv-icon :name="icon" size="15" color="#B3B3B3" />
+        </view>
+      </slot>
     </view>
   </view>
   <!-- #ifdef H5 -->

+ 1 - 1
src/hooks/useSms.ts

@@ -14,7 +14,7 @@ export const useSms = () => {
   const { setItem, getItem, removeItem } = useUniStore();
 
   // 状态常量定义
-  const SMS_COUNTDOWN_TIME = 60; // 倒计时时长(秒)
+  const SMS_COUNTDOWN_TIME = 5; // 倒计时时长(秒)
   const STORAGE_KEYS = {
     LAST_TIME: 'ie-smsLastTime',
     WAIT_TIME: 'ie-smsWaitTime'

+ 3 - 0
src/pagesMain/pages/index/index.vue

@@ -73,6 +73,9 @@ const checkTeacherInfo = async () => {
   const isTeacherInfoComplete = await userStore.checkInfoComplete();
 }
 const handleChangeLocation = () => {
+  if (userStore.isLogin) {
+    return;
+  }
   popupRef.value.open();
 }
 onHide(() => {

+ 2 - 2
src/pagesStudy/pages/study-history/components/exam-history-student.vue

@@ -7,7 +7,7 @@
 </template>
 <script lang="ts" setup>
 import { getSimulatedRecord } from '@/api/modules/study';
-import { EnumExamType } from '@/common/enum';
+import { EnumExamRecordType } from '@/common/enum';
 import examRecordItem from '@/pagesStudy/components/exam-record-item.vue';
 import { Study } from '@/types';
 const props = defineProps({
@@ -19,7 +19,7 @@ const props = defineProps({
 const dataList = ref<Study.SimulatedRecord[]>([]);
 const loadData = async (type: string) => {
   dataList.value = [];
-  if (type === EnumExamType.SIMULATED) {
+  if (type === EnumExamRecordType.SIMULATED) {
     const { data } = await getSimulatedRecord();
     // dataList.value = data;
   } else {

+ 7 - 7
src/pagesStudy/pages/study-history/components/exam-history.vue

@@ -1,13 +1,13 @@
 <template>
   <view class="flex-1 min-h-1 bg-white">
     <view class="px-30 py-20 flex gap-x-20">
-      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamType.SIMULATED }"
-        @click="handleChangeExamType(EnumExamType.SIMULATED)">
+      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamRecordType.SIMULATED }"
+        @click="handleChangeExamType(EnumExamRecordType.SIMULATED)">
         <ie-image src="/pagesStudy/static/image/icon-exam-test.png" custom-class="w-64 h-60" />
         <view class="exam-type-text">模拟仿真</view>
       </view>
-      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamType.HOMEWORK }"
-        @click="handleChangeExamType(EnumExamType.HOMEWORK)">
+      <view class="exam-type-item" :class="{ 'is-active': examType === EnumExamRecordType.HOMEWORK }"
+        @click="handleChangeExamType(EnumExamRecordType.HOMEWORK)">
         <ie-image src="/pagesStudy/static/image/icon-exam-homework.png" custom-class="w-64 h-60" />
         <view class="exam-type-text">组卷作业</view>
       </view>
@@ -17,14 +17,14 @@
   </view>
 </template>
 <script lang="ts" setup>
-import { EnumExamType } from '@/common/enum';
+import { EnumExamRecordType } from '@/common/enum';
 import examHistoryStudent from './exam-history-student.vue';
 import examHistoryTeacher from './exam-history-teacher.vue';
 import { useUserStore } from '@/store/userStore';
 const { isStudent } = storeToRefs(useUserStore());
-const examType = ref(EnumExamType.SIMULATED);
+const examType = ref(EnumExamRecordType.SIMULATED);
 
-const handleChangeExamType = (type: EnumExamType) => {
+const handleChangeExamType = (type: EnumExamRecordType) => {
   examType.value = type;
 }
 </script>

+ 345 - 0
src/pagesSystem/pages/bind-profile/bind-profile copy.vue

@@ -0,0 +1,345 @@
+<template>
+  <ie-page bg-color="#F6F8FA" :safeAreaInsetBottom="false">
+    <ie-navbar title="完善信息"></ie-navbar>
+    <uv-form labelPosition="left" :model="form" labelWidth="70px" ref="formRef">
+      <content-card title="考生信息">
+        <uv-form-item label="学生姓名" prop="name" borderBottom required>
+          <uv-input v-model="form.nickName" border="none" placeholder="请输入姓名" placeholderClass="text-30"
+            font-size="30rpx" :custom-style="customStyle">
+          </uv-input>
+        </uv-form-item>
+        <uv-form-item label="所在省份" prop="location" borderBottom required>
+          <ie-picker ref="pickerRef" v-model="examTypeForm.location" :list="provinceList" placeholder="选择省份"
+            :custom-style="customStyle" key-label="dictLabel" key-value="dictValue" :disabled="isProvinceDisabled"
+            :show-arrow="!isProvinceDisabled" @change="handleProvinceChange"></ie-picker>
+        </uv-form-item>
+        <uv-form-item label="考生类别" prop="examType" borderBottom required>
+          <ie-picker ref="pickerRef" v-model="examTypeForm.examType" :list="examTypeList" :disabled="isExamTypeDisabled"
+            placeholder="选择考生类别" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
+            :show-arrow="!isExamTypeDisabled"></ie-picker>
+        </uv-form-item>
+        <uv-form-item v-if="examTypeForm.examType === 'VHS'" label="专业类别" prop="majorType" borderBottom required>
+          <ie-picker ref="pickerRef" v-model="examTypeForm.majorType" :list="examMajorList"
+            :disabled="!examTypeForm.examType" placeholder="选择专业类别" :custom-style="customStyle" key-label="dictLabel"
+            key-value="dictValue"></ie-picker>
+        </uv-form-item>
+        <uv-form-item label="毕业年份" prop="year" required>
+          <ie-picker ref="pickerRef" v-model="examTypeForm.endYear" :list="endYearList"
+            :disabled="!examTypeForm.examType" placeholder="选择毕业年份" :custom-style="customStyle" key-label="dictLabel"
+            key-value="dictValue"></ie-picker>
+        </uv-form-item>
+
+      </content-card>
+      <content-card title="邀请信息">
+        <uv-form-item label="邀请码" prop="form.inviteCode">
+          <uv-input v-model="form.inviteCode" border="none" placeholder="请输入邀请码(非必填)" font-size="30rpx"
+            :custom-style="customStyle">
+          </uv-input>
+        </uv-form-item>
+      </content-card>
+      <content-card v-if="showCulture" title="文化素质">
+        <uv-form-item label="语文" prop="form.scores.chinese" borderBottom :required="isImproveMode">
+          <uv-input v-model="scoresForm.chinese" border="none" type="number" placeholder="请输入" font-size="30rpx"
+            :custom-style="customStyle">
+          </uv-input>
+        </uv-form-item>
+        <uv-form-item label="数学" prop="form.score.mathematics" borderBottom :required="isImproveMode">
+          <uv-input v-model="scoresForm.mathematics" border="none" type="number" placeholder="请输入" font-size="30rpx"
+            :custom-style="customStyle">
+          </uv-input>
+        </uv-form-item>
+        <uv-form-item label="外语" prop="form.scores.foreign" borderBottom :required="isImproveMode">
+          <uv-input v-model="scoresForm.foreign" border="none" type="number" placeholder="请输入" font-size="30rpx"
+            :custom-style="customStyle">
+          </uv-input>
+        </uv-form-item>
+        <uv-form-item label="物理" prop="form.scores.physics" borderBottom :required="isImproveMode">
+          <uv-input v-model="scoresForm.physics" border="none" type="number" placeholder="请输入" font-size="30rpx"
+            :custom-style="customStyle">
+          </uv-input>
+        </uv-form-item>
+        <uv-form-item label="政治" prop="form.scores.political" :required="isImproveMode">
+          <uv-input v-model="scoresForm.political" border="none" type="number" placeholder="请输入" font-size="30rpx"
+            :custom-style="customStyle">
+          </uv-input>
+        </uv-form-item>
+      </content-card>
+      <content-card v-if="isImproveMode" title="学校信息">
+        <uv-form-item label="学校名称" prop="form.name" borderBottom :required="isImproveMode">
+          <ie-picker ref="pickerRef" v-model="form.schoolName" disabled placeholder="请选择就读学校"
+            :custom-style="customStyle" :custom-label="form.schoolName" @click="handleSchoolSelect"
+            :show-arrow="!isSchoolDisabled"></ie-picker>
+        </uv-form-item>
+        <uv-form-item label="所在班级" prop="form.name" :required="isImproveMode">
+          <ie-picker ref="pickerRef" v-model="form.classId" :list="classList" :disabled="!form.schoolId" title="选择班级"
+            placeholder="请选择所在班级" :custom-style="customStyle" key-label="name" key-value="classId"></ie-picker>
+        </uv-form-item>
+      </content-card>
+    </uv-form>
+    <ie-safe-toolbar :height="84" :shadow="false">
+      <view class="px-30 py-16">
+        <ie-button @click="handleSubmit">确认提交</ie-button>
+      </view>
+    </ie-safe-toolbar>
+  </ie-page>
+</template>
+
+<script lang="ts" setup>
+import ContentCard from '../../components/content-card.vue';
+import { useUserStore } from '@/store/userStore';
+import { registry, improve } from '@/api/modules/login';
+import { useTransferPage } from '@/hooks/useTransferPage';
+import { useExamType } from '@/composables/useExamType';
+import { useAppStore } from '@/store/appStore';
+import { BindCardInfo, ClassItem, SchoolItem, Scores } from '@/types/user';
+
+import { getClassList } from '@/api/modules/user';
+const { form: examTypeForm, examTypeList, examMajorList, provinceList, endYearList } = useExamType();
+const userStore = useUserStore();
+const appStore = useAppStore();
+const { prevData, transferTo, transferBack } = useTransferPage();
+
+const form = ref<Partial<BindCardInfo>>({});
+const scoresForm = ref<Scores>({})
+const formRef = ref();
+const customStyle = {
+  paddingLeft: '26px'
+};
+
+const isImproveMode = computed(() => prevData.value.scene === 'phone_improve' || prevData.value.scene === 'card_improve');
+const isSchoolDisabled = computed(() => prevData.value.scene === 'card_improve' && prevData.value.card.assignSchoolId);
+const isProvinceDisabled = computed(() => prevData.value.scene === 'card_improve' && prevData.value.card.assignLocation);
+const isExamTypeDisabled = computed(() => (prevData.value.scene === 'card_improve' && prevData.value.card.assignExamType) || !examTypeForm.value.location);
+const handleProvinceChange = (val: string) => {
+  if (isProvinceDisabled.value) {
+    return;
+  }
+  form.value.examType = '';
+  form.value.majorType = '';
+}
+
+const classList = ref<ClassItem[]>([]);
+const showCulture = computed(() => {
+  return examTypeForm.value.examType === 'OHS';
+});
+const handleSchoolSelect = () => {
+  if (isSchoolDisabled.value) {
+    return;
+  }
+  transferTo('/pagesSystem/pages/school-select/school-select', {
+    data: form.value
+  }).then(res => {
+    const school = res as SchoolItem;
+    form.value.schoolId = school.id;
+    form.value.schoolName = school.name;
+    console.log(form.value)
+    form.value.classId = undefined;
+    classList.value = [];
+    handleGetClassList();
+  });
+}
+const handleGetClassList = () => {
+  if (!form.value.schoolId) {
+    return;
+  }
+  getClassList({ schoolId: form.value.schoolId }).then(res => {
+    classList.value = res.data;
+    console.log(classList.value)
+  });
+}
+
+
+const loginValidate = () => {
+  form.value = {
+    ...form.value,
+    ...examTypeForm.value,
+  }
+  const { nickName, location, examType, endYear } = form.value;
+  if (!nickName || nickName.trim() === '') {
+    uni.$ie.showToast('请输入姓名');
+    return false;
+  }
+  if (!location || location.trim() === '') {
+    uni.$ie.showToast('请选择省份');
+    return false;
+  }
+  if (!examType || examType.trim() === '') {
+    uni.$ie.showToast('请选择考生类别');
+    return false;
+  }
+  if (examType === 'VHS') {
+    if (!form.value.majorType) {
+      uni.$ie.showToast('请选择专业类别');
+      return false;
+    }
+  }
+  if (!endYear) {
+    uni.$ie.showToast('请选择毕业年份');
+    return false;
+  }
+  if (showCulture.value) {
+    if (isImproveMode.value) {
+      if (!scoresForm.value.chinese || scoresForm.value.chinese < 0 || scoresForm.value.chinese > 100) {
+        uni.$ie.showToast('请输入正确的语文成绩');
+        return false;
+      }
+    }
+    if (isImproveMode.value) {
+      if (!scoresForm.value.mathematics || scoresForm.value.mathematics < 0 || scoresForm.value.mathematics > 100) {
+        uni.$ie.showToast('请输入正确的数学成绩');
+        return false;
+      }
+    }
+    if (isImproveMode.value) {
+      if (!scoresForm.value.foreign || scoresForm.value.foreign < 0 || scoresForm.value.foreign > 100) {
+        uni.$ie.showToast('请输入正确的外语成绩');
+        return false;
+      }
+    }
+    if (isImproveMode.value) {
+      if (!scoresForm.value.physics || scoresForm.value.physics < 0 || scoresForm.value.physics > 100) {
+        uni.$ie.showToast('请输入正确的物理成绩');
+        return false;
+      }
+    }
+    if (isImproveMode.value) {
+      if (!scoresForm.value.political || scoresForm.value.political < 0 || scoresForm.value.political > 100) {
+        uni.$ie.showToast('请输入正确的政治成绩');
+        return false;
+      }
+    }
+  }
+  if (isImproveMode.value) {
+    if (!form.value.schoolId) {
+      uni.$ie.showToast('请选择学校');
+      return false;
+    }
+  }
+  if (isImproveMode.value) {
+    if (!form.value.classId) {
+      uni.$ie.showToast('请选择班级');
+      return false;
+    }
+  }
+  return true;
+}
+const handleSubmit = async () => {
+  const valid = loginValidate();
+  if (valid) {
+    let params = {
+      ...form.value,
+      scores: scoresForm.value,
+    };
+    try {
+      if (isImproveMode.value) {
+        const { cardNo, password } = prevData.value;
+        params = {
+          ...params,
+          username: cardNo,
+          password,
+        }
+        console.log('params', params)
+        if (prevData.value.scene === 'card_improve') {
+          startLogin(params as BindCardInfo);
+        } else {
+          startBind(params as BindCardInfo)
+        }
+      } else {
+        const { mobile, password, code, uuid } = prevData.value;
+        params = {
+          ...params,
+          mobile,
+          password,
+          code,
+          uuid,
+        }
+        startLogin(params as BindCardInfo);
+      }
+    } catch (error) {
+      console.error(error)
+    }
+  }
+}
+
+const startBind = async (params: BindCardInfo) => {
+  uni.$ie.showLoading();
+  await improve(params);
+  uni.$ie.hideLoading();
+  uni.$ie.showSuccess('绑定成功');
+  userStore.getUserInfo();
+  goHome();
+}
+
+const startLogin = async (params: BindCardInfo) => {
+  uni.$ie.showLoading();
+  const { token } = await registry(params);
+  if (token) {
+    const isLogin = await userStore.login(token);
+    uni.$ie.hideLoading();
+    uni.$ie.showSuccess('登录成功');
+    if (isLogin) {
+      goHome();
+    }
+  }
+}
+
+const goHome = () => {
+  setTimeout(() => {
+    transferTo('/pagesMain/pages/index/index', {
+      type: 'reLaunch'
+    });
+  }, 600);
+}
+
+const gatherInfo = () => {
+  // const { scene, card, phone, code, uuid } = prevData.value;
+  const { cardInfo, userInfo, loginInfo } = prevData.value;
+  console.log('prevData.value', prevData.value)
+  if (userStore.tempInfo?.location) {
+    examTypeForm.value.location = userStore.tempInfo?.location;
+    setTimeout(() => {
+      examTypeForm.value.examType = userStore.tempInfo!.examType;
+    }, 0)
+  }
+  console.log('examTypeForm', examTypeForm)
+  const { scene, phone } = loginInfo;
+  const { nickName, location, examType, majorType: userMajorType, endYear: userEndYear, scores } = userInfo;
+  const { assignLocation, assignExamType, majorType, endYear: cardEndYear, assignSchoolId, assignSchoolName, classId, } = cardInfo;
+  if (scene === 'card_improve') {
+    // 未登录用户卡注册登录
+    form.value = {
+      nickName,
+      scores,
+      // 下面 3 个属性卡的优先级更高
+      location: assignLocation || location,
+      examType: assignExamType || examType,
+      endYear: cardEndYear || userEndYear,
+      majorType: majorType || userMajorType,
+      schoolId: assignSchoolId,
+      schoolName: assignSchoolName,
+      classId: classId,
+      mobile: phone
+      // code
+    };
+    handleGetClassList();
+  } else if (scene === 'phone_improve') {
+    // 已登录用户绑卡
+    // const { nickName, location, examType, endYear, scores } = userStore.userInfo;
+    // const { nickName, location, examType, endYear, scores } = prevData.value.userInfo;
+    form.value = {
+      nickName,
+      location,
+      examType,
+      // endYear,
+      scores
+    };
+    scoresForm.value = scores;
+  }
+}
+
+onLoad(() => {
+  gatherInfo();
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 189 - 96
src/pagesSystem/pages/bind-profile/bind-profile.vue

@@ -10,13 +10,19 @@
         </uv-form-item>
         <uv-form-item label="所在省份" prop="location" borderBottom required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.location" :list="provinceList" placeholder="选择省份"
-            :custom-style="customStyle" key-label="dictLabel" key-value="dictValue" :disabled="isProvinceDisabled"
-            :show-arrow="!isProvinceDisabled" @change="handleProvinceChange"></ie-picker>
+            :custom-style="customStyle" key-label="dictLabel" key-value="dictValue" :disabled="isProvinceDisabled">
+            <template v-if="isProvinceDisabled" #right>
+              <ie-image src="/pagesSystem/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+            </template>
+          </ie-picker>
         </uv-form-item>
         <uv-form-item label="考生类别" prop="examType" borderBottom required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.examType" :list="examTypeList" :disabled="isExamTypeDisabled"
-            placeholder="选择考生类别" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
-            :show-arrow="!isExamTypeDisabled"></ie-picker>
+            placeholder="选择考生类别" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue">
+            <template v-if="isExamTypeDisabled" #right>
+              <ie-image src="/pagesSystem/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+            </template>
+          </ie-picker>
         </uv-form-item>
         <uv-form-item v-if="examTypeForm.examType === 'VHS'" label="专业类别" prop="majorType" borderBottom required>
           <ie-picker ref="pickerRef" v-model="examTypeForm.majorType" :list="examMajorList"
@@ -38,39 +44,42 @@
         </uv-form-item>
       </content-card>
       <content-card v-if="showCulture" title="文化素质">
-        <uv-form-item label="语文" prop="form.scores.chinese" borderBottom :required="isImproveMode">
-          <uv-input v-model="scoresForm.chinese" border="none" type="number" placeholder="请输入" font-size="30rpx"
+        <uv-form-item label="语文" prop="form.scores.chinese" borderBottom :required="isBindMode">
+          <uv-input v-model.number="scoresForm.chinese" border="none" type="number" placeholder="请输入" font-size="30rpx"
             :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
-        <uv-form-item label="数学" prop="form.score.mathematics" borderBottom :required="isImproveMode">
-          <uv-input v-model="scoresForm.mathematics" border="none" type="number" placeholder="请输入" font-size="30rpx"
-            :custom-style="customStyle">
+        <uv-form-item label="数学" prop="form.score.mathematics" borderBottom :required="isBindMode">
+          <uv-input v-model.number="scoresForm.mathematics" border="none" type="number" placeholder="请输入"
+            font-size="30rpx" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
-        <uv-form-item label="外语" prop="form.scores.foreign" borderBottom :required="isImproveMode">
-          <uv-input v-model="scoresForm.foreign" border="none" type="number" placeholder="请输入" font-size="30rpx"
+        <uv-form-item label="外语" prop="form.scores.foreign" borderBottom :required="isBindMode">
+          <uv-input v-model.number="scoresForm.foreign" border="none" type="number" placeholder="请输入" font-size="30rpx"
             :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
-        <uv-form-item label="物理" prop="form.scores.physics" borderBottom :required="isImproveMode">
-          <uv-input v-model="scoresForm.physics" border="none" type="number" placeholder="请输入" font-size="30rpx"
+        <uv-form-item label="物理" prop="form.scores.physics" borderBottom :required="isBindMode">
+          <uv-input v-model.number="scoresForm.physics" border="none" type="number" placeholder="请输入" font-size="30rpx"
             :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
-        <uv-form-item label="政治" prop="form.scores.political" :required="isImproveMode">
-          <uv-input v-model="scoresForm.political" border="none" type="number" placeholder="请输入" font-size="30rpx"
-            :custom-style="customStyle">
+        <uv-form-item label="政治" prop="form.scores.political" :required="isBindMode">
+          <uv-input v-model.number="scoresForm.political" border="none" type="number" placeholder="请输入"
+            font-size="30rpx" :custom-style="customStyle">
           </uv-input>
         </uv-form-item>
       </content-card>
-      <content-card v-if="isImproveMode" title="学校信息">
-        <uv-form-item label="学校名称" prop="form.name" borderBottom :required="isImproveMode">
+      <content-card v-if="isBindMode" title="学校信息">
+        <uv-form-item label="学校名称" prop="form.name" borderBottom :required="isBindMode">
           <ie-picker ref="pickerRef" v-model="form.schoolName" disabled placeholder="请选择就读学校"
-            :custom-style="customStyle" :custom-label="form.schoolName" @click="handleSchoolSelect"
-            :show-arrow="!isSchoolDisabled"></ie-picker>
+            :custom-style="customStyle" :custom-label="form.schoolName" @click="handleSchoolSelect">
+            <template v-if="isSchoolDisabled" #right>
+              <ie-image src="/pagesSystem/static/image/icon/icon-lock.png" custom-class="w-24 h-30" mode="aspectFill" />
+            </template>
+          </ie-picker>
         </uv-form-item>
-        <uv-form-item label="所在班级" prop="form.name" :required="isImproveMode">
+        <uv-form-item label="所在班级" prop="form.name" :required="isBindMode">
           <ie-picker ref="pickerRef" v-model="form.classId" :list="classList" :disabled="!form.schoolId" title="选择班级"
             placeholder="请选择所在班级" :custom-style="customStyle" key-label="name" key-value="classId"></ie-picker>
         </uv-form-item>
@@ -87,16 +96,24 @@
 <script lang="ts" setup>
 import ContentCard from '../../components/content-card.vue';
 import { useUserStore } from '@/store/userStore';
-import { registry, improve } from '@/api/modules/login';
+import { registry, improve, improveWithToken } from '@/api/modules/login';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { useExamType } from '@/composables/useExamType';
 import { useAppStore } from '@/store/appStore';
-import { BindCardInfo, ClassItem, SchoolItem, Scores } from '@/types/user';
+import { BindCardInfo, CardInfo, ClassItem, LoginInfo, RegisterInfo, SchoolItem, Scores, UserInfo } from '@/types/user';
 
 import { getClassList } from '@/api/modules/user';
+import { EnumBindScene, EnumExamRecordType, EnumExamType } from '@/common/enum';
+type PrevDataInfo = {
+  cardInfo: CardInfo;
+  userInfo: UserInfo;
+  registerInfo: RegisterInfo;
+  scene: EnumBindScene;
+  token: string; // 绑定已有账号时需要 token
+}
+
 const { form: examTypeForm, examTypeList, examMajorList, provinceList, endYearList } = useExamType();
 const userStore = useUserStore();
-const appStore = useAppStore();
 const { prevData, transferTo, transferBack } = useTransferPage();
 
 const form = ref<Partial<BindCardInfo>>({});
@@ -106,21 +123,15 @@ const customStyle = {
   paddingLeft: '26px'
 };
 
-const isImproveMode = computed(() => prevData.value.scene === 'phone_improve' || prevData.value.scene === 'card_improve');
-const isSchoolDisabled = computed(() => prevData.value.scene === 'card_improve' && prevData.value.card.assignSchoolId);
-const isProvinceDisabled = computed(() => prevData.value.scene === 'card_improve' && prevData.value.card.assignLocation);
-const isExamTypeDisabled = computed(() => (prevData.value.scene === 'card_improve' && prevData.value.card.assignExamType) || !examTypeForm.value.location);
-const handleProvinceChange = (val: string) => {
-  if (isProvinceDisabled.value) {
-    return;
-  }
-  form.value.examType = '';
-  form.value.majorType = '';
-}
+const isBindMode = computed(() => [EnumBindScene.LOGIN_BIND, EnumBindScene.REGISTER_BIND].includes(prevData.value.scene));
+const isSchoolDisabled = computed(() => isBindMode.value && prevData.value.cardInfo.assignSchoolId);
+const isProvinceDisabled = computed(() => isBindMode.value && prevData.value.cardInfo.assignLocation);
+const isExamTypeDisabled = computed(() => (isBindMode.value && prevData.value.cardInfo.assignExamType) || !examTypeForm.value.location);
+
 
 const classList = ref<ClassItem[]>([]);
 const showCulture = computed(() => {
-  return examTypeForm.value.examType === 'OHS';
+  return examTypeForm.value.examType === EnumExamType.OHS;
 });
 const handleSchoolSelect = () => {
   if (isSchoolDisabled.value) {
@@ -178,44 +189,44 @@ const loginValidate = () => {
     return false;
   }
   if (showCulture.value) {
-    if (isImproveMode.value) {
+    if (isBindMode.value) {
       if (!scoresForm.value.chinese || scoresForm.value.chinese < 0 || scoresForm.value.chinese > 100) {
         uni.$ie.showToast('请输入正确的语文成绩');
         return false;
       }
     }
-    if (isImproveMode.value) {
+    if (isBindMode.value) {
       if (!scoresForm.value.mathematics || scoresForm.value.mathematics < 0 || scoresForm.value.mathematics > 100) {
         uni.$ie.showToast('请输入正确的数学成绩');
         return false;
       }
     }
-    if (isImproveMode.value) {
+    if (isBindMode.value) {
       if (!scoresForm.value.foreign || scoresForm.value.foreign < 0 || scoresForm.value.foreign > 100) {
         uni.$ie.showToast('请输入正确的外语成绩');
         return false;
       }
     }
-    if (isImproveMode.value) {
+    if (isBindMode.value) {
       if (!scoresForm.value.physics || scoresForm.value.physics < 0 || scoresForm.value.physics > 100) {
         uni.$ie.showToast('请输入正确的物理成绩');
         return false;
       }
     }
-    if (isImproveMode.value) {
+    if (isBindMode.value) {
       if (!scoresForm.value.political || scoresForm.value.political < 0 || scoresForm.value.political > 100) {
         uni.$ie.showToast('请输入正确的政治成绩');
         return false;
       }
     }
   }
-  if (isImproveMode.value) {
+  if (isBindMode.value) {
     if (!form.value.schoolId) {
       uni.$ie.showToast('请选择学校');
       return false;
     }
   }
-  if (isImproveMode.value) {
+  if (isBindMode.value) {
     if (!form.value.classId) {
       uni.$ie.showToast('请选择班级');
       return false;
@@ -228,49 +239,82 @@ const handleSubmit = async () => {
   if (valid) {
     let params = {
       ...form.value,
+      ...examTypeForm.value,
       scores: scoresForm.value,
     };
+
+    // 接下来补充注册登录信息
     try {
-      if (isImproveMode.value) {
-        const { cardNo, password } = prevData.value;
-        params = {
-          ...params,
-          username: cardNo,
-          password,
-        }
-        console.log('params', params)
-        if (prevData.value.scene === 'card_improve') {
-          startLogin(params as BindCardInfo);
-        } else {
-          startBind(params as BindCardInfo)
-        }
+      if (prevData.value.scene === EnumBindScene.REGISTER) {
+        startRegister(params as BindCardInfo);
       } else {
-        const { mobile, password, code, uuid } = prevData.value;
-        params = {
-          ...params,
-          mobile,
-          password,
-          code,
-          uuid,
+        // startRegisterBind(params as BindCardInfo);
+        // params = {
+        //   ...params,
+        //   username: prevData.value.registerInfo.username,
+        //   password: prevData.value.registerInfo.password,
+        // };
+        console.log('初步提交信息:', params);
+        if (prevData.value.scene === EnumBindScene.LOGIN_BIND) {
+          startLoginBind(params as BindCardInfo);
+        } else {
+          startRegister(params as BindCardInfo);
         }
-        startLogin(params as BindCardInfo);
       }
+      // if (isBindMode.value) {
+      //   const { cardNo, password } = prevData.value;
+      //   params = {
+      //     ...params,
+      //     username: cardNo,
+      //     password,
+      //   }
+      //   console.log('params', params)
+      //   if (prevData.value.scene === 'card_improve') {
+      //     startRegister(params as BindCardInfo);
+      //   } else {
+      //     startRegisterBind(params as BindCardInfo)
+      //   }
+      // } else {
+      //   const { mobile, password, code, uuid } = prevData.value;
+      //   params = {
+      //     ...params,
+      //     mobile,
+      //     password,
+      //     code,
+      //     uuid,
+      //   }
+      //   startRegister(params as BindCardInfo);
+      // }
     } catch (error) {
       console.error(error)
     }
   }
 }
 
-const startBind = async (params: BindCardInfo) => {
+const startLoginBind = async (params: BindCardInfo) => {
   uni.$ie.showLoading();
-  await improve(params);
+  const token = prevData.value.token;
+  await improveWithToken(params, token);
   uni.$ie.hideLoading();
   uni.$ie.showSuccess('绑定成功');
-  userStore.getUserInfo();
-  goHome();
+  const userStore = useUserStore();
+  userStore.setToken(token);
+  setTimeout(() => {
+    userStore.getUserInfo();
+    goHome();
+  }, 50);
 }
 
-const startLogin = async (params: BindCardInfo) => {
+// const startRegisterBind = async (params: BindCardInfo) => {
+//   uni.$ie.showLoading();
+//   await improve(params);
+//   uni.$ie.hideLoading();
+//   uni.$ie.showSuccess('绑定成功');
+//   userStore.getUserInfo();
+//   goHome();
+// }
+
+const startRegister = async (params: BindCardInfo) => {
   uni.$ie.showLoading();
   const { token } = await registry(params);
   if (token) {
@@ -288,43 +332,92 @@ const goHome = () => {
     transferTo('/pagesMain/pages/index/index', {
       type: 'reLaunch'
     });
-  }, 600);
+  }, 800);
 }
 
 const gatherInfo = () => {
-  const { scene, card, phone, code, uuid } = prevData.value;
-  console.log('prevData.value', prevData.value)
-  if (userStore.tempInfo?.location) {
+  console.log('数据预览:', prevData.value)
+  // const { scene, card, phone, code, uuid } = prevData.value;
+  let { cardInfo = {} as CardInfo, userInfo = {} as UserInfo, registerInfo = {} as RegisterInfo, scene, token } = prevData.value as PrevDataInfo;
+  form.value = {
+    code: registerInfo.code,
+    uuid: registerInfo.uuid,
+    mobile: registerInfo.mobile,
+    username: registerInfo.username,
+    password: registerInfo.password,
+  }
+  // 注册时,如果以游客身份使用过,则从临时信息中获取省份和考试类型
+  if (scene === EnumBindScene.REGISTER) {
+    console.log('自动填写临时信息:', userStore.tempInfo)
     examTypeForm.value.location = userStore.tempInfo?.location;
     setTimeout(() => {
       examTypeForm.value.examType = userStore.tempInfo!.examType;
-    }, 0)
-  }
-  console.log('examTypeForm', examTypeForm)
-  if (scene === 'card_improve') {
+    }, 0);
+  } else if ([EnumBindScene.LOGIN_BIND, EnumBindScene.REGISTER_BIND].includes(scene)) {
+    // 已有卡信息,补充信息
+    if (scene === EnumBindScene.LOGIN_BIND) {
+      form.value = {
+        ...form.value,
+        ...userInfo,
+      };
+    }
     form.value = {
-      location: card.assignLocation,
-      examType: card.assignExamType,
-      endYear: card.endYear,
-      majorType: card.majorType,
-      schoolId: card.assignSchoolId,
-      schoolName: card.assignSchoolName,
-      classId: card.classId,
-      mobile: phone
-      // code
+      ...form.value,
+      schoolName: cardInfo.assignSchoolName,
+      schoolId: cardInfo.assignSchoolId,
+      classId: cardInfo.classId,
+      //
+      // code: registerInfo.code,
+      // uuid: registerInfo.uuid,
+      // mobile: registerInfo.mobile,
+      // username: registerInfo.username,
+      // password: registerInfo.password,
     };
+    // 考生相关信息
+    examTypeForm.value.location = cardInfo.assignLocation || userInfo.location || '';
+    setTimeout(() => {
+      examTypeForm.value.examType = cardInfo.assignExamType || userInfo.examType || '';
+      examTypeForm.value.endYear = cardInfo.endYear || userInfo.endYear;
+    }, 0);
+    examTypeForm.value.majorType = userInfo.majorType || '';
+    // 
+    scoresForm.value = userInfo.scores || {};
     handleGetClassList();
-  } else if (scene === 'phone_improve') {
-    const { nickName, location, examType, endYear, scores } = userStore.userInfo;
-    form.value = {
-      nickName,
-      location,
-      examType,
-      endYear,
-      scores
-    };
-    scoresForm.value = scores;
   }
+  console.log('初始化整理的信息:')
+  console.log('form.value:', form.value)
+  console.log('examTypeForm.value:', examTypeForm.value)
+  console.log('scoresForm.value:', scoresForm.value)
+  // if (scene === EnumBindScene.LOGIN_BIND) {
+  // 未登录用户卡注册登录
+  // form.value = {
+  // nickName,
+  // scores,
+  // 下面 3 个属性卡的优先级更高
+  // location: assignLocation || location,
+  // examType: assignExamType || examType,
+  // endYear: cardEndYear || userEndYear,
+  // majorType: majorType || userMajorType,
+  // schoolId: assignSchoolId,
+  // schoolName: assignSchoolName,
+  // classId: classId,
+  // mobile: phone
+  // code
+  // };
+  // handleGetClassList();
+  // } else if (scene === 'phone_improve') {
+  // 已登录用户绑卡
+  // const { nickName, location, examType, endYear, scores } = userStore.userInfo;
+  // const { nickName, location, examType, endYear, scores } = prevData.value.userInfo;
+  // form.value = {
+  //   nickName,
+  //   location,
+  //   examType,
+  //   // endYear,
+  //   scores
+  // };
+  // scoresForm.value = scores;
+  // }
 }
 
 onLoad(() => {

+ 0 - 262
src/pagesSystem/pages/bind-profile/user-profile copy.vue

@@ -1,262 +0,0 @@
-<template>
-  <ie-page bg-color="#F6F8FA" :safeAreaInsetBottom="false">
-    <ie-navbar title="完善信息"></ie-navbar>
-    <uv-form labelPosition="left" :model="form" labelWidth="70px" ref="formRef">
-      <content-card title="考生信息">
-        <uv-form-item label="学生姓名" prop="name" borderBottom required>
-          <uv-input v-model="form.nickName" border="none" placeholder="请输入姓名" placeholderClass="text-30"
-            font-size="30rpx" :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-        <uv-form-item label="所在省份" prop="location" borderBottom required>
-          <ie-picker ref="pickerRef" v-model="form.location" :list="appStore.provinceList" placeholder="选择省份"
-            :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
-            @change="handleProvinceChange"></ie-picker>
-        </uv-form-item>
-        <uv-form-item label="考生类别" prop="examType" borderBottom required>
-          <ie-picker ref="pickerRef" v-model="form.examType" :list="examTypeList" :disabled="!form.location"
-            placeholder="选择考生类别" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
-            @change="handleExamTypeChange"></ie-picker>
-        </uv-form-item>
-        <uv-form-item v-if="form.examType === 'VHS'" label="专业类别" prop="majorType" borderBottom required>
-          <ie-picker ref="pickerRef" v-model="form.majorType" :list="majorTypes" :disabled="!form.examType"
-            placeholder="选择专业类别" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"
-            @change="handleMajorChange"></ie-picker>
-        </uv-form-item>
-        <uv-form-item label="毕业年份" prop="year" required>
-          <ie-picker ref="pickerRef" v-model="form.endYear" :list="endYearList" :disabled="!form.examType"
-            placeholder="选择毕业年份" :custom-style="customStyle" key-label="dictLabel" key-value="dictValue"></ie-picker>
-        </uv-form-item>
-
-      </content-card>
-      <content-card title="邀请信息">
-        <uv-form-item label="邀请码" prop="form.inviteCode">
-          <uv-input v-model="form.inviteCode" border="none" placeholder="请输入邀请码(非必填)" font-size="30rpx"
-            :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-      </content-card>
-      <content-card title="文化素质">
-        <uv-form-item label="语文" prop="form.scores.chinese" borderBottom>
-          <uv-input v-model="scores.chinese" border="none" placeholder="满分100分" font-size="30rpx"
-            :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-        <uv-form-item label="数学" prop="form.score.mathematics" borderBottom>
-          <uv-input v-model="scores.mathematics" border="none" placeholder="满分100分" font-size="30rpx"
-            :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-        <uv-form-item label="外语" prop="form.scores.foreign" borderBottom>
-          <uv-input v-model="scores.foreign" border="none" placeholder="满分100分" font-size="30rpx"
-            :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-        <uv-form-item label="物理" prop="form.scores.physics" borderBottom>
-          <uv-input v-model="scores.physics" border="none" placeholder="满分100分" font-size="30rpx"
-            :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-        <uv-form-item label="政治" prop="form.scores.political">
-          <uv-input v-model="scores.political" border="none" placeholder="满分100分" font-size="30rpx"
-            :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-      </content-card>
-      <!-- <content-card title="学校信息">
-        <uv-form-item label="学校名称" prop="form.name">
-          <uv-input v-model="form.name" border="none" placeholder="请输入学校名称" :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-        <uv-form-item label="所在班级" prop="form.name">
-          <uv-input v-model="form.name" border="none" placeholder="请输入所在班级" :custom-style="customStyle">
-          </uv-input>
-        </uv-form-item>
-      </content-card> -->
-    </uv-form>
-    <ie-safe-toolbar :height="84" :shadow="false">
-      <view class="px-30 py-16">
-        <ie-button @click="handleSubmit">确认提交</ie-button>
-      </view>
-    </ie-safe-toolbar>
-  </ie-page>
-</template>
-
-<script lang="ts" setup>
-import ContentCard from '../../components/content-card.vue';
-import { useUserStore } from '@/store/userStore';
-import { } from '@/api/modules/login';
-import { getExamTypes, getExamMajors, getGraduateYears } from '@/api/modules/system';
-import { registry } from '@/api/modules/login';
-import { useTransferPage } from '@/hooks/useTransferPage';
-
-import { useAppStore } from '@/store/appStore';
-import { useDictStore } from '@/store/dictStore';
-import config from "@/config";
-import { RegisterInfo, Scores } from '@/types/user';
-import { DictItem } from '@/types';
-const userStore = useUserStore();
-const appStore = useAppStore();
-const { prevData, transferTo } = useTransferPage();
-
-const form = ref<Partial<RegisterInfo>>({});
-const scores = ref<Scores>({})
-const formRef = ref();
-const rules = ref({
-  name: [{ type: 'string', required: true, message: '请输入姓名', trigger: ['blur', 'change'] }],
-  location: [{ type: 'string', required: true, message: '请选择省份', trigger: ['blur', 'change'] }],
-  examType: [{ type: 'string', required: true, message: '请选择考生类别', trigger: ['blur', 'change'] }],
-  majorType: [{ type: 'string', required: true, message: '请选择专业类别', trigger: ['blur', 'change'] }],
-  endYear: [{ type: 'string', required: true, message: '请选择毕业年份', trigger: ['blur', 'change'] }],
-});
-const customStyle = {
-  paddingLeft: '26px'
-};
-const examTypeList = ref<DictItem[]>([]);
-const endYearList = ref<DictItem[]>([]);
-const majorTypes = ref<DictItem[]>([]);
-
-const handleProvinceChange = (val: string) => {
-  form.value.examType = '';
-  form.value.majorType = '';
-  loadExamTypes();
-}
-
-const handleExamTypeChange = (val: string) => {
-  form.value.majorType = '';
-  loadMajorTypes();
-  loadGraduateYears();
-}
-
-const handleShowExamTypePicker = () => {
-  if (!form.value.location) {
-    uni.$ie.showToast('请先选择省份');
-    return;
-  }
-}
-
-const loadExamTypes = async () => {
-  if (!form.value.location) {
-    return;
-  }
-  getExamTypes(form.value.location).then(res => {
-    examTypeList.value = res.data;
-    // if (examTypeList.value.length > 0) {
-    //   // 只有一个考生类别,自动选择
-    //   form.value.examType = examTypeList.value[0].dictValue as string;
-    // }
-  }).catch(err => {
-    console.log('获取考生类别失败', err)
-  });
-};
-
-const loadMajorTypes = async () => {
-  if (!form.value.location || !form.value.examType) {
-    return;
-  }
-  getExamMajors(form.value.location, form.value.examType).then(res => {
-    majorTypes.value = res.data;
-  }).catch(err => {
-    console.log('获取专业类别失败', err)
-  });
-}
-
-const loadGraduateYears = async () => {
-  if (!form.value.location || !form.value.examType) {
-    return;
-  }
-  getGraduateYears(form.value.location, form.value.examType).then(res => {
-    endYearList.value = res.data;
-    if (endYearList.value.length > 0) {
-      // 只有一个毕业年份,自动选择
-      // form.value.endYear = endYearList.value[0].dictValue as string;
-    }
-  }).catch(err => {
-    console.log('获取毕业年份失败', err)
-  });
-}
-
-const handleMajorChange = (val: string) => {
-
-}
-
-const loginValidate = () => {
-  const { nickName, location, examType, endYear } = form.value;
-  if (!nickName || nickName.trim() === '') {
-    uni.$ie.showToast('请输入姓名');
-    return false;
-  }
-  if (!location || location.trim() === '') {
-    uni.$ie.showToast('请选择省份');
-    return false;
-  }
-  if (!examType || examType.trim() === '') {
-    uni.$ie.showToast('请选择考生类别');
-    return false;
-  }
-  if (examType === 'VHS') {
-    if (!form.value.majorType) {
-      uni.$ie.showToast('请选择专业类别');
-      return false;
-    }
-  }
-  if (!endYear) {
-    uni.$ie.showToast('请选择毕业年份');
-    return false;
-  }
-  return true;
-}
-const handleSubmit = async () => {
-  console.log(form.value)
-  // const valid = await formRef.value.validate();
-  // const valid = await loginValidate();
-  const valid = loginValidate();
-  if (valid) {
-    const { mobile, password, code, uuid } = prevData.value;
-    const params = {
-      ...form.value,
-      mobile,
-      password,
-      code,
-      uuid,
-      scores: scores.value,
-    };
-    registry(params as RegisterInfo).then(res => {
-      const token = res.token;
-      if (token) {
-
-      }
-    });
-  }
-}
-
-const gatherInfo = () => {
-  const { nickName, location, examType, endYear, scores } = userStore.userInfo;
-  console.log(nickName, location, examType, endYear, scores)
-  form.value = {
-    nickName,
-    location,
-    examType,
-    endYear,
-    scores
-  };
-  if (location) {
-    loadExamTypes();
-  }
-  if (examType) {
-    loadMajorTypes();
-  }
-  if (endYear) {
-    loadGraduateYears();
-  }
-  console.log(form.value)
-}
-
-onLoad(() => {
-  console.log(prevData.value)
-  console.log(userStore.userInfo)
-  gatherInfo();
-});
-</script>
-
-<style lang="scss" scoped></style>

+ 17 - 9
src/pagesSystem/pages/card-verify/card-verify.vue

@@ -16,11 +16,14 @@
 
 <script lang="ts" setup>
 import { verifyCard } from '@/api/modules/user';
+import { EnumBindScene } from '@/common/enum';
 import { useTransferPage } from '@/hooks/useTransferPage';
+import { useUserStore } from '@/store/userStore';
 const { transferTo } = useTransferPage();
+const userStore = useUserStore();
 const form = ref({
-  cardNo: '',
-  password: ''
+  cardNo: '60005006',
+  password: '718312'
 });
 const handleSubmit = async () => {
   const { cardNo, password } = form.value;
@@ -33,15 +36,20 @@ const handleSubmit = async () => {
     return;
   }
   uni.$ie.showLoading();
-  verifyCard(cardNo, password).then(() => {
+  verifyCard(cardNo, password).then((res) => {
     uni.$ie.hideLoading();
-    transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
-      data: {
-        cardNo,
-        password,
-        type: 'card',
-        scene: 'phone_improve'
+    const submitInfo = {
+      token: userStore.accessToken,
+      scene: EnumBindScene.LOGIN_BIND,
+      userInfo: userStore.userInfo,
+      cardInfo: res.data,
+      registerInfo: {
+        username: form.value.cardNo,
+        password: form.value.password,
       }
+    };
+    transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
+      data: submitInfo
     });
   }).catch(() => {
     uni.$ie.hideLoading();

+ 23 - 13
src/pagesSystem/pages/login/login.vue

@@ -61,9 +61,9 @@ import { useUserStore } from '@/store/userStore';
 import { useTransferPage } from '@/hooks/useTransferPage';
 import { validatePhone } from '@/hooks/useValidation';
 import { verifyCard } from '@/api/modules/user';
-import { EnumSmsApiType } from '@/common/enum';
-import { mobileLogin } from '@/api/modules/login';
-import { MobileLoginRequestDTO, MobileLoginResponseDTO } from '@/types/user';
+import { EnumBindScene, EnumSmsApiType } from '@/common/enum';
+import { login } from '@/api/modules/login';
+import { LoginRequestDTO, MobileLoginResponseDTO } from '@/types/user';
 const { transferBack, transferTo } = useTransferPage();
 const userStore = useUserStore();
 
@@ -153,7 +153,7 @@ const handleLogin = async () => {
 }
 
 const submitLogin = async () => {
-  const params: MobileLoginRequestDTO = {
+  const params: LoginRequestDTO = {
     code: code.value,
     uuid: uuid.value
   };
@@ -168,16 +168,24 @@ const submitLogin = async () => {
   }
 }
 
-const handleMobileLogin = async (params: MobileLoginRequestDTO) => {
+const handleMobileLogin = async (params: LoginRequestDTO) => {
   uni.$ie.showLoading();
-  mobileLogin(params).then((res) => {
+  login(params).then((res) => {
     uni.$ie.hideLoading();
     if (res.data) {
       const { code, message } = res.data;
       if (code === 101) {
+        console.log('registerInfo:', params)
         // 账号不存在,需要注册
         transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
-          data: params
+          data: {
+            scene: EnumBindScene.REGISTER,
+            userInfo: {},
+            cardInfo: {},
+            registerInfo: {
+              ...params
+            }
+          }
         });
       }
     } else {
@@ -195,9 +203,9 @@ const handleMobileLogin = async (params: MobileLoginRequestDTO) => {
     console.log('登录失败', err)
   })
 }
-const handleCardLogin = (params: MobileLoginRequestDTO) => {
+const handleCardLogin = (params: LoginRequestDTO) => {
   uni.$ie.showLoading();
-  mobileLogin(params).then(res => {
+  login(params).then(res => {
     if (res.token) {
       userStore.login(res.token).then((success: boolean) => {
         uni.$ie.hideLoading();
@@ -210,14 +218,16 @@ const handleCardLogin = (params: MobileLoginRequestDTO) => {
     } else if (res.data.code === 101) {
       // 
       verifyCard(cardNo.value, cardPassword.value).then(res => {
-        console.log(res)
+        console.log('卡信息:', res)
         uni.$ie.hideLoading();
         if (res.data) {
+          console.log('registerInfo:', params)
           transferTo('/pagesSystem/pages/phone-verify/phone-verify', {
             data: {
-              card: res.data,
-              cardNo: res.data.cardNo,
-              password: res.data.password
+              scene: EnumBindScene.REGISTER,
+              userInfo: {},
+              cardInfo: res.data,
+              registerInfo: params
             }
           });
         }

+ 110 - 28
src/pagesSystem/pages/phone-verify/phone-verify.vue

@@ -4,8 +4,8 @@
     <view class="h-20"></view>
     <view class="px-46 py-50 bg-white">
       <ie-input v-model="form.phone" type="number" :maxlength="11" placeholder="请输入手机号" />
-      <ie-input custom-class="mt-28" type="number" :maxlength="6" v-model="form.code" placeholder="请输入验证码">
-        <ie-sms :phone="form.phone" :sms-api-type="EnumSmsApiType.NO_TOKEN" @send="handleSendSuccess" />
+      <ie-input custom-class="mt-28" type="number" :maxlength="6" v-model="form.password" placeholder="请输入验证码">
+        <ie-sms :phone="form.phone" :sms-api-type="EnumSmsApiType.NO_VALIDATION_NO_TOKEN" @send="handleSendSuccess" />
       </ie-input>
     </view>
     <ie-safe-toolbar :height="84" :shadow="false">
@@ -19,22 +19,99 @@
 <script lang="ts" setup>
 import { verifyCard } from '@/api/modules/user';
 import { useTransferPage } from '@/hooks/useTransferPage';
-import { EnumSmsApiType } from '@/common/enum';
+import { EnumBindScene, EnumSmsApiType } from '@/common/enum';
 import { validateSms } from '@/api/modules/system';
 import { validatePhone } from '@/hooks/useValidation';
+import { getUserInfo, getUserInfoWithToken, login } from '@/api/modules/login';
+import { useUserStore } from '@/store/userStore';
 const { prevData, transferTo } = useTransferPage();
 const form = ref({
   phone: '',
-  code: '',
+  password: '',
   uuid: '',
+  code: '', //图形验证码
 });
 const handleSendSuccess = (_phone: string, _code: string, _uuid: string) => {
   console.log('短信发送成功', _phone, _code, _uuid);
-  // form.value.code = _code;
+  form.value.code = _code;
   form.value.uuid = _uuid;
 }
+/**
+ * 通过登录接口,检查手机号是否已经注册用户
+ */
+const checkHasReg = async () => {
+  const params = {
+    mobile: form.value.phone,
+    code: form.value.code,
+    uuid: form.value.uuid,
+    password: form.value.password,
+  };
+  const res = await login(params);
+  // const params = {
+  //   phone: form.value.phone,
+  //   code: form.value.code,
+  //   uuid: form.value.uuid,
+  //   scene: '',
+  //   type: 'phone',
+  //   card: prevData.value.card,
+  //   cardNo: prevData.value.cardNo,
+  //   password: prevData.value.password
+  // };
+  if (res.data) {
+    const { code, message } = res.data;
+    if (code === 101) {
+      console.log('用户不存在')
+      console.log(params)
+      const submitInfo = {
+        scene: EnumBindScene.REGISTER_BIND,
+        userInfo: {},
+        cardInfo: prevData.value.cardInfo,
+        registerInfo: {
+          ...params,
+          // 此时注册信息需要替换为卡信息
+          username: prevData.value.registerInfo.username,
+          password: prevData.value.registerInfo.password,
+        }
+      };
+      // 账户不存在,执行注册操作
+      transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
+        data: submitInfo
+      });
+    }
+  } else {
+    // 账户已存在,执行绑卡操作
+    if (res.token) {
+      // 查询用户信息
+      const { data } = await getUserInfoWithToken(res.token);
+      console.log('用户已存在,用户信息:', data)
+      // params.scene = 'phone_improve';
+      // console.log(params)
+      // 判断用户是否是 vip
+      if (!!data.cardId) {
+        uni.$ie.showToast('该手机号已绑定其他账号,请使用其他手机号');
+        return;
+      }
+      // 不是 vip 则可以绑定
+      const submitInfo = {
+        scene: EnumBindScene.LOGIN_BIND,
+        userInfo: data,
+        cardInfo: prevData.value.cardInfo,
+        registerInfo: {
+          ...params,
+          // 此时注册信息需要替换为卡信息
+          username: prevData.value.registerInfo.username,
+          password: prevData.value.registerInfo.password,
+        }
+      };
+      console.log('提交信息:', submitInfo)
+      transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
+        data: submitInfo
+      });
+    }
+  }
+}
 const handleSubmit = async () => {
-  const { phone, code, uuid } = form.value;
+  const { phone, password, uuid } = form.value;
   if (!phone || phone.trim() === '') {
     uni.$ie.showToast('请输入手机号');
     return;
@@ -43,35 +120,40 @@ const handleSubmit = async () => {
     uni.$ie.showToast('请输入正确的手机号');
     return;
   }
-  if (!uuid && code) {
+  if (!uuid && password) {
     uni.$ie.showToast('请输入正确的验证码');
     return;
   }
-  if (!uuid || !code || code.trim() === '') {
+  if (!uuid || !password || password.trim() === '') {
     uni.$ie.showToast('请输入验证码');
     return;
   }
-  uni.$ie.showLoading();
-  validateSms({ mobile: phone, code }).then(() => {
-    uni.$ie.hideLoading();
-    const params = {
-      phone,
-      code,
-      uuid,
-      type: 'phone',
-      scene: 'card_improve',
-      card: prevData.value.card,
-      cardNo: prevData.value.cardNo,
-      password: prevData.value.password
-    };
-    console.log(params)
-    transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
-      data: params
-    });
-  }).catch(() => {
-    uni.$ie.hideLoading();
-  });
+  // uni.$ie.showLoading();
+  checkHasReg();
+  // validateSms({ mobile: phone, code: password }).then(() => {
+  //   uni.$ie.hideLoading();
+  //   const params = {
+  //     phone,
+  //     code: password,
+  //     uuid,
+  //     type: 'phone',
+  //     scene: 'card_improve',
+  //     card: prevData.value.card,
+  //     cardNo: prevData.value.cardNo,
+  //     password: prevData.value.password
+  //   };
+  //   console.log(params)
+  //   checkHasReg();
+  //   // transferTo('/pagesSystem/pages/bind-profile/bind-profile', {
+  //   //   data: params
+  //   // });
+  // }).catch(() => {
+  //   uni.$ie.hideLoading();
+  // });
 }
+onLoad(() => {
+  console.log('收到上个页面的数据', prevData.value)
+});
 </script>
 
 <style lang="scss" scoped></style>

+ 3 - 0
src/store/userStore.ts

@@ -90,6 +90,9 @@ export const useUserStore = defineStore('ie-user', {
     }
   },
   actions: {
+    setToken(token: string) {
+      this.accessToken = token;
+    },
     async login(token: string) {
       try {
         this.accessToken = token;

+ 2 - 1
src/types/user.ts

@@ -117,7 +117,7 @@ export interface CaptchaImage {
   uuid: string;
 }
 
-export interface MobileLoginRequestDTO {
+export interface LoginRequestDTO {
   code?: string;
   mobile?: string;
   password?: string;
@@ -138,6 +138,7 @@ export interface UserInfo {
   code: string;
   endYear: number;
   examType: string;
+  majorType?: string;
   inviteCode?: string;
   location: string;
   nickName: string;

+ 8 - 4
src/utils/uni-tool.ts

@@ -104,10 +104,14 @@ const tool: IeTool = {
   loadingStartTime: 0,
   minLoadingTime: 500, // 最小显示时间,单位毫秒
   showToast(title: string = '') {
-    uni.showToast({
-      title,
-      icon: 'none'
-    });
+    // 先立即隐藏,避免上一个 toast存在导致下次的 toast 很快关闭
+    uni.hideToast();
+    setTimeout(() => {
+      uni.showToast({
+        title,
+        icon: 'none'
+      });
+    }, 50);
   },
   showSuccess(title: string = '') {
     uni.showToast({