Newer
Older
hard-panel / panel / frontend / src / pages / LoginPage.vue
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { GnAlert, GnButton, GnCard, GnInput } from 'gnexus-ui-kit/vue'

import { setToken } from '../api.js'

const router = useRouter()
const route = useRoute()

const token = ref('')
const error = ref('')
const loading = ref(false)

async function submit() {
  if (!token.value.trim() || loading.value) return
  loading.value = true
  error.value = ''
  try {
    // проверяем токен запросом к API
    const response = await fetch('/api/v1/servers', {
      headers: { Authorization: `Bearer ${token.value.trim()}` },
    })
    if (!response.ok) {
      error.value = 'Неверный токен'
      return
    }
    setToken(token.value.trim())
    router.push(route.query.redirect || '/')
  } finally {
    loading.value = false
  }
}
</script>

<template>
  <div class="login-wrap">
    <GnCard title="GHard Monitor">
      <p class="login-hint">Админ-токен панели (GHARD_ADMIN_TOKEN)</p>
      <form @submit.prevent="submit">
        <GnInput
          v-model="token"
          type="password"
          label="Токен"
          icon="ph-lock-key"
          placeholder="ghard-..."
          autocomplete="current-password"
          :state="error ? 'error' : ''"
          :help="error"
        />
        <GnButton
          type="submit"
          variant="secondary"
          class="login-btn"
          :loading="loading"
        >
          Войти
        </GnButton>
      </form>
      <GnAlert v-if="error" variant="danger" style="margin-top: 12px">
        {{ error }}
      </GnAlert>
    </GnCard>
  </div>
</template>

<style scoped>
/* layout-обёртка, без стилей кита */
.login-wrap {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
}
.login-wrap form {
  display: grid;
  gap: 16px;
}
.login-hint {
  margin: 0 0 16px;
  opacity: 0.7;
  font-size: 14px;
}
.login-btn {
  width: 100%;
}
</style>