浏览代码

优化代码实现。

scholar 9 月之前
父节点
当前提交
2205526a79
共有 3 个文件被更改,包括 252 次插入119 次删除
  1. 7 1
      src/api/login/index.ts
  2. 7 0
      src/api/login/types.ts
  3. 238 118
      src/views/Login/components/RegisterForm.vue

+ 7 - 1
src/api/login/index.ts

@@ -1,6 +1,6 @@
 import request from '@/config/axios'
 import { getRefreshToken } from '@/utils/auth'
-import type { UserLoginVO } from './types'
+import type {RegisterVO, UserLoginVO} from './types'
 
 export interface SmsCodeVO {
   mobile: string
@@ -17,6 +17,12 @@ export const login = (data: UserLoginVO) => {
   return request.post({ url: '/system/auth/login', data })
 }
 
+// 注册
+export const register = (data: RegisterVO) => {
+  console.log("data: RegisterVO=========",data)
+  return request.post({ url: '/system/auth/register', data })
+}
+
 // 刷新访问令牌
 export const refreshToken = () => {
   return request.post({ url: '/system/auth/refresh-token?refreshToken=' + getRefreshToken() })

+ 7 - 0
src/api/login/types.ts

@@ -29,3 +29,10 @@ export type UserVO = {
   loginIp: string
   loginDate: string
 }
+
+export type RegisterVO = {
+  tenantName: string
+  username: string
+  password: string
+  captchaVerification: string
+}

+ 238 - 118
src/views/Login/components/RegisterForm.vue

@@ -1,142 +1,262 @@
 <template>
-  <Form
+  <el-form
     v-show="getShow"
-    :rules="rules"
-    :schema="schema"
-    class="dark:(border-1 border-[var(--el-border-color)] border-solid)"
-    hide-required-asterisk
+    ref="formLogin"
+    :model="registerData.registerForm"
+    :rules="registerRules"
+    class="login-form"
     label-position="top"
+    label-width="120px"
     size="large"
-    @register="register"
   >
-    <template #title>
-      <LoginFormTitle style="width: 100%" />
-    </template>
-
-    <template #code="form">
-      <div class="w-[100%] flex">
-        <el-input v-model="form['code']" :placeholder="t('login.codePlaceholder')" />
-      </div>
-    </template>
-
-    <template #register>
-      <div class="w-[100%]">
-        <XButton
-          :loading="loading"
-          :title="t('login.register')"
-          class="w-[100%]"
-          type="primary"
-          @click="loginRegister()"
-        />
-      </div>
-      <div class="mt-15px w-[100%]">
-        <XButton :title="t('login.hasUser')" class="w-[100%]" @click="handleBackLogin()" />
-      </div>
-    </template>
-  </Form>
+    <el-row style="margin-right: -10px; margin-left: -10px">
+      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
+        <el-form-item>
+          <LoginFormTitle style="width: 100%" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
+        <el-form-item v-if="registerData.tenantEnable === 'true'" prop="tenantName">
+          <el-input
+            v-model="registerData.registerForm.tenantName"
+            :placeholder="t('login.tenantname')"
+            :prefix-icon="iconHouse"
+            link
+            type="primary"
+            size="large"
+          />
+        </el-form-item>
+      </el-col>
+      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
+        <el-form-item prop="username">
+          <el-input
+            v-model="registerData.registerForm.username"
+            :placeholder="t('login.username')"
+            size="large"
+            :prefix-icon="iconAvatar"
+          />
+        </el-form-item>
+      </el-col>
+      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
+        <el-form-item prop="password">
+          <el-input
+            v-model="registerData.registerForm.password"
+            type="password"
+            auto-complete="off"
+            :placeholder="t('login.password')"
+            size="large"
+            :prefix-icon="iconLock"
+            show-password
+          />
+        </el-form-item>
+      </el-col>
+      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
+        <el-form-item prop="confirmPassword">
+          <el-input
+            v-model="registerData.registerForm.confirmPassword"
+            type="password"
+            size="large"
+            auto-complete="off"
+            :placeholder="t('login.checkPassword')"
+            :prefix-icon="iconLock"
+            show-password
+          />
+        </el-form-item>
+      </el-col>
+      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
+        <el-form-item>
+          <XButton
+            :loading="loginLoading"
+            :title="t('login.register')"
+            class="w-[100%]"
+            type="primary"
+            @click="getCode()"
+          />
+        </el-form-item>
+      </el-col>
+      <Verify
+        ref="verify"
+        :captchaType="captchaType"
+        :imgSize="{ width: '400px', height: '200px' }"
+        mode="pop"
+        @success="handleRegister"
+      />
+    </el-row>
+    <XButton :title="t('login.hasUser')" class="w-[100%]" @click="handleBackLogin()" />
+  </el-form>
 </template>
 <script lang="ts" setup>
-import type { FormRules } from 'element-plus'
-
-import { useForm } from '@/hooks/web/useForm'
-import { useValidator } from '@/hooks/web/useValidator'
+import {ElLoading, ElMessageBox} from 'element-plus'
 import LoginFormTitle from './LoginFormTitle.vue'
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
+import { useIcon } from '@/hooks/web/useIcon'
+import * as authUtil from '@/utils/auth'
+import { usePermissionStore } from '@/store/modules/permission'
+import * as LoginApi from '@/api/login'
 import { LoginStateEnum, useLoginState } from './useLogin'
-import { FormSchema } from '@/types/form'
 
-defineOptions({ name: 'RegisterForm' })
+defineOptions({ name: 'LoginForm' })
 
 const { t } = useI18n()
-const { required } = useValidator()
-const { register, elFormRef } = useForm()
+const iconHouse = useIcon({ icon: 'ep:house' })
+const iconAvatar = useIcon({ icon: 'ep:avatar' })
+const iconLock = useIcon({ icon: 'ep:lock' })
+const formLogin = ref()
 const { handleBackLogin, getLoginState } = useLoginState()
+const { currentRoute, push } = useRouter()
+const permissionStore = usePermissionStore()
+const redirect = ref<string>('')
+const loginLoading = ref(false)
+const verify = ref()
+const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
+
+
+
 const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER)
 
-const schema = reactive<FormSchema[]>([
-  {
-    field: 'title',
-    colProps: {
-      span: 24
-    }
-  },
-  {
-    field: 'username',
-    label: t('login.username'),
-    value: '',
-    component: 'Input',
-    colProps: {
-      span: 24
-    },
-    componentProps: {
-      placeholder: t('login.usernamePlaceholder')
-    }
-  },
-  {
-    field: 'password',
-    label: t('login.password'),
-    value: '',
-    component: 'InputPassword',
-    colProps: {
-      span: 24
-    },
-    componentProps: {
-      style: {
-        width: '100%'
-      },
-      strength: true,
-      placeholder: t('login.passwordPlaceholder')
-    }
-  },
-  {
-    field: 'check_password',
-    label: t('login.checkPassword'),
-    value: '',
-    component: 'InputPassword',
-    colProps: {
-      span: 24
-    },
-    componentProps: {
-      style: {
-        width: '100%'
-      },
-      strength: true,
-      placeholder: t('login.passwordPlaceholder')
-    }
-  },
-  {
-    field: 'code',
-    label: t('login.code'),
-    colProps: {
-      span: 24
-    }
-  },
-  {
-    field: 'register',
-    colProps: {
-      span: 24
-    }
+const equalToPassword = (rule, value, callback) => {
+  if (registerData.registerForm.password !== value) {
+    callback(new Error("两次输入的密码不一致"));
+  } else {
+    callback();
   }
-])
+};
 
-const rules: FormRules = {
-  username: [required()],
-  password: [required()],
-  check_password: [required()],
-  code: [required()]
+const registerRules = {
+  tenantName: [
+    { required: true, trigger: "blur", message: "请输入您所属的租户" },
+    { min: 2, max: 20, message: "租户账号长度必须介于 2 和 20 之间", trigger: "blur" }
+  ],
+  username: [
+    { required: true, trigger: "blur", message: "请输入您的账号" },
+    { min: 2, max: 20, message: "用户账号长度必须介于 2 和 20 之间", trigger: "blur" }
+  ],
+  password: [
+    { required: true, trigger: "blur", message: "请输入您的密码" },
+    { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
+    { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
+  ],
+  confirmPassword: [
+    { required: true, trigger: "blur", message: "请再次输入您的密码" },
+    { required: true, validator: equalToPassword, trigger: "blur" }
+  ]
 }
 
-const loading = ref(false)
+const registerData = reactive({
+  isShowPassword: false,
+  captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE,
+  tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE,
+  registerForm: {
+    tenantName: '',
+    nickname: "芋艿",
+    tenantId:  0,
+    username: '',
+    password: '',
+    confirmPassword: "",
+    captchaVerification: ''
+  }
+})
+
+async function handleRegister() {
+  loading.value = true
+  await getTenantId()
+  registerData.registerForm.tenantId = authUtil.getTenantId()
 
-const loginRegister = async () => {
-  const formRef = unref(elFormRef)
-  formRef?.validate(async (valid) => {
-    if (valid) {
-      try {
-        loading.value = true
-      } finally {
-        loading.value = false
+  LoginApi.register(registerData.registerForm).then(() => {
+  const username = registerData.registerForm.username;
+  ElMessageBox.alert("<font color='green'>恭喜你,您的账号 " + username + " 注册成功!</font>", "系统提示", {
+      dangerouslyUseHTMLString: true,
+      type: "success",
+    }).then(async () => {
+      const res = await LoginApi.login(registerData.registerForm)
+      if (!res) {
+        return
+      }
+      loading.value = ElLoading.service({
+        lock: true,
+        text: '正在加载系统中...',
+        background: 'rgba(0, 0, 0, 0.7)'
+      })
+      authUtil.removeLoginForm()
+      authUtil.setToken(res)
+      if (!redirect.value) {
+        redirect.value = '/'
+      }
+      // 判断是否为SSO登录
+      if (redirect.value.indexOf('sso') !== -1) {
+        window.location.href = window.location.href.replace('/login?redirect=', '')
+      } else {
+        push({path: redirect.value || permissionStore.addRouters[0].path})
       }
-    }
+      loginLoading.value = false
+      loading.value.close()
+    })
   })
 }
+
+// 获取验证码
+const getCode = async () => {
+  // 情况一,未开启:则直接登录
+  if (registerData.captchaEnable === 'false') {
+    await handleRegister()
+  } else {
+    // 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行登录
+    // 弹出验证码
+    verify.value.show()
+  }
+}
+// 获取租户 ID
+const getTenantId = async () => {
+  if (registerData.tenantEnable === 'true') {
+    const res = await LoginApi.getTenantIdByName(registerData.registerForm.tenantName)
+    authUtil.setTenantId(res)
+  }
+}
+
+// 根据域名,获得租户信息
+const getTenantByWebsite = async () => {
+  const website = location.host
+  const res = await LoginApi.getTenantByWebsite(website)
+  if (res) {
+    registerData.registerForm.tenantName = res.name
+    authUtil.setTenantId(res.id)
+  }
+}
+const loading = ref() // ElLoading.service 返回的实例
+
+watch(
+  () => currentRoute.value,
+  (route: RouteLocationNormalizedLoaded) => {
+    redirect.value = route?.query?.redirect as string
+  },
+  {
+    immediate: true
+  }
+)
+onMounted(() => {
+  // getCookie()
+  getTenantByWebsite()
+})
 </script>
+
+<style lang="scss" scoped>
+:deep(.anticon) {
+  &:hover {
+    color: var(--el-color-primary) !important;
+  }
+}
+
+.login-code {
+  float: right;
+  width: 100%;
+  height: 38px;
+
+  img {
+    width: 100%;
+    height: auto;
+    max-width: 100px;
+    vertical-align: middle;
+    cursor: pointer;
+  }
+}
+</style>