login.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. <script setup lang="ts">
  2. import type { AccountFormState } from '@/model';
  3. import { accountMethod, getMenusMethod, loginMethod } from '@/request/api/account.api';
  4. import router from '@/router';
  5. import { useAccountStore } from '@/stores';
  6. import { LockOutlined, UserOutlined } from '@ant-design/icons-vue';
  7. import { invalidateCache } from 'alova';
  8. import { useSerialRequest } from 'alova/client';
  9. import { Form } from 'ant-design-vue';
  10. import { h } from 'vue';
  11. const formState = reactive<AccountFormState>({
  12. username: '',
  13. password: '',
  14. remember: false,
  15. });
  16. const rulesRef = reactive({
  17. username: [ { required: true, message: '请输入账号' } ],
  18. password: [ { required: true, message: '请输入密码' } ],
  19. });
  20. const { validate, validateInfos } = Form.useForm(formState, rulesRef);
  21. const formWrapper = ref<HTMLElement>();
  22. const { loading, error, send } = useSerialRequest([
  23. () => loginMethod(formState),
  24. token => accountMethod(token),
  25. data => getMenusMethod(data),
  26. ], { immediate: false }).onSuccess(
  27. ({ data }) => {
  28. // console.log(data,"登录成功");
  29. localStorage.setItem("deptId",data?.user?.deptId);
  30. const path = useAccountStore().$init(data);
  31. nextTick(() => router.replace({ path }));
  32. },
  33. );
  34. async function handle() {
  35. loading.value = true;
  36. try {
  37. await validate();
  38. await invalidateCache()
  39. await send();
  40. } catch ( error: any ) {
  41. const field = error?.errorFields?.[ 0 ];
  42. if ( field ) formWrapper.value?.querySelector<HTMLInputElement>(`#${ field.name }`)?.focus();
  43. }
  44. loading.value = false;
  45. }
  46. </script>
  47. <template>
  48. <div class="page-container flex flex-col h-vh w-vw">
  49. <header class="flex-none h-60px text-center">
  50. <img src="@/assets/images/name.png" alt="中医健康管家" class="h-full">
  51. </header>
  52. <main class="flex-auto flex justify-center items-center">
  53. <div ref="formWrapper" class="form-wrapper flex flex-col justify-center">
  54. <a-form layout="vertical" @submit="handle">
  55. <a-form-item label="账号" html-for="username" v-bind="validateInfos.username">
  56. <a-input id="username" size="large" :prefix="h(UserOutlined)" :disabled="loading"
  57. v-model:value="formState.username"
  58. />
  59. </a-form-item>
  60. <a-form-item label="密码" html-for="password" v-bind="validateInfos.password">
  61. <a-input-password id="password" size="large" :prefix="h(LockOutlined)" :disabled="loading"
  62. v-model:value="formState.password"
  63. />
  64. </a-form-item>
  65. <a-form-item style="margin-top: 38px;" :help="error?.message" validate-status="error">
  66. <a-button type="primary" block html-type="submit" :loading="loading">登录</a-button>
  67. </a-form-item>
  68. </a-form>
  69. </div>
  70. </main>
  71. </div>
  72. </template>
  73. <style scoped lang="scss">
  74. .page-container {
  75. background: #000 url("@/assets/images/page-login.bg.jpg") no-repeat center center / cover;
  76. }
  77. .form-wrapper {
  78. width: calc(100vmin - 60px * 2);
  79. height: calc(100vmin - 60px * 2);
  80. max-width: 800px;
  81. max-height: 800px;
  82. padding: 10%;
  83. background: url("@/assets/images/page-login-form.bg.png") no-repeat center / contain;
  84. :deep(.ant-form-item-label) {
  85. color: #fff;
  86. font-size: 18px;
  87. label {
  88. color: inherit;
  89. font-size: inherit;
  90. }
  91. }
  92. }
  93. </style>