diff --git a/WEB/src/api/users/changeUserPassword.js b/WEB/src/api/users/changeUserPassword.js new file mode 100644 index 0000000..c53c041 --- /dev/null +++ b/WEB/src/api/users/changeUserPassword.js @@ -0,0 +1,27 @@ +import axios from "axios"; +import CONFIG from "@/core/config.js"; + +const changeUserPassword = async (userId, newPasswordData) => { + try { + const token = localStorage.getItem("access_token"); + const response = await axios.patch( + `${CONFIG.BASE_URL}/users/${userId}/password`, + newPasswordData, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + return response.data; + } catch (error) { + if (error.response?.status === 400) { + throw new Error(error.response.data.detail); + } else if (error.response?.status === 403) { + throw new Error("Доступ запрещён (403)"); + } + throw new Error(error.message); + } +}; + +export default changeUserPassword; \ No newline at end of file diff --git a/WEB/src/api/users/getUsers.js b/WEB/src/api/users/getUsers.js deleted file mode 100644 index 5411f49..0000000 --- a/WEB/src/api/users/getUsers.js +++ /dev/null @@ -1,18 +0,0 @@ -import axios from "axios"; -import CONFIG from "@/core/config.js"; - -const fetchUsers = async () => { - try { - const response = await axios.get(`${CONFIG.BASE_URL}/users`, { - withCredentials: true, - }); - return response.data; - } catch (error) { - if (error.response?.status === 401) { - throw new Error("Нет доступа к пользователям (401)"); - } - throw new Error(error.message); - } -}; - -export default fetchUsers; diff --git a/WEB/src/api/users/registerUser.js b/WEB/src/api/users/registerUser.js new file mode 100644 index 0000000..462f85e --- /dev/null +++ b/WEB/src/api/users/registerUser.js @@ -0,0 +1,19 @@ +import axios from "axios"; +import CONFIG from "@/core/config.js"; + +const registerUser = async (userData) => { + try { + const response = await axios.post( + `${CONFIG.BASE_URL}/users/register`, + userData + ); + return response.data; + } catch (error) { + if (error.response?.status === 400) { + throw new Error(error.response.data.detail); + } + throw new Error(error.message); + } +}; + +export default registerUser; \ No newline at end of file diff --git a/WEB/src/pages/AdminPage.vue b/WEB/src/pages/AdminPage.vue index b4e3209..80f6cc5 100644 --- a/WEB/src/pages/AdminPage.vue +++ b/WEB/src/pages/AdminPage.vue @@ -143,6 +143,7 @@ + @@ -469,6 +470,9 @@ import { ref, watch, onMounted, onBeforeUnmount } from 'vue' import { Notify, useQuasar } from 'quasar' +import registerUser from '@/api/users/registerUser.js' +import changePassword from '@/api/users/changeUserPassword.js' + import fetchTeams from '@/api/teams/getTeams.js' import updateTeam from '@/api/teams/updateTeam.js' import deleteTeamById from '@/api/teams/deleteTeam.js' @@ -489,8 +493,6 @@ import updateContest from '@/api/contests/updateContest.js' import deleteContestById from '@/api/contests/deleteContest.js' import createContest from '@/api/contests/createContest.js' -import CONFIG from '@/core/config.js' - import getProfilePhotosByProfileId from '@/api/profiles/profile_photos/getPhotoFileById.js' import uploadProfilePhoto from '@/api/profiles/profile_photos/uploadProfilePhoto.js' import deleteProfilePhoto from '@/api/profiles/profile_photos/deletePhoto.js' @@ -510,8 +512,9 @@ import getProjectFiles from '@/api/projects/project_files/getProjectFiles.js' import uploadProjectFile from '@/api/projects/project_files/uploadProjectFile.js' import deleteProjectFile from '@/api/projects/project_files/deleteProjectFile.js' import downloadProjectFile from '@/api/projects/project_files/downloadProjectFile.js' -import router from "@/router/index.js"; +import router from "@/router/index.js"; +import CONFIG from '@/core/config.js' const $q = useQuasar() @@ -537,6 +540,7 @@ const teamColumns = [ { name: 'description', label: 'Описание', field: 'description', sortable: true }, { name: 'logo', label: 'Логотип', field: 'logo', sortable: true }, { name: 'git_url', label: 'Git URL', field: 'git_url', sortable: true }, + { name: 'is_active', label: 'Активна', field: 'is_active', sortable: true }, ] const projects = ref([]) @@ -960,7 +964,7 @@ function openEdit(type, row) { dialogData.value = JSON.parse(JSON.stringify(row)) } else { if (type === 'teams') { - dialogData.value = { title: '', description: '', logo: '', git_url: '' } + dialogData.value = { title: '', description: '', logo: '', git_url: '', is_active: '' } } else if (type === 'projects') { dialogData.value = { title: '', description: '', repository_url: '' } projectFiles.value = []; diff --git a/WEB/src/pages/ContestDetailPage.vue b/WEB/src/pages/ContestDetailPage.vue index a4d329c..27e182e 100644 --- a/WEB/src/pages/ContestDetailPage.vue +++ b/WEB/src/pages/ContestDetailPage.vue @@ -80,7 +80,7 @@ - Файлы + Файлы конкурса @@ -100,45 +100,48 @@ - - - Участники конкурса - - - - - - - - - - - {{ member.name }} - {{ member.role }} - - + - + - Репозиторий решения - + Информация о проекте + + + Описание проекта + {{ contest.project_description }} + + + + Репозиторий проекта {{ contest.repository_url }} + + + Файлы проекта + + + + + + + {{ file.name }} + {{ file.description }} + + + + + + + + @@ -197,6 +200,11 @@ async function fetchContestDetails(id) { description: 'Ежегодный хакатон для стартапов, где команды соревнуются в создании инновационных решений за короткий период времени. Фокус на Web3 и AI технологиях.', web_url: 'https://example.com/hackathon2024', repository_url: 'https://github.com/my-team/hackathon2024-solution', + project_description: 'Проект представляет собой децентрализованное приложение для управления задачами, использующее блокчейн для обеспечения прозрачности и искусственный интеллект для автоматического распределения задач между участниками команды.', + project_files: [ + { id: 101, name: 'Техническое задание.pdf', description: 'Полное описание требований', url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' }, + { id: 102, name: 'Архитектура системы.pptx', description: 'Схема взаимодействия модулей', url: 'https://file-examples.com/wp-content/uploads/2017/02/file-example-PPT_10MB.ppt' }, + ], photo: 'https://cdn.quasar.dev/img/parallax2.jpg', results: '1 место в категории "Лучшее AI-решение"', is_win: true, @@ -208,7 +216,7 @@ async function fetchContestDetails(id) { { id: 5, url: 'https://cdn.quasar.dev/img/parallax2.jpg' }, ], files: [ - { id: 1, name: 'Презентация проекта.pdf', description: 'Финальная презентация', url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' }, + { id: 1, name: 'Презентация конкурса.pdf', description: 'Финальная презентация', url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' }, { id: 2, name: 'Код проекта.zip', description: 'Исходный код', url: 'https://www.learningcontainer.com/wp-content/uploads/2020/07/Example-Zip-File.zip' }, ], project_id: 1, @@ -220,13 +228,15 @@ async function fetchContestDetails(id) { description: 'Масштабное соревнование по спортивному программированию, где участники решают алгоритмические задачи. Отличная возможность проверить свои навыки.', web_url: 'https://codefest.org', repository_url: 'https://gitlab.com/awesome-devs/codefest-challenge', + project_description: null, // No project description for this one + project_files: [], // No project files for this one photo: 'https://cdn.quasar.dev/img/material.png', results: null, is_win: false, carousel_photos: [ { id: 10, url: 'https://images.unsplash.com/photo-1584291378203-674a462de8bc?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D' }, { id: 11, url: 'https://cdn.quasar.dev/img/chicken-salad.jpg' }, - ], // Добавлены фото для второго конкурса + ], files: [], project_id: 2, status_id: 2, diff --git a/WEB/src/pages/HomePage.vue b/WEB/src/pages/HomePage.vue index e341159..ca6033d 100644 --- a/WEB/src/pages/HomePage.vue +++ b/WEB/src/pages/HomePage.vue @@ -1,14 +1,12 @@ - - @@ -17,15 +15,15 @@ - @@ -39,7 +37,6 @@ - - - Активность команды за последний год - - - - Меньше Больше @@ -118,7 +109,6 @@ - + + + + + + + + + + + + + + {{ profile.first_name }} {{ profile.last_name }} {{ profile.patronymic }} + + + + + + + + + Фотографии профиля + + + + + + + + + + + + + Основная информация + + + День рождения: {{ profile.birth_date }} + + + + Пол: {{ profile.gender }} + + + + + + + + + Контакты + + + Email: {{ profile.email }} + + + + Телефон: {{ profile.phone_number }} + + + + + + + + + + + + + Команды + + + + + + + + + {{ team.name }} + {{ team.role }} + + + + + + + + + + + + + + Участие в проектах + + + + + + + + + {{ project.title }} + {{ project.role }} + + + + + + + + + + + + + + + + + + Активность за последний год + + + + {{ monthLabel }} + + + + + + + {{ day }} + + + + + + + + + + + + Меньше + Больше + + + + + + + + + Профиль не найден :( + + + + + + + + \ No newline at end of file diff --git a/WEB/src/router/index.js b/WEB/src/router/index.js index 361dec1..2d7e2d4 100644 --- a/WEB/src/router/index.js +++ b/WEB/src/router/index.js @@ -2,16 +2,22 @@ import { createRouter, createWebHistory } from 'vue-router' import LoginPage from "../pages/LoginPage.vue" import HomePage from "../pages/HomePage.vue" import AdminPage from "../pages/AdminPage.vue" -import ContestDetailPage from "@/pages/ContestDetailPage.vue"; +import ContestDetailPage from "@/pages/ContestDetailPage.vue" +import ProfileDetailPage from "@/pages/UserDetailPage.vue"; const routes = [ { path: '/', component: HomePage }, { path: '/login', component: LoginPage }, { path: '/admin', component: AdminPage }, { - path: '/contests/:id', // Динамический маршрут, :id будет ID конкурса - name: 'contest-detail', // Имя маршрута для удобства навигации (например, router.push({ name: 'contest-detail', params: { id: 123 } })) - component: ContestDetailPage // Компонент, который будет отображаться + path: '/contests/:id', + name: 'contest-detail', + component: ContestDetailPage + }, + { + path: '/profile/:id', + name: 'profile-detail', + component: ProfileDetailPage } ] @@ -37,4 +43,4 @@ router.beforeEach((to, from, next) => { } }) -export default router +export default router \ No newline at end of file