github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/static_source/admin/src/views/PasswordReset/PasswordReset.vue (about)

     1  <script setup lang="ts">
     2  import {useI18n} from '@/hooks/web/useI18n'
     3  import {underlineToHump} from '@/utils'
     4  import {useAppStore} from '@/store/modules/app'
     5  import {useDesign} from '@/hooks/web/useDesign'
     6  import {reactive, ref, unref} from 'vue'
     7  import {FormSchema} from "@/types/form";
     8  import {ElButton, ElCheckbox, ElLink, ElInput} from 'element-plus'
     9  import api from "@/api/api";
    10  import {useRouter} from "vue-router";
    11  import {useForm} from "@/hooks/web/useForm";
    12  import {useValidator} from "@/hooks/web/useValidator";
    13  import {Form} from '@/components/Form'
    14  
    15  const {getPrefixCls} = useDesign()
    16  const prefixCls = getPrefixCls('login')
    17  const appStore = useAppStore()
    18  const {t} = useI18n()
    19  const {required} = useValidator()
    20  const {register, elFormRef, methods} = useForm()
    21  const {currentRoute, addRoute, push} = useRouter()
    22  
    23  const newRequestSchema = reactive<FormSchema[]>([
    24    {
    25      field: 'title',
    26      colProps: {
    27        span: 24
    28      }
    29    },
    30    {
    31      field: 'username',
    32      label: t('login.username'),
    33      value: '',
    34      component: 'Input',
    35      colProps: {
    36        span: 24
    37      },
    38      componentProps: {
    39        placeholder: t('login.usernamePlaceholder')
    40      }
    41    },
    42    {
    43      field: 'restore',
    44      colProps: {
    45        span: 24
    46      }
    47    }
    48  ])
    49  const newPasswordSchema = reactive<FormSchema[]>([
    50    {
    51      field: 'title',
    52      colProps: {
    53        span: 24
    54      }
    55    },
    56    {
    57      field: 'password',
    58      label: t('login.password'),
    59      value: 'admin',
    60      component: 'InputPassword',
    61      colProps: {
    62        span: 24
    63      },
    64      componentProps: {
    65        style: {
    66          width: '100%'
    67        },
    68        placeholder: t('login.passwordPlaceholder')
    69      }
    70    },
    71    {
    72      field: 'check_password',
    73      label: t('login.checkPassword'),
    74      value: '',
    75      component: 'InputPassword',
    76      colProps: {
    77        span: 24
    78      },
    79      componentProps: {
    80        style: {
    81          width: '100%'
    82        },
    83        strength: true,
    84        placeholder: t('login.passwordPlaceholder')
    85      }
    86    },
    87    {
    88      field: 'update',
    89      colProps: {
    90        span: 24
    91      }
    92    }
    93  ])
    94  const newRequestRules = {
    95    username: [required()],
    96  }
    97  const newPasswordRules = {
    98    password: [required()],
    99    check_password: [required()],
   100  }
   101  
   102  // NEW_REQUEST
   103  // REQUEST_SENDED
   104  // UPDATE_PASSWORD
   105  const state = ref('NEW_REQUEST')
   106  const loading = ref(false)
   107  
   108  if (currentRoute.value.query?.t) {
   109    state.value = 'UPDATE_PASSWORD'
   110  }
   111  
   112  const toLogin = () => {
   113    push('/login')
   114  }
   115  
   116  const requestNewPassword = async () => {
   117    const formRef = unref(elFormRef)
   118    formRef?.validate(async (valid) => {
   119      if (valid) {
   120        try {
   121          loading.value = true
   122          const {getFormData} = methods
   123          const formData = await getFormData()
   124          const {username} = formData
   125          const data = await api.v1.authServicePasswordReset({email: username});
   126          state.value = 'REQUEST_SENDED'
   127          loading.value = false
   128  
   129        } finally {
   130          loading.value = false
   131        }
   132      }
   133    })
   134  }
   135  const updatePassword = async () => {
   136    const formRef = unref(elFormRef)
   137    formRef?.validate(async (valid) => {
   138      if (valid) {
   139        try {
   140          loading.value = true
   141  
   142          const {getFormData} = methods
   143          const formData = await getFormData()
   144          const {password} = formData
   145          const token = currentRoute.value.query.t as string || '';
   146          const data = await api.v1.authServicePasswordReset({newPassword: password, token: token});
   147  
   148          toLogin()
   149        } finally {
   150          loading.value = false
   151        }
   152      }
   153    })
   154  }
   155  
   156  </script>
   157  
   158  <template>
   159    <div
   160        :class="prefixCls"
   161        class="h-[100%] relative <xl:bg-v-dark <sm:px-10px <xl:px-10px <md:px-10px"
   162    >
   163      <div class="relative h-full flex mx-auto">
   164        <div
   165            :class="`${prefixCls}__left flex-1 bg-gray-500 bg-opacity-20 relative p-30px <xl:hidden`"
   166        >
   167  <!--        <div class="flex items-center relative text-white">-->
   168  <!--          <img src="../../assets/svgs/logo-w.svg" alt="" class="w-48px h-48px mr-10px"/>-->
   169  <!--          <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>-->
   170  <!--        </div>-->
   171          <div class="flex justify-center items-center h-[calc(100%-60px)]">
   172            <TransitionGroup
   173                appear
   174                tag="div"
   175                enter-active-class="animate__animated animate__bounceInLeft"
   176            >
   177              <img src="@/assets/svgs/banner-v4.svg" key="1" alt="" class="w-400px" />
   178  <!--            <div class="text-3xl text-white" key="2">{{ t('login.welcome') }}</div>-->
   179  <!--            <div class="mt-5 font-normal text-white text-14px" key="3">-->
   180  <!--              {{ t('login.message') }}-->
   181  <!--            </div>-->
   182            </TransitionGroup>
   183          </div>
   184        </div>
   185        <div class="flex-1 p-30px <sm:p-10px dark:bg-v-dark relative">
   186          <div class="flex justify-between items-center text-white @2xl:justify-end @xl:justify-end">
   187            <div class="flex items-center @2xl:hidden @xl:hidden">
   188              <img src="../../assets/svgs/logo-w.svg" alt="" class="w-48px h-48px mr-10px"/>
   189              <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
   190            </div>
   191  
   192            <div class="flex justify-end items-center space-x-10px">
   193              <ThemeSwitch/>
   194              <LocaleDropdown class="<xl:text-white dark:text-white"/>
   195            </div>
   196          </div>
   197  
   198          <Transition appear enter-active-class="animate__animated animate__bounceInRight">
   199          <div
   200              class="h-full flex items-center m-auto w-[100%] @2xl:max-w-500px @xl:max-w-500px @md:max-w-500px @lg:max-w-500px">
   201  
   202            <div v-if="state==='REQUEST_SENDED'" class="dark:(border-1 border-[var(--el-border-color)] border-solid)" style="padding: 20px">
   203              <p style="padding-bottom: 20px">
   204                Check your email for a link to reset your password. If it doesn’t appear within a few minutes, check your
   205                spam
   206                folder.
   207              </p>
   208              <el-button
   209                  type="primary"
   210                  class="w-[100%]"
   211                  @click="toLogin"
   212              >
   213                {{ $t('login.returnToSignIn') }}
   214              </el-button>
   215            </div>
   216            <div v-else-if="state==='NEW_REQUEST'" class="dark:(border-1 border-[var(--el-border-color)] border-solid)">
   217              <Form
   218                  :schema="newRequestSchema"
   219                  :rules="newRequestRules"
   220                  label-position="top"
   221                  hide-required-asterisk
   222                  size="large"
   223                  @register="register"
   224                  style="margin: 20px"
   225              >
   226  
   227                <template #title>
   228                  <h2 class="text-2xl font-bold text-center w-[100%]">{{ t('login.restorePassword') }}</h2>
   229                </template>
   230  
   231                <template #code="form">
   232                  <div class="w-[100%] flex">
   233                    <ElInput v-model="form['code']" :placeholder="t('login.codePlaceholder')"/>
   234                  </div>
   235                </template>
   236  
   237                <template #restore>
   238                  <div class="w-[100%]">
   239                    <ElButton type="primary" class="w-[100%]" :loading="loading" @click="requestNewPassword">
   240                      {{ t('login.restorePassword') }}
   241                    </ElButton>
   242                  </div>
   243                  <div class="w-[100%] mt-15px">
   244                    <ElButton class="w-[100%]" @click="toLogin">
   245                      {{ t('login.hasUser') }}
   246                    </ElButton>
   247                  </div>
   248                </template>
   249              </Form>
   250  
   251            </div>
   252            <div v-else-if="state==='UPDATE_PASSWORD'"
   253                 class="dark:(border-1 border-[var(--el-border-color)] border-solid)">
   254  
   255              <Form
   256                  :schema="newPasswordSchema"
   257                  :rules="newPasswordRules"
   258                  label-position="top"
   259                  hide-required-asterisk
   260                  size="large"
   261                  @register="register"
   262                  style="margin: 20px"
   263              >
   264  
   265                <template #title>
   266                  <h2 class="text-2xl font-bold text-center w-[100%]">{{ t('login.updatePassword') }}</h2>
   267                </template>
   268  
   269                <template #code="form">
   270                  <div class="w-[100%] flex">
   271                    <ElInput v-model="form['code']" :placeholder="t('login.codePlaceholder')"/>
   272                  </div>
   273                </template>
   274  
   275                <template #update>
   276                  <div class="w-[100%]">
   277                    <ElButton type="primary" class="w-[100%]" :loading="loading" @click="updatePassword">
   278                      {{ t('main.update') }}
   279                    </ElButton>
   280                  </div>
   281                </template>
   282              </Form>
   283  
   284            </div>
   285  
   286          </div>
   287          </Transition>
   288  
   289        </div>
   290      </div>
   291    </div>
   292  </template>
   293  
   294  <style lang="less" scoped>
   295  @prefix-cls: ~'@{namespace}-login';
   296  
   297  .@{prefix-cls} {
   298    &__left {
   299      &::before {
   300        position: absolute;
   301        top: 0;
   302        left: 0;
   303        z-index: -1;
   304        width: 100%;
   305        height: 100%;
   306        background-image: url('@/assets/svgs/login-bg.svg');
   307        background-position: center;
   308        background-repeat: no-repeat;
   309        content: '';
   310      }
   311    }
   312  }
   313  </style>