mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-11-04 10:57:10 +08:00 
			
		
		
		
	重构:重构登录页面前端代码
This commit is contained in:
		@@ -2,25 +2,29 @@ import axios from 'axios';
 | 
				
			|||||||
import type { RouteRecordNormalized } from 'vue-router';
 | 
					import type { RouteRecordNormalized } from 'vue-router';
 | 
				
			||||||
import { UserState } from '@/store/modules/login/types';
 | 
					import { UserState } from '@/store/modules/login/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BASE_URL = '/auth';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface LoginReq {
 | 
					export interface LoginReq {
 | 
				
			||||||
  username: string;
 | 
					  username: string;
 | 
				
			||||||
  password: string;
 | 
					  password: string;
 | 
				
			||||||
  captcha: string;
 | 
					  captcha: string;
 | 
				
			||||||
  uuid: string;
 | 
					  uuid: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface LoginRes {
 | 
					export interface LoginRes {
 | 
				
			||||||
  token: string;
 | 
					  token: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function login(req: LoginReq) {
 | 
					export function login(req: LoginReq) {
 | 
				
			||||||
  return axios.post<LoginRes>('/auth/login', req);
 | 
					  return axios.post<LoginRes>(`${BASE_URL}/login`, req);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function logout() {
 | 
					export function logout() {
 | 
				
			||||||
  return axios.post('/auth/logout');
 | 
					  return axios.post(`${BASE_URL}/logout`);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function getUserInfo() {
 | 
					export function getUserInfo() {
 | 
				
			||||||
  return axios.get<UserState>('/auth/user/info');
 | 
					  return axios.get<UserState>(`${BASE_URL}/user/info`);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function getMenuList() {
 | 
					export function getMenuList() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,66 +2,46 @@
 | 
				
			|||||||
  <div class="login-form-wrapper">
 | 
					  <div class="login-form-wrapper">
 | 
				
			||||||
    <div class="login-form-title">{{ $t('login.form.title') }}</div>
 | 
					    <div class="login-form-title">{{ $t('login.form.title') }}</div>
 | 
				
			||||||
    <div class="login-form-sub-title">{{ $t('login.form.subTitle') }}</div>
 | 
					    <div class="login-form-sub-title">{{ $t('login.form.subTitle') }}</div>
 | 
				
			||||||
    <div class="login-form-error-msg">{{ errorMessage }}</div>
 | 
					 | 
				
			||||||
    <a-form
 | 
					    <a-form
 | 
				
			||||||
      ref="formRef"
 | 
					      ref="formRef"
 | 
				
			||||||
      :model="formData"
 | 
					      :model="form"
 | 
				
			||||||
      :rules="rules"
 | 
					      :rules="rules"
 | 
				
			||||||
      class="login-form"
 | 
					 | 
				
			||||||
      layout="vertical"
 | 
					      layout="vertical"
 | 
				
			||||||
 | 
					      class="login-form"
 | 
				
			||||||
      @submit="handleLogin"
 | 
					      @submit="handleLogin"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="username" hide-label>
 | 
				
			||||||
        field="username"
 | 
					 | 
				
			||||||
        :validate-trigger="['change', 'blur']"
 | 
					 | 
				
			||||||
        hide-label
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-input
 | 
					        <a-input
 | 
				
			||||||
          v-model="formData.username"
 | 
					          v-model="form.username"
 | 
				
			||||||
          :placeholder="$t('login.form.placeholder.username')"
 | 
					          :placeholder="$t('login.form.placeholder.username')"
 | 
				
			||||||
          size="large"
 | 
					 | 
				
			||||||
          max-length="50"
 | 
					          max-length="50"
 | 
				
			||||||
 | 
					          size="large"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #prefix>
 | 
					          <template #prefix><icon-user /></template>
 | 
				
			||||||
            <icon-user />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
        </a-input>
 | 
					        </a-input>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item field="password" hide-label>
 | 
				
			||||||
        field="password"
 | 
					 | 
				
			||||||
        :validate-trigger="['change', 'blur']"
 | 
					 | 
				
			||||||
        hide-label
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-input-password
 | 
					        <a-input-password
 | 
				
			||||||
          v-model="formData.password"
 | 
					          v-model="form.password"
 | 
				
			||||||
          :placeholder="$t('login.form.placeholder.password')"
 | 
					          :placeholder="$t('login.form.placeholder.password')"
 | 
				
			||||||
          size="large"
 | 
					 | 
				
			||||||
          allow-clear
 | 
					 | 
				
			||||||
          max-length="32"
 | 
					          max-length="32"
 | 
				
			||||||
 | 
					          allow-clear
 | 
				
			||||||
 | 
					          size="large"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #prefix>
 | 
					          <template #prefix><icon-lock /></template>
 | 
				
			||||||
            <icon-lock />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
        </a-input-password>
 | 
					        </a-input-password>
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-form-item
 | 
					      <a-form-item class="login-form-captcha" field="captcha" hide-label>
 | 
				
			||||||
        class="login-form-captcha"
 | 
					 | 
				
			||||||
        field="captcha"
 | 
					 | 
				
			||||||
        :validate-trigger="['change', 'blur']"
 | 
					 | 
				
			||||||
        hide-label
 | 
					 | 
				
			||||||
      >
 | 
					 | 
				
			||||||
        <a-input
 | 
					        <a-input
 | 
				
			||||||
          v-model="formData.captcha"
 | 
					          v-model="form.captcha"
 | 
				
			||||||
          :placeholder="$t('login.form.placeholder.captcha')"
 | 
					          :placeholder="$t('login.form.placeholder.captcha')"
 | 
				
			||||||
 | 
					          allow-clear
 | 
				
			||||||
          size="large"
 | 
					          size="large"
 | 
				
			||||||
          style="width: 63%"
 | 
					          style="width: 63%"
 | 
				
			||||||
          allow-clear
 | 
					 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template #prefix>
 | 
					          <template #prefix><icon-check-circle /></template>
 | 
				
			||||||
            <icon-check-circle />
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
        </a-input>
 | 
					        </a-input>
 | 
				
			||||||
        <img :src="captchaImgBase64" @click="getCaptcha" :alt="$t('login.form.captcha')">
 | 
					        <img :src="captchaImgBase64" :alt="$t('login.form.captcha')" @click="getCaptcha">
 | 
				
			||||||
      </a-form-item>
 | 
					      </a-form-item>
 | 
				
			||||||
      <a-space :size="16" direction="vertical">
 | 
					      <a-space :size="16" direction="vertical">
 | 
				
			||||||
        <div class="login-form-remember-me">
 | 
					        <div class="login-form-remember-me">
 | 
				
			||||||
@@ -73,7 +53,7 @@
 | 
				
			|||||||
            {{ $t('login.form.rememberMe') }}
 | 
					            {{ $t('login.form.rememberMe') }}
 | 
				
			||||||
          </a-checkbox>
 | 
					          </a-checkbox>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <a-button type="primary" size="large" html-type="submit" long :loading="loading">
 | 
					        <a-button :loading="loading" type="primary" size="large" long html-type="submit">
 | 
				
			||||||
          {{ $t('login.form.login') }}
 | 
					          {{ $t('login.form.login') }}
 | 
				
			||||||
        </a-button>
 | 
					        </a-button>
 | 
				
			||||||
      </a-space>
 | 
					      </a-space>
 | 
				
			||||||
@@ -82,23 +62,23 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
  import { ref, reactive, computed, onMounted } from 'vue';
 | 
					import { getCurrentInstance, ref, toRefs, reactive, computed } from "vue";
 | 
				
			||||||
  import { useRouter } from 'vue-router';
 | 
					  import { FieldRule, ValidatedError } from '@arco-design/web-vue';
 | 
				
			||||||
  import { FieldRule, Message } from '@arco-design/web-vue';
 | 
					  import { LoginReq } from '@/api/auth/login';
 | 
				
			||||||
  import { ValidatedError } from '@arco-design/web-vue/es/form/interface';
 | 
					 | 
				
			||||||
  import { useI18n } from 'vue-i18n';
 | 
					  import { useI18n } from 'vue-i18n';
 | 
				
			||||||
  // import debug from '@/utils/env';
 | 
					  import { useRouter } from 'vue-router';
 | 
				
			||||||
  import { encryptByRsa } from '@/utils/encrypt';
 | 
					 | 
				
			||||||
  import { useStorage } from '@vueuse/core';
 | 
					  import { useStorage } from '@vueuse/core';
 | 
				
			||||||
  import { useLoginStore } from '@/store';
 | 
					  import { useLoginStore } from '@/store';
 | 
				
			||||||
  import useLoading from '@/hooks/loading';
 | 
					  import { encryptByRsa } from '@/utils/encrypt';
 | 
				
			||||||
 | 
					  // import debug from '@/utils/env';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { proxy } = getCurrentInstance() as any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const captchaImgBase64 = ref('');
 | 
				
			||||||
 | 
					  const loginStore = useLoginStore();
 | 
				
			||||||
 | 
					  const loading = ref(false);
 | 
				
			||||||
  const { t } = useI18n();
 | 
					  const { t } = useI18n();
 | 
				
			||||||
  const router = useRouter();
 | 
					  const router = useRouter();
 | 
				
			||||||
  const { loading, setLoading } = useLoading();
 | 
					 | 
				
			||||||
  const loginStore = useLoginStore();
 | 
					 | 
				
			||||||
  const errorMessage = ref('');
 | 
					 | 
				
			||||||
  const captchaImgBase64 = ref('');
 | 
					 | 
				
			||||||
  const loginConfig = useStorage('login-config', {
 | 
					  const loginConfig = useStorage('login-config', {
 | 
				
			||||||
    rememberMe: true,
 | 
					    rememberMe: true,
 | 
				
			||||||
    username: 'admin', // 演示默认值
 | 
					    username: 'admin', // 演示默认值
 | 
				
			||||||
@@ -106,59 +86,56 @@
 | 
				
			|||||||
    // username: !debug ? '' : 'admin', // 演示默认值
 | 
					    // username: !debug ? '' : 'admin', // 演示默认值
 | 
				
			||||||
    // password: !debug ? '' : 'admin123', // 演示默认值
 | 
					    // password: !debug ? '' : 'admin123', // 演示默认值
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const formData = reactive({
 | 
					 | 
				
			||||||
    username: loginConfig.value.username,
 | 
					 | 
				
			||||||
    password: loginConfig.value.password,
 | 
					 | 
				
			||||||
    captcha: '',
 | 
					 | 
				
			||||||
    uuid: '',
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  const rules = computed((): Record<string, FieldRule[]> => {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      username: [
 | 
					 | 
				
			||||||
        { required: true, message: t('login.form.error.required.username') }
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      password: [
 | 
					 | 
				
			||||||
        { required: true, message: t('login.form.error.required.password') }
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      captcha: [
 | 
					 | 
				
			||||||
        { required: true, message: t('login.form.error.required.captcha') }
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 获取验证码
 | 
					  const data = reactive({
 | 
				
			||||||
  const getCaptcha = async () => {
 | 
					    // 表单数据
 | 
				
			||||||
    const { data } = await loginStore.getImgCaptcha()
 | 
					    form: {
 | 
				
			||||||
    formData.uuid = data.uuid
 | 
					      username: loginConfig.value.username,
 | 
				
			||||||
    captchaImgBase64.value = data.img
 | 
					      password: loginConfig.value.password,
 | 
				
			||||||
  }
 | 
					      captcha: '',
 | 
				
			||||||
  onMounted(() => {
 | 
					      uuid: '',
 | 
				
			||||||
    getCaptcha();
 | 
					    } as LoginReq,
 | 
				
			||||||
  })
 | 
					    // 表单验证规则
 | 
				
			||||||
 | 
					    rules: computed((): Record<string, FieldRule[]> => {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        username: [{ required: true, message: t('login.form.error.required.username') }],
 | 
				
			||||||
 | 
					        password: [{ required: true, message: t('login.form.error.required.password') }],
 | 
				
			||||||
 | 
					        captcha: [{ required: true, message: t('login.form.error.required.captcha') }],
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  const { form, rules } = toRefs(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 记住我
 | 
					  /**
 | 
				
			||||||
  const setRememberMe = (value: boolean) => {
 | 
					   * 获取验证码
 | 
				
			||||||
    loginConfig.value.rememberMe = value;
 | 
					   */
 | 
				
			||||||
 | 
					  const getCaptcha = () => {
 | 
				
			||||||
 | 
					    loginStore.getImgCaptcha().then((res) => {
 | 
				
			||||||
 | 
					      form.value.uuid = res.data.uuid;
 | 
				
			||||||
 | 
					      captchaImgBase64.value = res.data.img;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  getCaptcha();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 登录处理
 | 
					  /**
 | 
				
			||||||
  const handleLogin = async ({
 | 
					   * 登录
 | 
				
			||||||
    errors,
 | 
					   *
 | 
				
			||||||
    values,
 | 
					   * @param errors 表单验证错误
 | 
				
			||||||
  }: {
 | 
					   * @param values 表单数据
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  const handleLogin = ({ errors, values, }: {
 | 
				
			||||||
    errors: Record<string, ValidatedError> | undefined;
 | 
					    errors: Record<string, ValidatedError> | undefined;
 | 
				
			||||||
    values: Record<string, any>;
 | 
					    values: Record<string, any>;
 | 
				
			||||||
  }) => {
 | 
					  }) => {
 | 
				
			||||||
    if (loading.value) return;
 | 
					    if (loading.value) return;
 | 
				
			||||||
    if (!errors) {
 | 
					    if (!errors) {
 | 
				
			||||||
      setLoading(true);
 | 
					      loading.value = true;
 | 
				
			||||||
      try {
 | 
					      loginStore.login({
 | 
				
			||||||
        await loginStore.login({
 | 
					        username: values.username,
 | 
				
			||||||
          username: values.username,
 | 
					        password: encryptByRsa(values.password) || '',
 | 
				
			||||||
          password: encryptByRsa(values.password) || '',
 | 
					        captcha: values.captcha,
 | 
				
			||||||
          captcha: values.captcha,
 | 
					        uuid: values.uuid
 | 
				
			||||||
          uuid: values.uuid
 | 
					      }).then(() => {
 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        const { redirect, ...othersQuery } = router.currentRoute.value.query;
 | 
					        const { redirect, ...othersQuery } = router.currentRoute.value.query;
 | 
				
			||||||
        router.push({
 | 
					        router.push({
 | 
				
			||||||
          name: (redirect as string) || 'Workplace',
 | 
					          name: (redirect as string) || 'Workplace',
 | 
				
			||||||
@@ -166,21 +143,32 @@
 | 
				
			|||||||
            ...othersQuery,
 | 
					            ...othersQuery,
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        Message.success(t('login.form.login.success'));
 | 
					 | 
				
			||||||
        const { rememberMe } = loginConfig.value;
 | 
					        const { rememberMe } = loginConfig.value;
 | 
				
			||||||
        const { username } = values;
 | 
					        const { username } = values;
 | 
				
			||||||
        loginConfig.value.username = rememberMe ? username : '';
 | 
					        loginConfig.value.username = rememberMe ? username : '';
 | 
				
			||||||
      } catch (err) {
 | 
					        proxy.$message.success(t('login.form.login.success'));
 | 
				
			||||||
        await getCaptcha();
 | 
					      }).catch(() => {
 | 
				
			||||||
      } finally {
 | 
					        getCaptcha();
 | 
				
			||||||
        setLoading(false);
 | 
					      }).finally(() => {
 | 
				
			||||||
      }
 | 
					        loading.value = false;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 记住我
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param value 是否记住我
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  const setRememberMe = (value: boolean) => {
 | 
				
			||||||
 | 
					    loginConfig.value.rememberMe = value;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="less" scoped>
 | 
					<style lang="less" scoped>
 | 
				
			||||||
  .login-form {
 | 
					  .login-form {
 | 
				
			||||||
 | 
					    margin-top: 32px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &-wrapper {
 | 
					    &-wrapper {
 | 
				
			||||||
      width: 320px;
 | 
					      width: 320px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -198,12 +186,6 @@
 | 
				
			|||||||
      line-height: 24px;
 | 
					      line-height: 24px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &-error-msg {
 | 
					 | 
				
			||||||
      height: 32px;
 | 
					 | 
				
			||||||
      color: rgb(var(--red-6));
 | 
					 | 
				
			||||||
      line-height: 32px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    &-captcha img {
 | 
					    &-captcha img {
 | 
				
			||||||
      width: 111px;
 | 
					      width: 111px;
 | 
				
			||||||
      height: 36px;
 | 
					      height: 36px;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,7 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
    <div class="logo">
 | 
					    <div class="logo">
 | 
				
			||||||
      <img
 | 
					      <img src="/logo.svg" alt="logo" />
 | 
				
			||||||
        alt="logo"
 | 
					 | 
				
			||||||
        src="/logo.svg"
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <div class="logo-text">{{ $t('title') }}</div>
 | 
					      <div class="logo-text">{{ $t('title') }}</div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <LoginBanner />
 | 
					    <LoginBanner />
 | 
				
			||||||
@@ -67,9 +64,7 @@
 | 
				
			|||||||
      font-size: 20px;
 | 
					      font-size: 20px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
</style>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="less" scoped>
 | 
					 | 
				
			||||||
  @media (max-width: @screen-lg) {
 | 
					  @media (max-width: @screen-lg) {
 | 
				
			||||||
    .container {
 | 
					    .container {
 | 
				
			||||||
      .banner {
 | 
					      .banner {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user