diff --git a/backend/communications/management/commands/README.md b/backend/communications/management/commands/README.md
index f606c7f8..c91bb96c 100644
--- a/backend/communications/management/commands/README.md
+++ b/backend/communications/management/commands/README.md
@@ -85,6 +85,61 @@ cd backend
---
+## check_chats
+
+Проверка и очистка чатов с некорректными типами.
+
+### Примеры использования
+
+#### Найти все чаты с некорректными типами
+
+```bash
+.venv/bin/python manage.py check_chats --find
+```
+
+#### Проверить конкретный чат
+
+```bash
+.venv/bin/python manage.py check_chats --check 6
+```
+
+#### Удалить все чаты с некорректными типами (с подтверждением)
+
+```bash
+.venv/bin/python manage.py check_chats --cleanup
+```
+
+#### Удалить все чаты с некорректными типами (без подтверждения)
+
+```bash
+.venv/bin/python manage.py check_chats --cleanup --no-confirm
+```
+
+#### Удалить конкретный чат
+
+```bash
+.venv/bin/python manage.py check_chats --delete 6
+```
+
+### Допустимые типы чатов
+
+- `private` - Личный диалог
+- `group` - Групповой чат
+- `channel` - Канал
+- `announcement` - Объявления
+- `global` - Глобальный чат
+- `comments` - Комментарии
+
+### Опции
+
+- `--find` - Найти все чаты с некорректными типами
+- `--check CHAT_ID` - Проверить конкретный чат по ID
+- `--cleanup` - Удалить все чаты с некорректными типами
+- `--delete CHAT_ID` - Удалить конкретный чат по ID
+- `--no-confirm` - Не запрашивать подтверждение при удалении
+
+---
+
## Другие команды
- `init_reactions.py` - Инициализация реакций
diff --git a/backend/communications/management/commands/check_chats.py b/backend/communications/management/commands/check_chats.py
new file mode 100644
index 00000000..f94e809d
--- /dev/null
+++ b/backend/communications/management/commands/check_chats.py
@@ -0,0 +1,161 @@
+"""
+Management команда для проверки и очистки чатов с некорректными типами.
+
+Использование:
+ # Найти все чаты с некорректными типами
+ python manage.py check_chats --find
+
+ # Проверить конкретный чат
+ python manage.py check_chats --check 6
+
+ # Удалить все чаты с некорректными типами
+ python manage.py check_chats --cleanup
+
+ # Удалить конкретный чат
+ python manage.py check_chats --delete 6
+"""
+
+from django.core.management.base import BaseCommand, CommandError
+from communications.models import Chat
+
+VALID_TYPES = ["private", "group", "channel", "announcement", "global", "comments"]
+
+
+class Command(BaseCommand):
+ help = 'Проверка и очистка чатов с некорректными типами'
+
+ def add_arguments(self, parser):
+ parser.add_argument(
+ '--find',
+ action='store_true',
+ help='Найти все чаты с некорректными типами',
+ )
+ parser.add_argument(
+ '--check',
+ type=int,
+ metavar='CHAT_ID',
+ help='Проверить конкретный чат по ID',
+ )
+ parser.add_argument(
+ '--cleanup',
+ action='store_true',
+ help='Удалить все чаты с некорректными типами',
+ )
+ parser.add_argument(
+ '--delete',
+ type=int,
+ metavar='CHAT_ID',
+ help='Удалить конкретный чат по ID',
+ )
+ parser.add_argument(
+ '--no-confirm',
+ action='store_true',
+ help='Не запрашивать подтверждение при удалении',
+ )
+
+ def handle(self, *args, **options):
+ if options['find']:
+ self.find_invalid_chats()
+ elif options['check']:
+ self.check_chat(options['check'])
+ elif options['cleanup']:
+ self.cleanup_invalid_chats(no_confirm=options['no_confirm'])
+ elif options['delete']:
+ self.delete_chat(options['delete'], no_confirm=options['no_confirm'])
+ else:
+ self.stdout.write(self.style.ERROR('Укажите действие: --find, --check, --cleanup или --delete'))
+ self.stdout.write('Используйте --help для справки')
+
+ def find_invalid_chats(self):
+ """Находит все чаты с некорректными типами"""
+ invalid_chats = Chat.objects.exclude(type__in=VALID_TYPES)
+
+ if not invalid_chats.exists():
+ self.stdout.write(self.style.SUCCESS('✅ Все чаты имеют корректные типы'))
+ return
+
+ count = invalid_chats.count()
+ self.stdout.write(self.style.WARNING(f'⚠️ Найдено {count} чатов с некорректными типами:\n'))
+
+ for chat in invalid_chats:
+ self.stdout.write(f'ID {chat.id}:')
+ self.stdout.write(f' Название: {chat.name}')
+ self.stdout.write(f' Тип: {chat.type}')
+ self.stdout.write(f' Участников: {chat.participants.count()}')
+ self.stdout.write(f' Создан: {chat.created_at}')
+ self.stdout.write('')
+
+ self.stdout.write(self.style.WARNING(f'Всего найдено: {count} чатов'))
+ self.stdout.write(self.style.NOTICE('Для удаления используйте: python manage.py check_chats --cleanup'))
+
+ def check_chat(self, chat_id):
+ """Проверяет конкретный чат"""
+ try:
+ chat = Chat.objects.get(id=chat_id)
+ except Chat.DoesNotExist:
+ raise CommandError(f'❌ Чат с ID {chat_id} не найден')
+
+ self.stdout.write(f'Чат ID {chat_id}:')
+ self.stdout.write(f' Название: {chat.name}')
+ self.stdout.write(f' Тип: {chat.type}')
+ self.stdout.write(f' Участников: {chat.participants.count()}')
+ self.stdout.write(f' Создан: {chat.created_at}')
+
+ if chat.type not in VALID_TYPES:
+ self.stdout.write(self.style.ERROR(f'\n⚠️ Чат имеет некорректный тип: {chat.type}'))
+ self.stdout.write(self.style.NOTICE(f'Допустимые типы: {", ".join(VALID_TYPES)}'))
+ self.stdout.write(self.style.NOTICE(f'Для удаления используйте: python manage.py check_chats --delete {chat_id}'))
+ else:
+ self.stdout.write(self.style.SUCCESS(f'\n✅ Чат в порядке, тип корректен'))
+
+ def cleanup_invalid_chats(self, no_confirm=False):
+ """Удаляет все чаты с некорректными типами"""
+ invalid_chats = Chat.objects.exclude(type__in=VALID_TYPES)
+
+ if not invalid_chats.exists():
+ self.stdout.write(self.style.SUCCESS('✅ Все чаты имеют корректные типы'))
+ return
+
+ count = invalid_chats.count()
+ self.stdout.write(self.style.WARNING(f'⚠️ Найдено {count} чатов с некорректными типами\n'))
+ self.stdout.write('Чаты для удаления:')
+
+ for chat in invalid_chats:
+ self.stdout.write(f' • ID {chat.id}: {chat.name} (тип: {chat.type})')
+
+ if not no_confirm:
+ confirm = input(f'\n⚠️ Удалить {count} чатов? (yes/no): ')
+ if confirm.lower() not in ['yes', 'y', 'да']:
+ self.stdout.write(self.style.ERROR('❌ Отменено'))
+ return
+
+ deleted, details = invalid_chats.delete()
+ self.stdout.write(self.style.SUCCESS(f'\n✅ Успешно удалено {deleted} объектов'))
+
+ # Показываем детали удаления
+ if details:
+ self.stdout.write('\nУдалено объектов по типам:')
+ for model, count in details.items():
+ self.stdout.write(f' • {model}: {count}')
+
+ def delete_chat(self, chat_id, no_confirm=False):
+ """Удаляет конкретный чат"""
+ try:
+ chat = Chat.objects.get(id=chat_id)
+ except Chat.DoesNotExist:
+ raise CommandError(f'❌ Чат с ID {chat_id} не найден')
+
+ self.stdout.write(f'Удаление чата ID {chat_id}:')
+ self.stdout.write(f' Название: {chat.name}')
+ self.stdout.write(f' Тип: {chat.type}')
+ self.stdout.write(f' Участников: {chat.participants.count()}')
+
+ if not no_confirm:
+ confirm = input('\n⚠️ Подтвердите удаление (yes/no): ')
+ if confirm.lower() not in ['yes', 'y', 'да']:
+ self.stdout.write(self.style.ERROR('❌ Отменено'))
+ return
+
+ chat_name = chat.name
+ chat.delete()
+ self.stdout.write(self.style.SUCCESS(f'\n✅ Чат "{chat_name}" (ID {chat_id}) успешно удален'))
diff --git a/frontend/src/app/messages/page.tsx b/frontend/src/app/messages/page.tsx
index b6c6abf7..a77fd735 100644
--- a/frontend/src/app/messages/page.tsx
+++ b/frontend/src/app/messages/page.tsx
@@ -5,7 +5,7 @@ import { AppShell } from "../../components/AppShell";
import { apiClient } from "@/lib/api";
import { resolveMediaUrl } from "@/lib/url";
import type { Chat } from "@/types/api";
-import { Search, MessageCircle, Pin, BellOff, Filter, Plus, X, Users, Globe, Radio, Upload, Image as ImageIcon } from "lucide-react";
+import { Search, MessageCircle, Pin, BellOff, Filter, Plus, X, Users, Globe, Radio, Upload, Image as ImageIcon, Megaphone, MessageSquare } from "lucide-react";
import Link from "next/link";
import Image from "next/image";
import { useUser } from "@/contexts/UserContext";
@@ -111,6 +111,27 @@ function getChatInitials(chat: Chat, currentUserId?: number, currentUser?: { fir
.join("") || "Ч";
}
+function getChatTypeIcon(chat: Chat) {
+ const chatType = chat.chat_type || chat.type;
+ switch (chatType) {
+ case 'global':
+ return ;
+ case 'channel':
+ return ;
+ case 'group':
+ return ;
+ case 'private':
+ case 'direct':
+ return ;
+ case 'announcement':
+ return ;
+ case 'comments':
+ return ;
+ default:
+ return null;
+ }
+}
+
function formatTime(date?: string): string {
if (!date) return "";
const d = new Date(date);
@@ -685,9 +706,15 @@ export default function MessagesPage() {
getChatInitials(chat, currentUserId, currentUserForMatch)
)}
+ {/* Иконка типа чата */}
+
+ {getChatTypeIcon(chat)}
+
+ {/* Онлайн-статус */}
{isChatOnline(chat, user?.id) ? (
) : null}
+ {/* Счетчик непрочитанных */}
{(chat.unread_count ?? 0) > 0 ? (
{chat.unread_count! > 99 ? '99+' : chat.unread_count}