mirror of
https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git
synced 2025-08-14 00:25:46 +02:00
Починка добавления сотрудника2231ап
This commit is contained in:
@@ -16,6 +16,7 @@ services:
|
|||||||
container_name: support-backend
|
container_name: support-backend
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=postgresql://postgres:postgres123@postgres:5432/support_db
|
- DATABASE_URL=postgresql://postgres:postgres123@postgres:5432/support_db
|
||||||
|
- TEST_DATABASE_URL=postgresql://postgres:postgres123@postgres:5432/support_db_test
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -32,8 +33,10 @@ services:
|
|||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
POSTGRES_PASSWORD: postgres123
|
POSTGRES_PASSWORD: postgres123
|
||||||
POSTGRES_DB: support_db
|
POSTGRES_DB: support_db
|
||||||
|
POSTGRES_MULTIPLE_DATABASES: support_db,support_db_test
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
- ./backend/scripts/create-multiple-postgresql-databases.sh:/docker-entrypoint-initdb.d/create-multiple-postgresql-databases.sh
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U postgres -d support_db"]
|
test: ["CMD-SHELL", "pg_isready -U postgres -d support_db"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ export const getStatusLabel = (status: string): string => {
|
|||||||
const statuses: Record<string, string> = {
|
const statuses: Record<string, string> = {
|
||||||
new: 'Новая',
|
new: 'Новая',
|
||||||
in_progress: 'В работе',
|
in_progress: 'В работе',
|
||||||
resolved: 'Решена',
|
completed: 'Завершена',
|
||||||
closed: 'Закрыта'
|
rejected: 'Отклонена'
|
||||||
};
|
};
|
||||||
return statuses[status] || status;
|
return statuses[status] || status;
|
||||||
};
|
};
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
<!-- Статистика -->
|
<!-- Статистика -->
|
||||||
<div v-if="activeSection === 'statistics'" class="space-y-6">
|
<div v-if="activeSection === 'statistics'" class="space-y-6">
|
||||||
<h2 class="text-2xl font-medium text-gray-900">Статистика</h2>
|
<h2 class="text-2xl font-medium text-gray-900">Статистика</h2>
|
||||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-3">
|
<div class="grid grid-cols-1 gap-6 sm:grid-cols-4">
|
||||||
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||||
<div class="text-sm font-medium text-gray-500 mb-1">Новые заявки</div>
|
<div class="text-sm font-medium text-gray-500 mb-1">Новые заявки</div>
|
||||||
<div class="text-2xl font-medium text-gray-900">{{ statistics.new || 0 }}</div>
|
<div class="text-2xl font-medium text-gray-900">{{ statistics.new || 0 }}</div>
|
||||||
@@ -84,8 +84,12 @@
|
|||||||
<div class="text-2xl font-medium text-gray-900">{{ statistics.inProgress || 0 }}</div>
|
<div class="text-2xl font-medium text-gray-900">{{ statistics.inProgress || 0 }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||||
<div class="text-sm font-medium text-gray-500 mb-1">Решенные</div>
|
<div class="text-sm font-medium text-gray-500 mb-1">Завершенные</div>
|
||||||
<div class="text-2xl font-medium text-gray-900">{{ statistics.resolved || 0 }}</div>
|
<div class="text-2xl font-medium text-gray-900">{{ statistics.completed || 0 }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||||
|
<div class="text-sm font-medium text-gray-500 mb-1">Отклоненные</div>
|
||||||
|
<div class="text-2xl font-medium text-gray-900">{{ statistics.rejected || 0 }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -130,7 +134,7 @@
|
|||||||
Подробнее
|
Подробнее
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="request.status !== 'resolved'"
|
v-if="request.status !== 'completed'"
|
||||||
@click="updateRequestStatus(request)"
|
@click="updateRequestStatus(request)"
|
||||||
class="text-blue-600 hover:text-blue-700"
|
class="text-blue-600 hover:text-blue-700"
|
||||||
>
|
>
|
||||||
@@ -246,7 +250,7 @@
|
|||||||
Закрыть
|
Закрыть
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="selectedRequest?.status !== 'resolved'"
|
v-if="selectedRequest?.status !== 'completed'"
|
||||||
@click="updateRequestStatus(selectedRequest)"
|
@click="updateRequestStatus(selectedRequest)"
|
||||||
class="px-4 py-2 text-sm font-medium text-blue-600 hover:text-blue-700"
|
class="px-4 py-2 text-sm font-medium text-blue-600 hover:text-blue-700"
|
||||||
>
|
>
|
||||||
@@ -347,7 +351,8 @@ import axios from 'axios'
|
|||||||
interface Statistics {
|
interface Statistics {
|
||||||
new: number
|
new: number
|
||||||
inProgress: number
|
inProgress: number
|
||||||
resolved: number
|
completed: number
|
||||||
|
rejected: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Employee {
|
interface Employee {
|
||||||
@@ -366,7 +371,7 @@ interface Request {
|
|||||||
request_type: string
|
request_type: string
|
||||||
priority: 'low' | 'medium' | 'high' | 'critical'
|
priority: 'low' | 'medium' | 'high' | 'critical'
|
||||||
description: string
|
description: string
|
||||||
status: 'new' | 'in_progress' | 'resolved'
|
status: 'new' | 'in_progress' | 'completed' | 'rejected'
|
||||||
created_at: string
|
created_at: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +386,7 @@ interface EmployeeForm {
|
|||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const activeSection = ref('statistics')
|
const activeSection = ref('statistics')
|
||||||
const statistics = ref<Statistics>({ new: 0, inProgress: 0, resolved: 0 })
|
const statistics = ref<Statistics>({ new: 0, inProgress: 0, completed: 0, rejected: 0 })
|
||||||
const requests = ref<Request[]>([])
|
const requests = ref<Request[]>([])
|
||||||
const employees = ref<Employee[]>([])
|
const employees = ref<Employee[]>([])
|
||||||
const showRequestModal = ref(false)
|
const showRequestModal = ref(false)
|
||||||
@@ -407,7 +412,8 @@ const priorityClasses = {
|
|||||||
const statusClasses = {
|
const statusClasses = {
|
||||||
new: 'px-2 py-1 text-xs rounded-full bg-gray-100 text-gray-800',
|
new: 'px-2 py-1 text-xs rounded-full bg-gray-100 text-gray-800',
|
||||||
in_progress: 'px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800',
|
in_progress: 'px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800',
|
||||||
resolved: 'px-2 py-1 text-xs rounded-full bg-green-100 text-green-800'
|
completed: 'px-2 py-1 text-xs rounded-full bg-green-100 text-green-800',
|
||||||
|
rejected: 'px-2 py-1 text-xs rounded-full bg-red-100 text-red-800'
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
const getPriorityClass = (priority: Request['priority'] | undefined) => {
|
const getPriorityClass = (priority: Request['priority'] | undefined) => {
|
||||||
@@ -521,7 +527,9 @@ const updateRequestStatus = async (request: Request | null) => {
|
|||||||
if (request.status === 'new') {
|
if (request.status === 'new') {
|
||||||
newStatus = 'in_progress'
|
newStatus = 'in_progress'
|
||||||
} else if (request.status === 'in_progress') {
|
} else if (request.status === 'in_progress') {
|
||||||
newStatus = 'resolved'
|
newStatus = 'completed'
|
||||||
|
} else if (request.status === 'completed') {
|
||||||
|
newStatus = 'rejected'
|
||||||
}
|
}
|
||||||
|
|
||||||
await axios.put(`/api/requests/${request.id}`, { status: newStatus }, { headers })
|
await axios.put(`/api/requests/${request.id}`, { status: newStatus }, { headers })
|
||||||
|
|||||||
@@ -113,10 +113,12 @@ const form = ref({
|
|||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
isSubmitting.value = true;
|
isSubmitting.value = true;
|
||||||
|
const token = localStorage.getItem('admin_token');
|
||||||
const response = await fetch('/api/employees/', {
|
const response = await fetch('/api/employees/', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify(form.value)
|
body: JSON.stringify(form.value)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -62,7 +62,12 @@ const employees = ref<Employee[]>([]);
|
|||||||
|
|
||||||
const fetchEmployees = async () => {
|
const fetchEmployees = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/employees/');
|
const token = localStorage.getItem('admin_token');
|
||||||
|
const response = await fetch('/api/employees/', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
if (!response.ok) throw new Error('Failed to fetch employees');
|
if (!response.ok) throw new Error('Failed to fetch employees');
|
||||||
employees.value = await response.json();
|
employees.value = await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user