1
0
mirror of https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git synced 2025-08-14 00:25:46 +02:00

add websockets support22312

This commit is contained in:
MoonTestUse1
2025-01-05 01:50:08 +06:00
parent df9af0131c
commit a81310d0e7
3 changed files with 92 additions and 48 deletions

View File

@@ -2,6 +2,7 @@
from fastapi import APIRouter, Depends, HTTPException, Query, WebSocket, WebSocketDisconnect from fastapi import APIRouter, Depends, HTTPException, Query, WebSocket, WebSocketDisconnect
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from typing import List, Optional from typing import List, Optional
import logging
from ..database import get_db from ..database import get_db
from ..crud import requests from ..crud import requests
from ..schemas.request import Request, RequestCreate, RequestUpdate from ..schemas.request import Request, RequestCreate, RequestUpdate
@@ -11,16 +12,19 @@ from ..utils.telegram import notify_new_request
from ..websockets.notifications import notification_manager from ..websockets.notifications import notification_manager
router = APIRouter() router = APIRouter()
logger = logging.getLogger(__name__)
@router.websocket("/ws/admin") @router.websocket("/ws/admin")
async def websocket_admin_endpoint(websocket: WebSocket): async def websocket_admin_endpoint(websocket: WebSocket):
"""WebSocket endpoint для админов""" """WebSocket endpoint для админов"""
logger.info("Admin WebSocket connection attempt")
await notification_manager.connect(websocket, "admin") await notification_manager.connect(websocket, "admin")
try: try:
while True: while True:
data = await websocket.receive_text() data = await websocket.receive_text()
# Здесь можно добавить обработку сообщений от админа logger.info(f"Received message from admin: {data}")
except WebSocketDisconnect: except WebSocketDisconnect:
logger.info("Admin WebSocket disconnected")
notification_manager.disconnect(websocket, "admin") notification_manager.disconnect(websocket, "admin")
@router.websocket("/ws/employee/{employee_id}") @router.websocket("/ws/employee/{employee_id}")
@@ -41,12 +45,15 @@ async def create_request(
current_employee: dict = Depends(get_current_employee) current_employee: dict = Depends(get_current_employee)
): ):
"""Create new request""" """Create new request"""
logger.info(f"Creating new request from employee {current_employee['id']}")
db_request = requests.create_request(db, request, current_employee["id"]) db_request = requests.create_request(db, request, current_employee["id"])
# Отправляем уведомление в Telegram # Отправляем уведомление в Telegram
await notify_new_request(db_request.id) await notify_new_request(db_request.id)
# Получаем актуальную статистику # Получаем актуальную статистику
stats = requests.get_statistics(db) stats = requests.get_statistics(db)
logger.info(f"Current statistics: {stats}")
# Получаем полные данные о заявке для отправки через WebSocket # Получаем полные данные о заявке для отправки через WebSocket
request_data = { request_data = {
@@ -61,15 +68,17 @@ async def create_request(
"created_at": db_request.created_at.isoformat() "created_at": db_request.created_at.isoformat()
} }
# Отправляем уведомление через WebSocket всем админам # Формируем сообщение для WebSocket
await notification_manager.broadcast_to_admins({ ws_message = {
"type": "new_request", "type": "new_request",
"data": request_data, "data": request_data,
"statistics": { "statistics": stats
"total": stats["total"], }
"by_status": stats["by_status"]
} logger.info(f"Broadcasting WebSocket message: {ws_message}")
}) # Отправляем уведомление через WebSocket всем админам
await notification_manager.broadcast_to_admins(ws_message)
return db_request return db_request
@router.get("/my", response_model=List[Request]) @router.get("/my", response_model=List[Request])
@@ -99,25 +108,29 @@ async def update_request_status(
_: dict = Depends(get_current_admin) _: dict = Depends(get_current_admin)
): ):
"""Update request status (admin only)""" """Update request status (admin only)"""
logger.info(f"Updating request {request_id} status to {request_update.status}")
db_request = requests.update_request_status(db, request_id, request_update.status) db_request = requests.update_request_status(db, request_id, request_update.status)
if db_request is None: if db_request is None:
raise HTTPException(status_code=404, detail="Request not found") raise HTTPException(status_code=404, detail="Request not found")
# Получаем актуальную статистику # Получаем актуальную статистику
stats = requests.get_statistics(db) stats = requests.get_statistics(db)
logger.info(f"Current statistics after status update: {stats}")
# Отправляем уведомление через WebSocket # Формируем сообщение для WebSocket
await notification_manager.broadcast_to_admins({ ws_message = {
"type": "status_update", "type": "status_update",
"data": { "data": {
"id": request_id, "id": request_id,
"status": db_request.status "status": db_request.status
}, },
"statistics": { "statistics": stats
"total": stats["total"], }
"by_status": stats["by_status"]
} logger.info(f"Broadcasting WebSocket message for status update: {ws_message}")
}) # Отправляем уведомление через WebSocket
await notification_manager.broadcast_to_admins(ws_message)
return db_request return db_request
@router.get("/statistics") @router.get("/statistics")

View File

@@ -22,65 +22,86 @@ class WebSocketClient {
`${baseUrl}/api/requests/ws/admin` : `${baseUrl}/api/requests/ws/admin` :
`${baseUrl}/api/requests/ws/employee/${id}` `${baseUrl}/api/requests/ws/employee/${id}`
console.log('Connecting to WebSocket:', url) console.log('WebSocket: Connecting to', url)
if (this.socket) { if (this.socket) {
console.log('Closing existing connection') console.log('WebSocket: Closing existing connection')
this.socket.close() this.socket.close()
this.socket = null
} }
this.socket = new WebSocket(url) try {
this.socket = new WebSocket(url)
this.socket.onopen = () => { this.socket.onopen = () => {
console.log('WebSocket connected') console.log('WebSocket: Connected successfully')
this.isConnected.value = true this.isConnected.value = true
this.reconnectAttempts = 0 this.reconnectAttempts = 0
}
this.socket.onmessage = (event) => {
console.log('WebSocket message received:', event.data)
try {
const data = JSON.parse(event.data)
this.messageHandlers.forEach(handler => handler(data))
} catch (error) {
console.error('Error parsing WebSocket message:', error)
} }
}
this.socket.onclose = () => { this.socket.onmessage = (event) => {
console.log('WebSocket disconnected') console.log('WebSocket: Message received', event.data)
try {
const data = JSON.parse(event.data)
this.messageHandlers.forEach(handler => {
try {
handler(data)
} catch (error) {
console.error('WebSocket: Error in message handler:', error)
}
})
} catch (error) {
console.error('WebSocket: Error parsing message:', error)
}
}
this.socket.onclose = (event) => {
console.log('WebSocket: Connection closed', event.code, event.reason)
this.isConnected.value = false
this.tryReconnect()
}
this.socket.onerror = (error) => {
console.error('WebSocket: Error occurred:', error)
this.isConnected.value = false
}
} catch (error) {
console.error('WebSocket: Error creating connection:', error)
this.isConnected.value = false this.isConnected.value = false
this.tryReconnect() this.tryReconnect()
} }
this.socket.onerror = (error) => {
console.error('WebSocket error:', error)
this.isConnected.value = false
}
} }
private tryReconnect() { private tryReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts && this.currentType) { if (this.reconnectAttempts < this.maxReconnectAttempts && this.currentType) {
this.reconnectAttempts++ this.reconnectAttempts++
console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})`) const delay = this.reconnectTimeout * Math.min(this.reconnectAttempts, 3)
console.log(`WebSocket: Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts}) in ${delay}ms`)
setTimeout(() => { setTimeout(() => {
console.log('WebSocket: Reconnecting...')
this.connect(this.currentType!, this.currentId) this.connect(this.currentType!, this.currentId)
}, this.reconnectTimeout * this.reconnectAttempts) }, delay)
} else {
console.log('WebSocket: Max reconnection attempts reached')
} }
} }
addMessageHandler(handler: (data: any) => void) { addMessageHandler(handler: (data: any) => void) {
this.messageHandlers.push(handler) this.messageHandlers.push(handler)
console.log('WebSocket: Message handler added')
} }
removeMessageHandler(handler: (data: any) => void) { removeMessageHandler(handler: (data: any) => void) {
const index = this.messageHandlers.indexOf(handler) const index = this.messageHandlers.indexOf(handler)
if (index > -1) { if (index > -1) {
this.messageHandlers.splice(index, 1) this.messageHandlers.splice(index, 1)
console.log('WebSocket: Message handler removed')
} }
} }
disconnect() { disconnect() {
console.log('WebSocket: Disconnecting...')
if (this.socket) { if (this.socket) {
this.socket.close() this.socket.close()
this.socket = null this.socket = null

View File

@@ -98,20 +98,24 @@ const fetchData = async () => {
} }
// Обработчик WebSocket сообщений // Обработчик WebSocket сообщений
const handleWebSocketMessage = async (data: any) => { const handleWebSocketMessage = (data: any) => {
console.log('Received WebSocket message:', data) console.log('Received WebSocket message:', data)
// Обновляем статистику, если она пришла в сообщении // Обновляем статистику, если она пришла в сообщении
if (data.statistics) { if (data.statistics) {
statistics.value = data.statistics console.log('Updating statistics:', data.statistics)
statistics.value = {
total: data.statistics.total,
by_status: { ...data.statistics.by_status }
}
} }
if (data.type === 'new_request') { if (data.type === 'new_request' && data.data) {
console.log('Adding new request:', data.data)
// Добавляем новую заявку в начало списка // Добавляем новую заявку в начало списка
if (data.data) { requests.value = [data.data, ...requests.value.slice(0, 99)]
requests.value = [data.data, ...requests.value] } else if (data.type === 'status_update' && data.data) {
} console.log('Updating request status:', data.data)
} else if (data.type === 'status_update') {
// Обновляем статус заявки в списке // Обновляем статус заявки в списке
const request = requests.value.find(r => r.id === data.data.id) const request = requests.value.find(r => r.id === data.data.id)
if (request) { if (request) {
@@ -122,9 +126,12 @@ const handleWebSocketMessage = async (data: any) => {
// Подключение к WebSocket при монтировании компонента // Подключение к WebSocket при монтировании компонента
onMounted(() => { onMounted(() => {
console.log('Component mounted, fetching initial data')
fetchData() fetchData()
// Добавляем небольшую задержку перед подключением WebSocket // Добавляем небольшую задержку перед подключением WebSocket
setTimeout(() => { setTimeout(() => {
console.log('Connecting to WebSocket')
wsClient.connect('admin') wsClient.connect('admin')
wsClient.addMessageHandler(handleWebSocketMessage) wsClient.addMessageHandler(handleWebSocketMessage)
}, 1000) }, 1000)
@@ -132,7 +139,9 @@ onMounted(() => {
// Переподключение WebSocket при потере соединения // Переподключение WebSocket при потере соединения
watch(() => wsClient.isConnected, (isConnected) => { watch(() => wsClient.isConnected, (isConnected) => {
console.log('WebSocket connection status changed:', isConnected)
if (!isConnected) { if (!isConnected) {
console.log('Attempting to reconnect WebSocket')
setTimeout(() => { setTimeout(() => {
wsClient.connect('admin') wsClient.connect('admin')
}, 3000) }, 3000)
@@ -141,6 +150,7 @@ watch(() => wsClient.isConnected, (isConnected) => {
// Отключение от WebSocket при размонтировании компонента // Отключение от WebSocket при размонтировании компонента
onUnmounted(() => { onUnmounted(() => {
console.log('Component unmounting, disconnecting WebSocket')
wsClient.removeMessageHandler(handleWebSocketMessage) wsClient.removeMessageHandler(handleWebSocketMessage)
wsClient.disconnect() wsClient.disconnect()
}) })