auth base

This commit is contained in:
grey-cat-1908 2024-08-23 09:54:47 +03:00
parent b99f1d403d
commit 854a9aaa97
10 changed files with 214 additions and 110 deletions

View file

@ -1,6 +1,7 @@
<template>
<div class="root" id="root">
<Header />
<Auth />
<router-view v-slot="{ Component }">
<div class="layout">
<transition name="page" mode="out-in">
@ -13,6 +14,7 @@
<script setup lang="ts">
import Header from '@/components/Header.vue'
import Auth from '@/components/Auth.vue'
</script>
<style scoped>

53
src/components/Auth.vue Normal file
View file

@ -0,0 +1,53 @@
<script setup lang="ts">
import { makeAPIRequest } from '@/utils/http'
import { useAuthStore } from '@/stores/auth'
import { ref } from 'vue'
import router from '@/router'
const authStore = useAuthStore()
const username = ref('')
const password = ref('')
const authError = ref('')
async function submitForm() {
const data = await makeAPIRequest(
'/user/login',
'POST',
{},
{ username: username.value, password: password.value }
)
if (data.status === 200) {
authError.value = ''
localStorage.setItem('auth_token', data.json.token)
authStore.authDialogOpened = false
await authStore.prepareStore()
await router.push('/')
} else {
authError.value = 'Авторизация не удалась.'
}
}
</script>
<template>
<div v-if="authStore.authDialogOpened">
<button @click="authStore.authDialogOpened = false">x</button>
<form @submit.prevent="submitForm">
<div>
<div>Имя пользователя</div>
<input type="text" id="username" v-model="username" placeholder="Введи имя пользователя" />
</div>
<div>
<div>Пароль</div>
<input type="password" id="password" v-model="password" placeholder="Введи пароль" />
</div>
<p v-if="authError.length > 0">{{ authError }}</p>
<button type="submit">Войти</button>
</form>
</div>
</template>
<style scoped></style>

View file

@ -1,9 +1,23 @@
<script setup lang="ts">
import { getTitle } from '@/utils/env'
import { useAuthStore } from '@/stores/auth'
const authStore = useAuthStore()
</script>
<template>
<h1>{{ getTitle() }}</h1>
<div v-if="authStore.isAuthorized">
<button type="button">
{{ authStore.user.username }}
</button>
<button type="button" @click="authStore.logout">leave</button>
</div>
<div v-else>
<button type="button" @click="authStore.authDialogOpened = !authStore.authDialogOpened">
Войти
</button>
</div>
</template>
<style scoped></style>

View file

@ -7,18 +7,16 @@
<div class="rating-options">
<label v-for="n in range" :key="n" class="rating-option">
<input
type="radio"
:value="n"
v-model="selectedValue"
:required="isRequired"
@change="updateValue"
type="radio"
:value="n"
v-model="selectedValue"
:required="isRequired"
@change="updateValue"
/>
<span>{{ n }}</span>
</label>
</div>
<button v-if="selectedValue !== null" @click="cancelSelection">
Отменить выбор
</button>
<button v-if="selectedValue !== null" @click="cancelSelection">Отменить выбор</button>
</div>
</template>
@ -56,7 +54,7 @@ const emit = defineEmits(['input'])
const selectedValue = ref(props.value)
const range = computed(() => {
return Array.from({length: props.max - props.min + 1}, (_, i) => props.min + i)
return Array.from({ length: props.max - props.min + 1 }, (_, i) => props.min + i)
})
function updateValue() {

View file

@ -2,11 +2,11 @@
<div class="selector-component">
<div class="options">
<div
v-for="(option, index) in options"
:key="index"
class="option"
@click="toggleSelection(index)"
:class="{ selected: isSelected(index) }"
v-for="(option, index) in options"
:key="index"
class="option"
@click="toggleSelection(index)"
:class="{ selected: isSelected(index) }"
>
<span>{{ option.label }}</span>
</div>

View file

@ -1,12 +1,12 @@
<template>
<div class="text-question-component">
<input
type="text"
v-model="inputValue"
:maxlength="maxLength"
:required="isRequired"
@input="validateInput"
@blur="validateInput"
type="text"
v-model="inputValue"
:maxlength="maxLength"
:required="isRequired"
@input="validateInput"
@blur="validateInput"
/>
<div v-if="error" class="error">{{ error }}</div>
</div>
@ -50,48 +50,48 @@ function validateTIN(value) {
if (len === 10) {
const checksum =
((2 * digits[0] +
4 * digits[1] +
10 * digits[2] +
3 * digits[3] +
5 * digits[4] +
9 * digits[5] +
4 * digits[6] +
6 * digits[7] +
8 * digits[8]) %
11) %
10
((2 * digits[0] +
4 * digits[1] +
10 * digits[2] +
3 * digits[3] +
5 * digits[4] +
9 * digits[5] +
4 * digits[6] +
6 * digits[7] +
8 * digits[8]) %
11) %
10
return digits[9] === checksum
}
if (len === 12) {
const checksum1 =
((7 * digits[0] +
2 * digits[1] +
4 * digits[2] +
10 * digits[3] +
3 * digits[4] +
5 * digits[5] +
9 * digits[6] +
4 * digits[7] +
6 * digits[8] +
8 * digits[9]) %
11) %
10
((7 * digits[0] +
2 * digits[1] +
4 * digits[2] +
10 * digits[3] +
3 * digits[4] +
5 * digits[5] +
9 * digits[6] +
4 * digits[7] +
6 * digits[8] +
8 * digits[9]) %
11) %
10
const checksum2 =
((3 * digits[0] +
7 * digits[1] +
2 * digits[2] +
4 * digits[3] +
10 * digits[4] +
3 * digits[5] +
5 * digits[6] +
9 * digits[7] +
4 * digits[8] +
6 * digits[9] +
8 * digits[10]) %
11) %
10
((3 * digits[0] +
7 * digits[1] +
2 * digits[2] +
4 * digits[3] +
10 * digits[4] +
3 * digits[5] +
5 * digits[6] +
9 * digits[7] +
4 * digits[8] +
6 * digits[9] +
8 * digits[10]) %
11) %
10
return digits[10] === checksum1 && digits[11] === checksum2
}

44
src/stores/auth.ts Normal file
View file

@ -0,0 +1,44 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { makeAPIRequest } from '@/utils/http'
export const useAuthStore = defineStore('auth', () => {
const authDialogOpened = ref(false)
const isAuthorized = ref(false)
const user = ref({
id: 0,
username: ''
})
const prepareStore = async () => {
if (localStorage.getItem('auth_token')) {
const data = await makeAPIRequest('/user/get', 'POST', {}, {}, true)
if (data.status !== 200) {
localStorage.removeItem('auth_token')
return (isAuthorized.value = false)
} else {
isAuthorized.value = true
user.value = {
id: data.json.id,
username: data.json.username
}
}
} else {
isAuthorized.value = false
}
}
const logout = () => {
localStorage.removeItem('auth_token')
isAuthorized.value = false
authDialogOpened.value = false
user.value = {
id: 0,
username: ''
}
}
prepareStore()
return { authDialogOpened, isAuthorized, user, prepareStore, logout }
})

View file

@ -1,10 +1,10 @@
export function makeAPIRequest(
path: string = '',
method: string = 'GET',
query: any = {},
body: any = {},
useAuthorization: boolean = false
): Promise < any > {
path: string = '',
method: string = 'GET',
query: any = {},
body: any = {},
useAuthorization: boolean = false
): Promise<any> {
return new Promise(async (resolve, _) => {
let options: any = {
method,
@ -12,7 +12,7 @@ export function makeAPIRequest(
'Content-Type': 'application/json'
}
}
if (useAuthorization) options.headers.Authorization = `${localStorage.getItem('auth_token')}`
if (useAuthorization) options.headers['x-token'] = `${localStorage.getItem('auth_token')}`
if (method !== 'GET') {
options.body = JSON.stringify(body)
@ -24,17 +24,17 @@ export function makeAPIRequest(
}
await fetch(finalPath, options)
.then(async (r) => {
return resolve({
json: await r.json(),
status: r.status
})
.then(async (r) => {
return resolve({
json: await r.json(),
status: r.status
})
.catch((err) => {
console.error(err)
return resolve({
error: 'CRITICAL_ERROR'
})
})
.catch((err) => {
console.error(err)
return resolve({
error: 'CRITICAL_ERROR'
})
})
})
}

View file

@ -1,5 +0,0 @@
<script setup lang="ts"></script>
<template></template>
<style scoped></style>

View file

@ -46,12 +46,12 @@ async function submitForm() {
await prepareNewPage()
} else {
await makeAPIRequest(
'/answer/create',
'POST',
{ form_id: Number(route.params.id) },
{
values: Array.from(Object.keys(answers.value).map((val) => answers.value[val]))
}
'/answer/create',
'POST',
{ form_id: Number(route.params.id) },
{
values: Array.from(Object.keys(answers.value).map((val) => answers.value[val]))
}
)
isSent.value = true
}
@ -83,37 +83,35 @@ onMounted(async () => {
<h3>{{ question.label }}</h3>
<p>{{ question.description }}</p>
<TextQuestion
v-if="question.question_type === 1"
:minLength="question.min_length"
:maxLength="question.max_length"
:validator="question.validator"
:isRequired="question.required"
v-model="answers[question.id].value"
@input="answers[question.id].value = $event"
v-if="question.question_type === 1"
:minLength="question.min_length"
:maxLength="question.max_length"
:validator="question.validator"
:isRequired="question.required"
v-model="answers[question.id].value"
@input="answers[question.id].value = $event"
/>
<SelectorQuestion
v-if="question.question_type === 2"
:minValues="question.min_values"
:maxValues="question.max_values"
:options="question.options"
:isRequired="question.required"
v-model="answers[question.id].values"
@input="answers[question.id].values = $event"
v-if="question.question_type === 2"
:minValues="question.min_values"
:maxValues="question.max_values"
:options="question.options"
:isRequired="question.required"
v-model="answers[question.id].values"
@input="answers[question.id].values = $event"
/>
<Scale
v-if="question.question_type === 3"
:min="question.min_value"
:max="question.max_value"
:minLabel="question.min_label"
:maxLabel="question.max_label"
:isRequired="question.required"
v-model="answers[question.id].value"
@input="answers[question.id].value = $event"
v-if="question.question_type === 3"
:min="question.min_value"
:max="question.max_value"
:minLabel="question.min_label"
:maxLabel="question.max_label"
:isRequired="question.required"
v-model="answers[question.id].value"
@input="answers[question.id].value = $event"
/>
</div>
<button type="submit" v-if="currentPageNumber === pageCount - 1">
Отправить
</button>
<button type="submit" v-if="currentPageNumber === pageCount - 1">Отправить</button>
<button type="submit" v-else>Дальше</button>
</form>
</div>