浏览代码

Merge branch 'wanzi'

liyanbo 7 月之前
父节点
当前提交
8af174e528
共有 2 个文件被更改,包括 240 次插入46 次删除
  1. 20 0
      src/api/login/login.js
  2. 220 46
      src/views/Login.vue

+ 20 - 0
src/api/login/login.js

@@ -27,4 +27,24 @@ export function logout (data){
         method: 'post',
         data
     })
+}
+
+// 手机号登录
+export function smsLogin(headers,data){
+    return axios({
+        url: "bjdxWeb/web/sms-login",
+        method: 'post',
+        data,
+        headers: headers,
+    })
+}
+
+// 手机号获取验证码
+export function smsCode(headers,data){
+    return axios({
+        url: "bjdxWeb/web/send-sms-code",
+        method: 'post',
+        data,
+        headers: headers,
+    })
 }

+ 220 - 46
src/views/Login.vue

@@ -24,27 +24,60 @@
               placeholder="学校"
             />
           </el-form-item>
-          <el-form-item prop="username">
-            <el-input
-              v-model="loginData.loginForm.username"
-              :prefix-icon="Avatar"
-              placeholder="账号"
-            />
-          </el-form-item>
-          <el-form-item prop="password">
-            <el-input
-              v-model="loginData.loginForm.password"
-              type="password"
-              :prefix-icon="Lock"
-              placeholder="密码"
-              show-password
-            />
-          </el-form-item>
           
+          <!-- 条件显示手机号和短信验证码或账号和密码 -->
+         <template v-if="isAuthorized"> 
+            <el-form-item prop="username">
+              <el-input
+                v-model="loginData.loginForm.username"
+                :prefix-icon="Avatar"
+                placeholder="账号"
+              />
+            </el-form-item>
+            <el-form-item prop="password">
+              <el-input
+                v-model="loginData.loginForm.password"
+                class="password-input"
+                type="password"
+                :prefix-icon="Lock"
+                placeholder="密码"
+                show-password
+              />
+            </el-form-item>
+          </template> 
+          
+       <template v-else>
+            <el-form-item prop="phoneNumber">
+              <el-input
+                v-model="loginData.loginForm.phoneNumber"
+                :prefix-icon="Iphone"
+                placeholder="手机号"
+              />
+            </el-form-item>
+            <!-- 短信验证码输入框和获取验证码按钮 -->
+            <el-form-item prop="smsCode">
+              <div class="sms-code-container">
+                <el-input
+                  v-model="loginData.loginForm.smsCode"
+                  placeholder="短信验证码"
+                  class="sms-input"
+                />
+                <el-button 
+                  type="primary" 
+                  @click="getSmsCode"
+                  :disabled="countingDown"
+                  class="get-code-btn"
+                  :loading="sendingCode"
+                >
+                  {{ countingDown ? `${countDown}秒后重新获取` : '获取验证码' }}
+                </el-button>
+              </div>
+            </el-form-item>
+          </template> 
 
           <!-- 登录按钮 -->
           <el-form-item>
-            <el-button type="primary" @click="handleLogin">登录</el-button>
+            <el-button class="login-btn" type="primary" @click="handleLogin">登录</el-button>
           </el-form-item>
         </el-form>
         <!-- 多选框 -->
@@ -54,7 +87,6 @@
               label="记住我"
               size="large"
             />
-            <!-- <a href="javascript:;" class="forgot-password">忘记密码?</a> -->
           </div>
       </div>
     </div>
@@ -62,14 +94,15 @@
 </template>
 
 <script setup>
-import { ref, onMounted, computed ,onUnmounted} from 'vue'
+import { ref, onMounted, computed, onUnmounted, nextTick } from 'vue'
 import { useRouter } from 'vue-router'
-import { HomeFilled, Avatar, Lock } from '@element-plus/icons-vue'
-import { getTenantIdByName, login } from '@/api/login/login.js'
+import { HomeFilled, Avatar, Lock,Iphone } from '@element-plus/icons-vue'
+import { getTenantIdByName, login,smsLogin,smsCode } from '@/api/login/login.js'
 import { ElLoading, ElMessage } from 'element-plus'
 
 import BGImages from '@/assets/images/homeBG.png'
 
+
 const router = useRouter()
 
 const loginFormRef = ref(null)
@@ -79,7 +112,9 @@ const loginData = ref({
     tenantName: import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT || '',
     username: import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME || '',
     password: import.meta.env.VITE_APP_DEFAULT_LOGIN_PASSWORD || '',
-    rememberMe: false // 记住
+    smsCode: '', // 短信验证码字段
+    rememberMe: false, // 记住
+     phoneNumber: '' // 手机号字段
   }
 })
 
@@ -89,17 +124,42 @@ const tenantId = ref('')
 // 登录状态标识
 const isLoggedIn = ref(false)
 
-// 输入框校验
-const rules = {
-  tenantName: [{ required: true, message: '请输入学校名称', trigger: 'blur' }],
-  username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
-  password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
-}
+// 短信验证码相关状态
+const countingDown = ref(false)
+const countDown = ref(60)
+const sendingCode = ref(false)
+let countDownTimer = null
+
+// 授权状态 默认授权
+const isAuthorized = ref(true)
+
+// 输入框校验 - 根据授权状态动态调整
+const rules = computed(() => {
+  if (isAuthorized.value) {
+    // 授权状态:需要账号和密码
+    return {
+      tenantName: [{ required: true, message: '请输入学校名称', trigger: 'blur' }],
+      username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
+      password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
+    }
+  } else {
+    // 未授权状态:需要手机号和短信验证码
+    return {
+      tenantName: [{ required: true, message: '请输入学校名称', trigger: 'blur' }],
+      phoneNumber: [
+        { required: true, message: '请输入手机号', trigger: 'blur' },
+        { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' }
+      ],
+      smsCode: [{ required: true, message: '请输入短信验证码', trigger: 'blur' }]
+    }
+  }
+})
 
 // 获取租户 ID
 const getTenantId = async () => {
   try {
     const res = await getTenantIdByName(loginData.value.loginForm.tenantName)
+    console.log(res);
     if (res && res.data) {
       //记录租户id
       tenantId.value = res.data
@@ -115,6 +175,64 @@ const getTenantId = async () => {
   }
 }
 
+// 获取短信验证码函数
+const getSmsCode = async () => {
+  // 先验证租户和手机号是否填写
+  if (!loginData.value.loginForm.tenantName) {
+    ElMessage.warning('请先输入学校名称')
+    return
+  }
+  if (!loginData.value.loginForm.phoneNumber) {
+    ElMessage.warning('请先输入手机号')
+    return
+  }
+  // 验证租户是否存在
+  const tenantValid = await getTenantId()
+  if (!tenantValid) {
+    return
+  }
+  sendingCode.value = true
+  try {
+    // 获取验证码
+    const res = await smsCode(
+      { 'Tenant-Id': tenantId.value },{
+      tenantName: loginData.value.loginForm.tenantName,
+      mobile: loginData.value.loginForm.phoneNumber,
+      scene: 21,
+    })
+    console.log('发送短信验证码:', res)
+    if (res.code === 0) {
+      ElMessage.success('验证码发送成功')
+      // 开始倒计时
+      startCountDown()
+    } else {
+      ElMessage.error(res.message || '验证码发送失败')
+    }
+  } catch (error) {
+    ElMessage.error('验证码发送失败,请重试')
+    console.error('发送验证码错误:', error)
+  } finally {
+    sendingCode.value = false
+  }
+}
+
+
+// 验证码倒计时函数
+const startCountDown = () => {
+  countingDown.value = true
+  countDown.value = 60
+  
+  if (countDownTimer) {
+    clearInterval(countDownTimer)
+  }
+  countDownTimer = setInterval(() => {
+    countDown.value--
+    if (countDown.value <= 0) {
+      clearInterval(countDownTimer)
+      countingDown.value = false
+    }
+  }, 1000)
+}
 
 // 登录
 const handleLogin = async params => {
@@ -131,23 +249,32 @@ const handleLogin = async params => {
           return
         }
         const loginDataLoginForm = { ...loginData.value.loginForm }
-        // 构建包含 headers 的请求参数
-        const res = await login(
-          { 'Tenant-Id': tenantId.value },
-          loginDataLoginForm
-        )
-        console.log(res);
+
+        // 根据授权状态选择不同的登录接口
+        let res
+        if (!isAuthorized.value) {
+          // 未授权状态,使用短信验证码登录
+          res = await smsLogin(
+            { 'Tenant-Id': tenantId.value },{
+            mobile: loginData.value.loginForm.phoneNumber,
+            code: loginData.value.loginForm.smsCode,
+          }) 
+        } else {
+          // 授权状态,使用账号密码登录
+          res = await login(
+            { 'Tenant-Id': tenantId.value },
+            loginDataLoginForm
+          )
+        }
         
         if (!res) {
           return
         }
-        //【补充】校验登录状态
-        // 成功-失败-提示文字
-        // 校验登录状态,返回数据中 code 为 200 表示成功
+        // 校验登录状态
         if (res.code === 0) {
           ElMessage.success('登录成功')
           isLoggedIn.value = true
-          // 存储登录状态(无论是否勾选记住我都保存基本登录状态)
+          // 存储登录状态
           localStorage.setItem('isLoggedIn', 'true')
           localStorage.setItem('token', res.data.accessToken)
           
@@ -176,11 +303,15 @@ const handleLogin = async params => {
           })
           // 登录成功后,跳转到指定的页面
           router.push('/home')
+        } else if (res.code === 1002000009)  {
+          // 未授权状态,切换到短信验证码登录
+          ElMessage.warning(res.msg || '登录IP未被授权,请使用手机号短信验证码登录!')
+          isAuthorized.value = false
         } else {
-          ElMessage.error(res.message || '登录失败,请检查账号密码')
+          ElMessage.error(res.msg || '登录失败,请检查账号密码')
         }
       } catch (error) {
-        ElMessage.error('登录出错,请重试')
+        ElMessage.error('登录出错,请重试')
         console.error('登录错误:', error)
       } finally {
         loginLoading.value = false
@@ -231,6 +362,9 @@ onMounted(() => {
   // 在组件卸载时移除事件监听
   onUnmounted(() => {
     document.removeEventListener('keydown', handleKeyPress)
+    if (countDownTimer) {
+      clearInterval(countDownTimer)
+    }
   })
 
 })
@@ -301,21 +435,24 @@ onMounted(() => {
   font-size: rpx(7);
 }
 .el-form-item ::v-deep(.el-form-item__error) {
-  top: 0;
-  padding-top: rpx(25);
+  top: rpx(25);
+  // padding-top: rpx(25);
 }
-.input-item .el-button {
+.login-btn {
   width: rpx(150);
-  height: rpx(20);
+  height: rpx(22);
   color: black;
   font-size: rpx(8);
   letter-spacing: rpx(10);
    border-radius: rpx(5);
-  margin: rpx(10) 0 auto;
+  margin: rpx(15) 0 auto;
   border: none;
   background: linear-gradient(to bottom, #fee78a, #ffce1b);
   box-shadow: 0 8px 8px rgb(0, 0, 0, 0.2);
 }
+.password-input {
+  margin-bottom: rpx(0) !important;
+}
 .check-box {
   width: rpx(150);
   height: rpx(18);
@@ -337,4 +474,41 @@ onMounted(() => {
   font-size: rpx(6);
   text-decoration: none;
 }
-</style>
+
+// 短信验证码容器样式
+.sms-code-container {
+  display: flex;
+  align-items: center;
+  width: rpx(150);
+  height: rpx(22);
+}
+
+.sms-input {
+  flex: 1;
+  height: rpx(22);
+  margin-bottom: 0 !important;
+}
+.sms-input ::v-deep(.el-input__wrapper) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+
+.get-code-btn {
+  width: rpx(40);
+  height: rpx(22);
+  margin: 0 !important;
+  padding: 0;
+  font-size: rpx(5);
+   border-radius: rpx(5);
+   border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+  letter-spacing: normal;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #fff;
+  color: #919191;
+  // background: linear-gradient(to bottom, #78c0ff, #0070f3);
+  border: none;
+}
+</style>