сделал проекты
This commit is contained in:
parent
ac42a8da7f
commit
5b1e74876d
23
WEB/src/api/projects/createProject.js
Normal file
23
WEB/src/api/projects/createProject.js
Normal file
@ -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
|
||||||
22
WEB/src/api/projects/deleteProject.js
Normal file
22
WEB/src/api/projects/deleteProject.js
Normal file
@ -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
|
||||||
@ -3,13 +3,19 @@ import CONFIG from "@/core/config.js";
|
|||||||
|
|
||||||
const fetchProjects = async () => {
|
const fetchProjects = async () => {
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem("access_token");
|
||||||
const response = await axios.get(`${CONFIG.BASE_URL}/projects`, {
|
const response = await axios.get(`${CONFIG.BASE_URL}/projects`, {
|
||||||
withCredentials: true,
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response?.status === 401) {
|
if (error.response?.status === 401) {
|
||||||
throw new Error("Нет доступа к проектам (401)");
|
throw new Error("Нет доступа к проектам (401)");
|
||||||
|
} else if (error.response?.status === 403) {
|
||||||
|
throw new Error("Доступ запрещён (403)");
|
||||||
}
|
}
|
||||||
throw new Error(error.message);
|
throw new Error(error.message);
|
||||||
}
|
}
|
||||||
|
|||||||
31
WEB/src/api/projects/updateProject.js
Normal file
31
WEB/src/api/projects/updateProject.js
Normal file
@ -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
|
||||||
@ -3,9 +3,15 @@ import CONFIG from '@/core/config.js'
|
|||||||
|
|
||||||
const deleteTeam = async (teamId) => {
|
const deleteTeam = async (teamId) => {
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('access_token') // получение токена
|
||||||
const response = await axios.delete(
|
const response = await axios.delete(
|
||||||
`${CONFIG.BASE_URL}/teams/${teamId}`,
|
`${CONFIG.BASE_URL}/teams/${teamId}`,
|
||||||
{ withCredentials: true }
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
26
WEB/src/components/SharedDialogWrapper.vue
Normal file
26
WEB/src/components/SharedDialogWrapper.vue
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<q-dialog v-model="visible" persistent>
|
||||||
|
<q-card style="min-width: 350px; max-width: 700px;">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">{{ title }}</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator />
|
||||||
|
|
||||||
|
<q-card-section>
|
||||||
|
<slot />
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<slot name="actions" />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
visible: Boolean,
|
||||||
|
title: String
|
||||||
|
})
|
||||||
|
</script>
|
||||||
37
WEB/src/components/dialogs/ContestDialog.vue
Normal file
37
WEB/src/components/dialogs/ContestDialog.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<SharedDialogWrapper :visible="visible" title="Редактирование конкурса">
|
||||||
|
<q-input v-model="data.title" label="Название конкурса" dense autofocus clearable />
|
||||||
|
<q-input v-model="data.description" label="Описание" dense clearable type="textarea" class="q-mt-sm" />
|
||||||
|
<q-input v-model="data.start_date" label="Дата начала" type="date" dense clearable class="q-mt-sm" />
|
||||||
|
<q-input v-model="data.end_date" label="Дата окончания" type="date" dense clearable class="q-mt-sm" />
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<q-btn flat label="Удалить" color="negative" @click="onDelete" v-if="showDelete" />
|
||||||
|
<q-space />
|
||||||
|
<q-btn flat label="Закрыть" color="primary" @click="onClose" />
|
||||||
|
<q-btn flat label="Сохранить" color="primary" @click="onSave" />
|
||||||
|
</template>
|
||||||
|
</SharedDialogWrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import SharedDialogWrapper from './SharedDialogWrapper.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
visible: Boolean,
|
||||||
|
data: Object,
|
||||||
|
showDelete: Boolean
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['save', 'close', 'delete'])
|
||||||
|
|
||||||
|
function onSave() {
|
||||||
|
emit('save')
|
||||||
|
}
|
||||||
|
function onClose() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
function onDelete() {
|
||||||
|
emit('delete')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
36
WEB/src/components/dialogs/ProjectDialog.vue
Normal file
36
WEB/src/components/dialogs/ProjectDialog.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<SharedDialogWrapper :visible="visible" title="Редактирование проекта">
|
||||||
|
<q-input v-model="data.title" label="Название проекта" dense autofocus clearable />
|
||||||
|
<q-input v-model="data.description" label="Описание" dense clearable type="textarea" class="q-mt-sm" />
|
||||||
|
<q-input v-model="data.repo_url" label="URL репозитория" dense clearable class="q-mt-sm" />
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<q-btn flat label="Удалить" color="negative" @click="onDelete" v-if="showDelete" />
|
||||||
|
<q-space />
|
||||||
|
<q-btn flat label="Закрыть" color="primary" @click="onClose" />
|
||||||
|
<q-btn flat label="Сохранить" color="primary" @click="onSave" />
|
||||||
|
</template>
|
||||||
|
</SharedDialogWrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import SharedDialogWrapper from './SharedDialogWrapper.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
visible: Boolean,
|
||||||
|
data: Object,
|
||||||
|
showDelete: Boolean
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['save', 'close', 'delete'])
|
||||||
|
|
||||||
|
function onSave() {
|
||||||
|
emit('save')
|
||||||
|
}
|
||||||
|
function onClose() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
function onDelete() {
|
||||||
|
emit('delete')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
37
WEB/src/components/dialogs/TeamDialog.vue
Normal file
37
WEB/src/components/dialogs/TeamDialog.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<SharedDialogWrapper :visible="visible" title="Редактирование команды">
|
||||||
|
<q-input v-model="data.title" label="Название команды" dense autofocus clearable />
|
||||||
|
<q-input v-model="data.description" label="Описание" dense clearable type="textarea" class="q-mt-sm" />
|
||||||
|
<q-input v-model="data.logo" label="Логотип" dense clearable class="q-mt-sm" />
|
||||||
|
<q-input v-model="data.git_url" label="Git URL" dense clearable class="q-mt-sm" />
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<q-btn flat label="Удалить" color="negative" @click="onDelete" v-if="showDelete" />
|
||||||
|
<q-space />
|
||||||
|
<q-btn flat label="Закрыть" color="primary" @click="onClose" />
|
||||||
|
<q-btn flat label="Сохранить" color="primary" @click="onSave" />
|
||||||
|
</template>
|
||||||
|
</SharedDialogWrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import SharedDialogWrapper from './SharedDialogWrapper.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
visible: Boolean,
|
||||||
|
data: Object,
|
||||||
|
showDelete: Boolean
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['save', 'close', 'delete'])
|
||||||
|
|
||||||
|
function onSave() {
|
||||||
|
emit('save')
|
||||||
|
}
|
||||||
|
function onClose() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
function onDelete() {
|
||||||
|
emit('delete')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
36
WEB/src/components/dialogs/UserDialog.vue
Normal file
36
WEB/src/components/dialogs/UserDialog.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<SharedDialogWrapper :visible="visible" title="Редактирование пользователя">
|
||||||
|
<q-input v-model="data.login" label="Логин" dense autofocus clearable />
|
||||||
|
<q-input v-model="data.name" label="Имя" dense clearable class="q-mt-sm" />
|
||||||
|
<q-input v-model="data.email" label="Email" dense clearable class="q-mt-sm" />
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<q-btn flat label="Удалить" color="negative" @click="onDelete" v-if="showDelete" />
|
||||||
|
<q-space />
|
||||||
|
<q-btn flat label="Закрыть" color="primary" @click="onClose" />
|
||||||
|
<q-btn flat label="Сохранить" color="primary" @click="onSave" />
|
||||||
|
</template>
|
||||||
|
</SharedDialogWrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import SharedDialogWrapper from '@/components/dialogs/SharedDialogWrapper.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
visible: Boolean,
|
||||||
|
data: Object,
|
||||||
|
showDelete: Boolean
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['save', 'close', 'delete'])
|
||||||
|
|
||||||
|
function onSave() {
|
||||||
|
emit('save')
|
||||||
|
}
|
||||||
|
function onClose() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
function onDelete() {
|
||||||
|
emit('delete')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -45,7 +45,7 @@
|
|||||||
<q-btn
|
<q-btn
|
||||||
label="Создание команды"
|
label="Создание команды"
|
||||||
color="primary"
|
color="primary"
|
||||||
@click="createTeamHandler"
|
@click="createHandler"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -169,7 +169,7 @@
|
|||||||
flat
|
flat
|
||||||
label="Удалить"
|
label="Удалить"
|
||||||
color="negative"
|
color="negative"
|
||||||
@click="deleteTeam"
|
@click="deleteItem"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="dialogType === 'users'"
|
v-if="dialogType === 'users'"
|
||||||
@ -216,16 +216,17 @@ import updateTeam from '@/api/teams/updateTeam.js'
|
|||||||
import deleteTeamById from '@/api/teams/deleteTeam.js'
|
import deleteTeamById from '@/api/teams/deleteTeam.js'
|
||||||
import createTeam from '@/api/teams/createTeam.js'
|
import createTeam from '@/api/teams/createTeam.js'
|
||||||
|
|
||||||
|
import fetchProjects from '@/api/projects/getProjects.js'
|
||||||
|
import updateProject from '@/api/projects/updateProject.js'
|
||||||
|
import deleteProjectById from '@/api/projects/deleteProject.js'
|
||||||
|
import createProject from '@/api/projects/createProject.js'
|
||||||
|
|
||||||
|
// Текущая вкладка — 'teams' или 'projects'
|
||||||
const tab = ref('teams')
|
const tab = ref('teams')
|
||||||
|
|
||||||
|
// --- Teams ---
|
||||||
const teams = ref([])
|
const teams = ref([])
|
||||||
const loadingTeams = ref(false)
|
const loadingTeams = ref(false)
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
|
||||||
const dialogData = ref({})
|
|
||||||
const dialogType = ref('')
|
|
||||||
|
|
||||||
const teamColumns = [
|
const teamColumns = [
|
||||||
{ name: 'title', label: 'Название команды', field: 'title', sortable: true },
|
{ name: 'title', label: 'Название команды', field: 'title', sortable: true },
|
||||||
{ name: 'description', label: 'Описание', field: 'description', sortable: true },
|
{ name: 'description', label: 'Описание', field: 'description', sortable: true },
|
||||||
@ -233,20 +234,37 @@ const teamColumns = [
|
|||||||
{ name: 'git_url', label: 'Git URL', field: 'git_url', sortable: true },
|
{ name: 'git_url', label: 'Git URL', field: 'git_url', sortable: true },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// --- Projects ---
|
||||||
|
const projects = ref([])
|
||||||
|
const loadingProjects = ref(false)
|
||||||
|
const projectColumns = [
|
||||||
|
{ name: 'name', label: 'Название проекта', field: 'name', sortable: true },
|
||||||
|
{ name: 'summary', label: 'Описание', field: 'summary', sortable: true },
|
||||||
|
{ name: 'deadline', label: 'Дедлайн', field: 'deadline', sortable: true },
|
||||||
|
// добавьте нужные поля
|
||||||
|
]
|
||||||
|
|
||||||
|
// Общие состояния для диалогов
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const dialogData = ref({})
|
||||||
|
const dialogType = ref('') // 'teams' или 'projects'
|
||||||
|
|
||||||
function openEdit(type, row) {
|
function openEdit(type, row) {
|
||||||
console.log('openEdit called with row:', row)
|
|
||||||
dialogType.value = type
|
dialogType.value = type
|
||||||
// Проверка на null или undefined
|
|
||||||
if (row) {
|
if (row) {
|
||||||
dialogData.value = JSON.parse(JSON.stringify(row))
|
dialogData.value = JSON.parse(JSON.stringify(row))
|
||||||
dialogVisible.value = true
|
} else {
|
||||||
|
if (type === 'teams') {
|
||||||
|
dialogData.value = { title: '', description: '', logo: '', git_url: '' }
|
||||||
|
} else if (type === 'projects') {
|
||||||
|
dialogData.value = { name: '', summary: '', deadline: '' }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRowClick(event, row) {
|
function onRowClick(event, row) {
|
||||||
console.log('event:', event)
|
openEdit(tab.value, row)
|
||||||
console.log('row:', row)
|
|
||||||
openEdit('teams', row)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeDialog() {
|
function closeDialog() {
|
||||||
@ -254,37 +272,32 @@ function closeDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function saveChanges() {
|
async function saveChanges() {
|
||||||
if (dialogType.value === 'teams') {
|
try {
|
||||||
try {
|
if (dialogType.value === 'teams') {
|
||||||
if (dialogData.value.id) {
|
if (dialogData.value.id) {
|
||||||
// Формируем чистый объект с нужными полями
|
await updateTeam(dialogData.value)
|
||||||
const teamToUpdate = {
|
const idx = teams.value.findIndex(t => t.id === dialogData.value.id)
|
||||||
id: dialogData.value.id,
|
if (idx !== -1) teams.value[idx] = JSON.parse(JSON.stringify(dialogData.value))
|
||||||
title: dialogData.value.title,
|
|
||||||
description: dialogData.value.description,
|
|
||||||
logo: dialogData.value.logo,
|
|
||||||
git_url: dialogData.value.git_url
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Отправляем на сервер:', teamToUpdate)
|
|
||||||
await updateTeam(teamToUpdate)
|
|
||||||
|
|
||||||
const index = teams.value.findIndex(t => t.id === teamToUpdate.id)
|
|
||||||
if (index !== -1) {
|
|
||||||
teams.value[index] = JSON.parse(JSON.stringify(teamToUpdate))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const newTeam = await createTeam(dialogData.value)
|
const newTeam = await createTeam(dialogData.value)
|
||||||
teams.value.push(newTeam)
|
teams.value.push(newTeam)
|
||||||
}
|
}
|
||||||
closeDialog()
|
} else if (dialogType.value === 'projects') {
|
||||||
} catch (error) {
|
if (dialogData.value.id) {
|
||||||
console.error('Ошибка при сохранении:', error.message)
|
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) {
|
async function loadData(name) {
|
||||||
if (name === 'teams') {
|
if (name === 'teams') {
|
||||||
loadingTeams.value = true
|
loadingTeams.value = true
|
||||||
@ -296,30 +309,37 @@ async function loadData(name) {
|
|||||||
} finally {
|
} finally {
|
||||||
loadingTeams.value = false
|
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
|
if (!dialogData.value.id) return
|
||||||
try {
|
try {
|
||||||
await deleteTeamById(dialogData.value.id)
|
if (dialogType.value === 'teams') {
|
||||||
teams.value = teams.value.filter(t => t.id !== dialogData.value.id)
|
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()
|
closeDialog()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ошибка при удалении команды:', error.message)
|
console.error('Ошибка при удалении:', error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTeamHandler() {
|
function createHandler() {
|
||||||
dialogType.value = 'teams'
|
openEdit(tab.value, null)
|
||||||
dialogData.value = {
|
|
||||||
title: '',
|
|
||||||
description: '',
|
|
||||||
logo: '',
|
|
||||||
git_url: ''
|
|
||||||
}
|
|
||||||
dialogVisible.value = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -350,4 +370,4 @@ watch(tab, (newTab) => {
|
|||||||
background: #ede9fe;
|
background: #ede9fe;
|
||||||
box-shadow: 0 6px 32px rgba(124, 58, 237, 0.13), 0 1.5px 6px rgba(124, 58, 237, 0.10);
|
box-shadow: 0 6px 32px rgba(124, 58, 237, 0.13), 0 1.5px 6px rgba(124, 58, 237, 0.10);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user