From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/Login/components/MobileForm.vue | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 226 insertions(+), 0 deletions(-)
diff --git a/src/views/Login/components/MobileForm.vue b/src/views/Login/components/MobileForm.vue
new file mode 100644
index 0000000..bb4f1a6
--- /dev/null
+++ b/src/views/Login/components/MobileForm.vue
@@ -0,0 +1,226 @@
+<template>
+ <el-form
+ v-show="getShow"
+ ref="formSmsLogin"
+ :model="loginData.loginForm"
+ :rules="rules"
+ class="login-form"
+ label-position="top"
+ label-width="120px"
+ size="large"
+ >
+ <el-row class="mx-[-10px]">
+ <!-- 绉熸埛鍚� -->
+ <el-col :span="24" class="px-10px">
+ <el-form-item>
+ <LoginFormTitle class="w-full" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="24" class="px-10px">
+ <el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantName">
+ <el-input
+ v-model="loginData.loginForm.tenantName"
+ :placeholder="t('login.tenantNamePlaceholder')"
+ :prefix-icon="iconHouse"
+ type="primary"
+ link
+ />
+ </el-form-item>
+ </el-col>
+ <!-- 鎵嬫満鍙� -->
+ <el-col :span="24" class="px-10px">
+ <el-form-item prop="mobileNumber">
+ <el-input
+ v-model="loginData.loginForm.mobileNumber"
+ :placeholder="t('login.mobileNumberPlaceholder')"
+ :prefix-icon="iconCellphone"
+ />
+ </el-form-item>
+ </el-col>
+ <!-- 楠岃瘉鐮� -->
+ <el-col :span="24" class="px-10px">
+ <el-form-item prop="code">
+ <el-row :gutter="5" justify="space-between" style="width: 100%">
+ <el-col :span="24">
+ <el-input
+ v-model="loginData.loginForm.code"
+ :placeholder="t('login.codePlaceholder')"
+ :prefix-icon="iconCircleCheck"
+ >
+ <!-- <el-button class="w-[100%]"> -->
+ <template #append>
+ <span
+ v-if="mobileCodeTimer <= 0"
+ class="getMobileCode"
+ style="cursor: pointer"
+ @click="getSmsCode"
+ >
+ {{ t('login.getSmsCode') }}
+ </span>
+ <span v-if="mobileCodeTimer > 0" class="getMobileCode" style="cursor: pointer">
+ {{ mobileCodeTimer }}绉掑悗鍙噸鏂拌幏鍙�
+ </span>
+ </template>
+ </el-input>
+ <!-- </el-button> -->
+ </el-col>
+ </el-row>
+ </el-form-item>
+ </el-col>
+ <!-- 鐧诲綍鎸夐挳 / 杩斿洖鎸夐挳 -->
+ <el-col :span="24" class="px-10px">
+ <el-form-item>
+ <XButton
+ :loading="loginLoading"
+ :title="t('login.login')"
+ class="w-full"
+ type="primary"
+ @click="signIn()"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="24" class="px-10px">
+ <el-form-item>
+ <XButton
+ :loading="loginLoading"
+ :title="t('login.backLogin')"
+ class="w-full"
+ @click="handleBackLogin()"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+</template>
+<script lang="ts" setup>
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
+
+import { useIcon } from '@/hooks/web/useIcon'
+
+import { setTenantId, setToken } from '@/utils/auth'
+import { usePermissionStore } from '@/store/modules/permission'
+import { getTenantIdByName, sendSmsCode, smsLogin } from '@/api/login'
+import LoginFormTitle from './LoginFormTitle.vue'
+import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
+import { ElLoading } from 'element-plus'
+
+defineOptions({ name: 'MobileForm' })
+
+const { t } = useI18n()
+const message = useMessage()
+const permissionStore = usePermissionStore()
+const { currentRoute, push } = useRouter()
+const formSmsLogin = ref()
+const loginLoading = ref(false)
+const iconHouse = useIcon({ icon: 'ep:house' })
+const iconCellphone = useIcon({ icon: 'ep:cellphone' })
+const iconCircleCheck = useIcon({ icon: 'ep:circle-check' })
+const { validForm } = useFormValid(formSmsLogin)
+const { handleBackLogin, getLoginState } = useLoginState()
+const getShow = computed(() => unref(getLoginState) === LoginStateEnum.MOBILE)
+
+const rules = {
+ tenantName: [required],
+ mobileNumber: [required],
+ code: [required]
+}
+const loginData = reactive({
+ codeImg: '',
+ tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE,
+ token: '',
+ loading: {
+ signIn: false
+ },
+ loginForm: {
+ uuid: '',
+ tenantName: '鑺嬮亾婧愮爜',
+ mobileNumber: '',
+ code: ''
+ }
+})
+const smsVO = reactive({
+ smsCode: {
+ mobile: '',
+ scene: 21
+ },
+ loginSms: {
+ mobile: '',
+ code: ''
+ }
+})
+const mobileCodeTimer = ref(0)
+const redirect = ref<string>('')
+const getSmsCode = async () => {
+ await getTenantId()
+ smsVO.smsCode.mobile = loginData.loginForm.mobileNumber
+ await sendSmsCode(smsVO.smsCode).then(async () => {
+ message.success(t('login.SmsSendMsg'))
+ // 璁剧疆鍊掕鏃�
+ mobileCodeTimer.value = 60
+ let msgTimer = setInterval(() => {
+ mobileCodeTimer.value = mobileCodeTimer.value - 1
+ if (mobileCodeTimer.value <= 0) {
+ clearInterval(msgTimer)
+ }
+ }, 1000)
+ })
+}
+watch(
+ () => currentRoute.value,
+ (route: RouteLocationNormalizedLoaded) => {
+ redirect.value = route?.query?.redirect as string
+ },
+ {
+ immediate: true
+ }
+)
+// 鑾峰彇绉熸埛 ID
+const getTenantId = async () => {
+ if (loginData.tenantEnable === 'true') {
+ const res = await getTenantIdByName(loginData.loginForm.tenantName)
+ setTenantId(res)
+ }
+}
+// 鐧诲綍
+const signIn = async () => {
+ await getTenantId()
+ const data = await validForm()
+ if (!data) return
+ ElLoading.service({
+ lock: true,
+ text: '姝e湪鍔犺浇绯荤粺涓�...',
+ background: 'rgba(0, 0, 0, 0.7)'
+ })
+ loginLoading.value = true
+ smsVO.loginSms.mobile = loginData.loginForm.mobileNumber
+ smsVO.loginSms.code = loginData.loginForm.code
+ await smsLogin(smsVO.loginSms)
+ .then(async (res) => {
+ setToken(res)
+ if (!redirect.value) {
+ redirect.value = '/'
+ }
+ push({ path: redirect.value || permissionStore.addRouters[0].path })
+ })
+ .catch(() => {})
+ .finally(() => {
+ loginLoading.value = false
+ setTimeout(() => {
+ const loadingInstance = ElLoading.service()
+ loadingInstance.close()
+ }, 400)
+ })
+}
+</script>
+
+<style lang="scss" scoped>
+:deep(.anticon) {
+ &:hover {
+ color: var(--el-color-primary) !important;
+ }
+}
+
+.smsbtn {
+ margin-top: 33px;
+}
+</style>
--
Gitblit v1.8.0