login is ready
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<h1 class="text-2xl font-semibold">New Dashboard</h1>
|
||||
<p class="text-color-secondary">Страница пока пустая.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DashboardNew'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,194 @@
|
||||
<script setup>
|
||||
import AdminService from '@/service/AdminService';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
const createEmail = ref('');
|
||||
const createPassword = ref('');
|
||||
const createLoading = ref(false);
|
||||
const createError = ref('');
|
||||
const createSuccess = ref('');
|
||||
|
||||
const roles = ref([]);
|
||||
const assignEmail = ref('');
|
||||
const assignRoles = ref([]);
|
||||
const assignLoading = ref(false);
|
||||
const assignError = ref('');
|
||||
const assignSuccess = ref('');
|
||||
|
||||
const usersPage = ref({ content: [], totalElements: 0, number: 0, size: 10 });
|
||||
const tableLoading = ref(false);
|
||||
|
||||
const editDialogVisible = ref(false);
|
||||
const editForm = ref({ id: null, email: '', password: '', roles: [] });
|
||||
const editSaving = ref(false);
|
||||
const editError = ref('');
|
||||
|
||||
async function loadRoles() {
|
||||
try {
|
||||
roles.value = await AdminService.getRoles();
|
||||
} catch (e) {
|
||||
roles.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function loadUsers(page = 0, size = usersPage.value.size || 10) {
|
||||
tableLoading.value = true;
|
||||
try {
|
||||
usersPage.value = await AdminService.listUsers(page, size);
|
||||
} catch (e) {
|
||||
usersPage.value = { content: [], totalElements: 0, number: 0, size };
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([loadRoles(), loadUsers(0, 10)]);
|
||||
});
|
||||
|
||||
async function onCreateUser() {
|
||||
createError.value = '';
|
||||
createSuccess.value = '';
|
||||
createLoading.value = true;
|
||||
try {
|
||||
await AdminService.createUser(createEmail.value.trim().toLowerCase(), createPassword.value);
|
||||
createSuccess.value = 'Пользователь создан';
|
||||
createEmail.value = '';
|
||||
createPassword.value = '';
|
||||
await loadUsers(usersPage.value.number, usersPage.value.size);
|
||||
} catch (e) {
|
||||
createError.value = e?.message || 'Ошибка создания пользователя';
|
||||
} finally {
|
||||
createLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function onAssignRoles() {
|
||||
assignError.value = '';
|
||||
assignSuccess.value = '';
|
||||
assignLoading.value = true;
|
||||
try {
|
||||
await AdminService.assignRoles(assignEmail.value.trim().toLowerCase(), assignRoles.value);
|
||||
assignSuccess.value = 'Роли обновлены';
|
||||
await loadUsers(usersPage.value.number, usersPage.value.size);
|
||||
} catch (e) {
|
||||
assignError.value = e?.message || 'Ошибка назначения ролей';
|
||||
} finally {
|
||||
assignLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openEdit(user) {
|
||||
editError.value = '';
|
||||
editForm.value = {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
password: '',
|
||||
roles: String(user.roles || '')
|
||||
.split(',')
|
||||
.map((r) => r.trim())
|
||||
.filter((r) => r.length > 0)
|
||||
};
|
||||
editDialogVisible.value = true;
|
||||
}
|
||||
|
||||
async function saveEdit() {
|
||||
editError.value = '';
|
||||
editSaving.value = true;
|
||||
try {
|
||||
const payload = { id: editForm.value.id };
|
||||
if (editForm.value.email && editForm.value.email !== '') payload.email = editForm.value.email;
|
||||
if (editForm.value.password && editForm.value.password !== '') payload.password = editForm.value.password;
|
||||
if (Array.isArray(editForm.value.roles)) payload.roles = editForm.value.roles;
|
||||
await AdminService.updateUser(payload);
|
||||
editDialogVisible.value = false;
|
||||
await loadUsers(usersPage.value.number, usersPage.value.size);
|
||||
} catch (e) {
|
||||
editError.value = e?.message || 'Ошибка сохранения';
|
||||
} finally {
|
||||
editSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function removeUser(user) {
|
||||
if (!confirm('Удалить пользователя?')) return;
|
||||
try {
|
||||
await AdminService.deleteUser(user.id);
|
||||
await loadUsers(usersPage.value.number, usersPage.value.size);
|
||||
} catch (e) {
|
||||
// ignore for now
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 p-6">
|
||||
<div class="bg-surface-0 dark:bg-surface-900 p-6 rounded-md">
|
||||
<h2 class="text-xl font-semibold mb-4">Создать пользователя</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Email</label>
|
||||
<InputText v-model="createEmail" placeholder="user@example.com" class="w-full" />
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Пароль</label>
|
||||
<Password v-model="createPassword" :feedback="false" placeholder="Пароль" fluid />
|
||||
</div>
|
||||
<div v-if="createError" class="text-red-500 text-sm mb-2">{{ createError }}</div>
|
||||
<div v-if="createSuccess" class="text-green-500 text-sm mb-2">{{ createSuccess }}</div>
|
||||
<Button :loading="createLoading" label="Создать" @click="onCreateUser" />
|
||||
</div>
|
||||
|
||||
<div class="bg-surface-0 dark:bg-surface-900 p-6 rounded-md">
|
||||
<h2 class="text-xl font-semibold mb-4">Назначить роли</h2>
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Email</label>
|
||||
<InputText v-model="assignEmail" placeholder="user@example.com" class="w-full" />
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="block mb-2">Роли</label>
|
||||
<MultiSelect v-model="assignRoles" :options="roles" class="w-full" display="chip" />
|
||||
</div>
|
||||
<div v-if="assignError" class="text-red-500 text-sm mb-2">{{ assignError }}</div>
|
||||
<div v-if="assignSuccess" class="text-green-500 text-sm mb-2">{{ assignSuccess }}</div>
|
||||
<Button :loading="assignLoading" label="Назначить" @click="onAssignRoles" />
|
||||
</div>
|
||||
|
||||
<div class="bg-surface-0 dark:bg-surface-900 p-6 rounded-md lg:col-span-3">
|
||||
<h2 class="text-xl font-semibold mb-4">Пользователи</h2>
|
||||
<DataTable :value="usersPage.content" :loading="tableLoading" tableStyle="min-width: 50rem">
|
||||
<Column field="id" header="ID" style="width: 6rem" />
|
||||
<Column field="email" header="Email" />
|
||||
<Column field="roles" header="Роли" />
|
||||
<Column header="Действия" style="width: 16rem">
|
||||
<template #body="{ data }">
|
||||
<Button label="Редактировать" size="small" class="mr-2" @click="openEdit(data)" />
|
||||
<Button label="Удалить" size="small" severity="danger" @click="removeUser(data)" />
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
<div class="flex justify-end mt-4">
|
||||
<Paginator :rows="usersPage.size" :totalRecords="usersPage.totalElements" :first="usersPage.number * usersPage.size" @page="(e) => loadUsers(e.page, e.rows)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog v-model:visible="editDialogVisible" modal header="Редактировать пользователя" :style="{ width: '30rem' }">
|
||||
<div class="mb-3">
|
||||
<label class="block mb-2">Email</label>
|
||||
<InputText v-model="editForm.email" class="w-full" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="block mb-2">Пароль (опционально)</label>
|
||||
<Password v-model="editForm.password" :feedback="false" toggleMask fluid />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="block mb-2">Роли</label>
|
||||
<MultiSelect v-model="editForm.roles" :options="roles" class="w-full" display="chip" />
|
||||
</div>
|
||||
<div v-if="editError" class="text-red-500 text-sm mb-2">{{ editError }}</div>
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button label="Отмена" severity="secondary" @click="editDialogVisible = false" />
|
||||
<Button :loading="editSaving" label="Сохранить" @click="saveEdit" />
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="font-semibold text-2xl mb-4">Documentation</div>
|
||||
<div class="font-semibold text-xl mb-4">Get Started</div>
|
||||
<p class="text-lg mb-4">
|
||||
Sakai is an application template for Vue based on the <a href="https://github.com/vuejs/create-vue" class="font-medium text-primary hover:underline">create-vue</a>, the recommended way to start a <strong>Vite-powered</strong> Vue
|
||||
KonturAI is an application template for Vue based on the <a href="https://github.com/vuejs/create-vue" class="font-medium text-primary hover:underline">create-vue</a>, the recommended way to start a <strong>Vite-powered</strong> Vue
|
||||
projects. To get started, clone the <a href="https://github.com/primefaces/sakai-vue" class="font-medium text-primary hover:underline">repository</a> from GitHub and install the dependencies with npm or yarn.
|
||||
</p>
|
||||
<pre class="app-code">
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
<script setup>
|
||||
import FloatingConfigurator from '@/components/FloatingConfigurator.vue';
|
||||
import AuthService from '@/service/AuthService';
|
||||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
const email = ref('');
|
||||
const password = ref('');
|
||||
const checked = ref(false);
|
||||
const loading = ref(false);
|
||||
const errorMessage = ref('');
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
async function onSubmit() {
|
||||
errorMessage.value = '';
|
||||
loading.value = true;
|
||||
try {
|
||||
await AuthService.signin(email.value.trim().toLowerCase(), password.value);
|
||||
const redirect = (route.query.redirect && String(route.query.redirect)) || '/';
|
||||
router.replace(redirect);
|
||||
} catch (e) {
|
||||
errorMessage.value = e?.message || 'Ошибка входа';
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -31,7 +52,7 @@ const checked = ref(false);
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">Welcome to PrimeLand!</div>
|
||||
<div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">Welcome to Konturai!</div>
|
||||
<span class="text-muted-color font-medium">Sign in to continue</span>
|
||||
</div>
|
||||
|
||||
@@ -49,7 +70,8 @@ const checked = ref(false);
|
||||
</div>
|
||||
<span class="font-medium no-underline ml-2 text-right cursor-pointer text-primary">Forgot password?</span>
|
||||
</div>
|
||||
<Button label="Sign In" class="w-full" as="router-link" to="/"></Button>
|
||||
<div v-if="errorMessage" class="text-red-500 text-sm mb-4">{{ errorMessage }}</div>
|
||||
<Button :loading="loading" label="Sign In" class="w-full" @click="onSubmit"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user