diff --git a/WEB/src/api/projects/createProject.js b/WEB/src/api/projects/createProject.js new file mode 100644 index 0000000..abebdd5 --- /dev/null +++ b/WEB/src/api/projects/createProject.js @@ -0,0 +1,23 @@ +import axios from 'axios' +import CONFIG from '@/core/config.js' + +const createProject = async (project) => { + try { + const token = localStorage.getItem('access_token') // или другой способ получения токена + const response = await axios.post( + `${CONFIG.BASE_URL}/projects`, + project, + { + withCredentials: true, + headers: { + Authorization: `Bearer ${token}` + } + } + ) + return response.data + } catch (error) { + throw new Error(error.response?.data?.detail || error.message) + } +} + +export default createProject diff --git a/WEB/src/api/projects/deleteProject.js b/WEB/src/api/projects/deleteProject.js new file mode 100644 index 0000000..0f5f03e --- /dev/null +++ b/WEB/src/api/projects/deleteProject.js @@ -0,0 +1,22 @@ +import axios from 'axios' +import CONFIG from '@/core/config.js' + +const deleteProject = async (projectId) => { + try { + const token = localStorage.getItem('access_token') // получение токена + const response = await axios.delete( + `${CONFIG.BASE_URL}/projects/${projectId}`, + { + withCredentials: true, + headers: { + Authorization: `Bearer ${token}` + } + } + ) + return response.data + } catch (error) { + throw new Error(error.response?.data?.detail || error.message) + } +} + +export default deleteProject diff --git a/WEB/src/api/projects/getProjects.js b/WEB/src/api/projects/getProjects.js index d0c5fdf..c3daf6d 100644 --- a/WEB/src/api/projects/getProjects.js +++ b/WEB/src/api/projects/getProjects.js @@ -3,13 +3,19 @@ import CONFIG from "@/core/config.js"; const fetchProjects = async () => { try { + const token = localStorage.getItem("access_token"); const response = await axios.get(`${CONFIG.BASE_URL}/projects`, { - withCredentials: true, + headers: { + Authorization: `Bearer ${token}`, + }, }); + return response.data; } catch (error) { if (error.response?.status === 401) { throw new Error("Нет доступа к проектам (401)"); + } else if (error.response?.status === 403) { + throw new Error("Доступ запрещён (403)"); } throw new Error(error.message); } diff --git a/WEB/src/api/projects/updateProject.js b/WEB/src/api/projects/updateProject.js new file mode 100644 index 0000000..dee0132 --- /dev/null +++ b/WEB/src/api/projects/updateProject.js @@ -0,0 +1,31 @@ +import axios from 'axios' +import CONFIG from '@/core/config.js' + +const updateProject = async (project) => { + try { + const token = localStorage.getItem('access_token') + + // Убираем id из тела запроса, он идет в URL + const { id, ...projectData } = project + + console.log('Отправляем на сервер:', projectData) + + const response = await axios.put( + `${CONFIG.BASE_URL}/projects/${id}`, + projectData, + { + withCredentials: true, + headers: { + Authorization: `Bearer ${token}` + } + } + ) + + console.log('Ответ от сервера:', response.data) + return response.data + } catch (error) { + throw new Error(error.response?.data?.detail || error.message) + } +} + +export default updateProject diff --git a/WEB/src/api/teams/deleteTeam.js b/WEB/src/api/teams/deleteTeam.js index 4203818..9a53cb3 100644 --- a/WEB/src/api/teams/deleteTeam.js +++ b/WEB/src/api/teams/deleteTeam.js @@ -3,9 +3,15 @@ import CONFIG from '@/core/config.js' const deleteTeam = async (teamId) => { try { + const token = localStorage.getItem('access_token') // получение токена const response = await axios.delete( `${CONFIG.BASE_URL}/teams/${teamId}`, - { withCredentials: true } + { + withCredentials: true, + headers: { + Authorization: `Bearer ${token}` + } + } ) return response.data } catch (error) { diff --git a/WEB/src/components/SharedDialogWrapper.vue b/WEB/src/components/SharedDialogWrapper.vue new file mode 100644 index 0000000..ba28848 --- /dev/null +++ b/WEB/src/components/SharedDialogWrapper.vue @@ -0,0 +1,26 @@ + + + diff --git a/WEB/src/components/dialogs/ContestDialog.vue b/WEB/src/components/dialogs/ContestDialog.vue new file mode 100644 index 0000000..bfb3c2f --- /dev/null +++ b/WEB/src/components/dialogs/ContestDialog.vue @@ -0,0 +1,37 @@ + + + diff --git a/WEB/src/components/dialogs/ProjectDialog.vue b/WEB/src/components/dialogs/ProjectDialog.vue new file mode 100644 index 0000000..e3b1242 --- /dev/null +++ b/WEB/src/components/dialogs/ProjectDialog.vue @@ -0,0 +1,36 @@ + + + diff --git a/WEB/src/components/dialogs/TeamDialog.vue b/WEB/src/components/dialogs/TeamDialog.vue new file mode 100644 index 0000000..eec20ed --- /dev/null +++ b/WEB/src/components/dialogs/TeamDialog.vue @@ -0,0 +1,37 @@ + + + diff --git a/WEB/src/components/dialogs/UserDialog.vue b/WEB/src/components/dialogs/UserDialog.vue new file mode 100644 index 0000000..9bfc80e --- /dev/null +++ b/WEB/src/components/dialogs/UserDialog.vue @@ -0,0 +1,36 @@ + + + diff --git a/WEB/src/pages/AdminPage.vue b/WEB/src/pages/AdminPage.vue index eefb0f7..22f9df2 100644 --- a/WEB/src/pages/AdminPage.vue +++ b/WEB/src/pages/AdminPage.vue @@ -45,7 +45,7 @@ @@ -169,7 +169,7 @@ flat label="Удалить" color="negative" - @click="deleteTeam" + @click="deleteItem" /> t.id === teamToUpdate.id) - if (index !== -1) { - teams.value[index] = JSON.parse(JSON.stringify(teamToUpdate)) - } + await updateTeam(dialogData.value) + const idx = teams.value.findIndex(t => t.id === dialogData.value.id) + if (idx !== -1) teams.value[idx] = JSON.parse(JSON.stringify(dialogData.value)) } else { const newTeam = await createTeam(dialogData.value) teams.value.push(newTeam) } - closeDialog() - } catch (error) { - console.error('Ошибка при сохранении:', error.message) + } else if (dialogType.value === 'projects') { + if (dialogData.value.id) { + await updateProject(dialogData.value) + const idx = projects.value.findIndex(p => p.id === dialogData.value.id) + if (idx !== -1) projects.value[idx] = JSON.parse(JSON.stringify(dialogData.value)) + } else { + const newProject = await createProject(dialogData.value) + projects.value.push(newProject) + } } + closeDialog() + } catch (error) { + console.error('Ошибка при сохранении:', error.message) } } - async function loadData(name) { if (name === 'teams') { loadingTeams.value = true @@ -296,30 +309,37 @@ async function loadData(name) { } finally { loadingTeams.value = false } + } else if (name === 'projects') { + loadingProjects.value = true + try { + projects.value = await fetchProjects() || [] + } catch (error) { + projects.value = [] + console.error(error.message) + } finally { + loadingProjects.value = false + } } - console.log('teams loaded:', teams.value) } -async function deleteTeam() { +async function deleteItem() { if (!dialogData.value.id) return try { - await deleteTeamById(dialogData.value.id) - teams.value = teams.value.filter(t => t.id !== dialogData.value.id) + if (dialogType.value === 'teams') { + await deleteTeamById(dialogData.value.id) + teams.value = teams.value.filter(t => t.id !== dialogData.value.id) + } else if (dialogType.value === 'projects') { + await deleteProjectById(dialogData.value.id) + projects.value = projects.value.filter(p => p.id !== dialogData.value.id) + } closeDialog() } catch (error) { - console.error('Ошибка при удалении команды:', error.message) + console.error('Ошибка при удалении:', error.message) } } -function createTeamHandler() { - dialogType.value = 'teams' - dialogData.value = { - title: '', - description: '', - logo: '', - git_url: '' - } - dialogVisible.value = true +function createHandler() { + openEdit(tab.value, null) } onMounted(() => { @@ -350,4 +370,4 @@ watch(tab, (newTab) => { background: #ede9fe; box-shadow: 0 6px 32px rgba(124, 58, 237, 0.13), 0 1.5px 6px rgba(124, 58, 237, 0.10); } - + \ No newline at end of file