Исправлено: встраивание веб-версий мессенджеров через iframe вместо интеграции. Удалена проблемная миграция.
This commit is contained in:
parent
95739f287b
commit
750a2c5da8
@ -1,88 +0,0 @@
|
||||
# Быстрый старт: Настройка интеграции мессенджеров
|
||||
|
||||
## Что было добавлено:
|
||||
|
||||
✅ **3 новые модели базы данных:**
|
||||
- `MessengerIntegration` - настройки подключения
|
||||
- `MessengerAccount` - привязка аккаунтов сотрудников
|
||||
- `MessengerMessage` - синхронизация сообщений
|
||||
|
||||
✅ **Админ-панель** для управления интеграциями
|
||||
|
||||
✅ **Страницы мессенджеров** с инструкциями
|
||||
|
||||
## Как начать:
|
||||
|
||||
### 1. Откройте админ-панель
|
||||
|
||||
Перейдите: http://localhost:9000/admin/communications/
|
||||
|
||||
Вы увидите новые разделы:
|
||||
- **Интеграции с мессенджерами**
|
||||
- **Аккаунты в мессенджерах**
|
||||
- **Сообщения из мессенджеров**
|
||||
|
||||
### 2. Создайте интеграцию (пример для Telegram)
|
||||
|
||||
1. Нажмите "Интеграции с мессенджерами" → "Добавить"
|
||||
|
||||
2. Заполните:
|
||||
- **Тип мессенджера**: Telegram
|
||||
- **Включена**: ✓
|
||||
- **Статус**: Active
|
||||
- **API ключ**: (получите от @BotFather в Telegram)
|
||||
|
||||
3. Сохраните
|
||||
|
||||
### 3. Проверьте результат
|
||||
|
||||
Перейдите в раздел "Мои чаты":
|
||||
- В боковой панели появились иконки мессенджеров
|
||||
- Кликните на иконку Telegram
|
||||
- Вы увидите страницу с инструкциями
|
||||
|
||||
Если вы администратор:
|
||||
- Появится кнопка "Настроить интеграцию"
|
||||
- Будут видны подробные инструкции
|
||||
|
||||
## Для администраторов
|
||||
|
||||
### Получение API ключей:
|
||||
|
||||
**Telegram (самый простой):**
|
||||
1. Откройте @BotFather в Telegram
|
||||
2. Отправьте `/newbot`
|
||||
3. Следуйте инструкциям
|
||||
4. Скопируйте Bot Token
|
||||
5. Вставьте в админ-панель
|
||||
|
||||
**WhatsApp Business API:**
|
||||
1. https://business.whatsapp.com/
|
||||
2. Создайте приложение в Facebook for Developers
|
||||
3. Получите Access Token
|
||||
|
||||
**WeChat:**
|
||||
1. https://mp.weixin.qq.com/
|
||||
2. Зарегистрируйте Official Account
|
||||
3. Получите AppID и AppSecret
|
||||
|
||||
### Полная документация
|
||||
|
||||
📖 См. файл `MESSENGER_INTEGRATION_GUIDE.md` для детальных инструкций по:
|
||||
- Настройке webhooks
|
||||
- Привязке аккаунтов сотрудников
|
||||
- Синхронизации сообщений
|
||||
- Безопасности
|
||||
- Мониторингу
|
||||
- Troubleshooting
|
||||
|
||||
## Следующие шаги (для разработки)
|
||||
|
||||
Для полноценной работы интеграций потребуется реализовать:
|
||||
|
||||
1. **Webhook handlers** - обработка входящих сообщений
|
||||
2. **Sync services** - синхронизация сообщений
|
||||
3. **API endpoints** - для отправки сообщений
|
||||
4. **Celery tasks** - фоновая синхронизация
|
||||
|
||||
Базовая инфраструктура готова, можно начинать интеграцию!
|
||||
@ -1,316 +0,0 @@
|
||||
# Настройка интеграции мессенджеров
|
||||
|
||||
Этот документ описывает процесс настройки интеграции с WhatsApp, Telegram и WeChat.
|
||||
|
||||
## Архитектура
|
||||
|
||||
Система интеграции состоит из трех основных компонентов:
|
||||
|
||||
1. **MessengerIntegration** - настройки подключения к мессенджеру
|
||||
2. **MessengerAccount** - привязка аккаунтов сотрудников
|
||||
3. **MessengerMessage** - синхронизация сообщений
|
||||
|
||||
## Шаги настройки
|
||||
|
||||
### 1. Доступ к админ-панели
|
||||
|
||||
Перейдите в Django Admin: `http://your-domain/admin/communications/`
|
||||
|
||||
Вы увидите три новых раздела:
|
||||
- Интеграции с мессенджерами
|
||||
- Аккаунты в мессенджерах
|
||||
- Сообщения из мессенджеров
|
||||
|
||||
### 2. Настройка WhatsApp
|
||||
|
||||
#### 2.1. Получение API ключей
|
||||
|
||||
**Вариант A: WhatsApp Business API (официальный)**
|
||||
1. Зарегистрируйтесь на https://business.whatsapp.com/
|
||||
2. Создайте приложение в Facebook for Developers
|
||||
3. Получите `WhatsApp Business Account ID` и `Access Token`
|
||||
|
||||
**Вариант B: WhatsApp Web API (неофициальный, через Baileys/Whatsapp-web.js)**
|
||||
1. Используйте библиотеку для Node.js
|
||||
2. Настройте webhook для получения сообщений
|
||||
3. Получите QR-код для авторизации
|
||||
|
||||
#### 2.2. Настройка в системе
|
||||
|
||||
1. Откройте "Интеграции с мессенджерами" → "Добавить"
|
||||
2. Выберите тип: **WhatsApp**
|
||||
3. Заполните поля:
|
||||
- **Включена**: ✓
|
||||
- **Статус**: Active
|
||||
- **API ключ**: `<ваш Access Token>`
|
||||
- **Webhook URL**: `https://your-domain/communications/webhooks/whatsapp/`
|
||||
|
||||
4. В разделе "Дополнительные настройки" (JSON):
|
||||
```json
|
||||
{
|
||||
"phone_number_id": "YOUR_PHONE_NUMBER_ID",
|
||||
"business_account_id": "YOUR_BUSINESS_ACCOUNT_ID",
|
||||
"verify_token": "YOUR_WEBHOOK_VERIFY_TOKEN"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3. Настройка webhook на стороне WhatsApp
|
||||
|
||||
1. В Facebook for Developers → WhatsApp → Configuration
|
||||
2. Укажите webhook URL: `https://your-domain/communications/webhooks/whatsapp/`
|
||||
3. Укажите Verify Token (из настроек выше)
|
||||
4. Подпишитесь на события: `messages`, `message_status`
|
||||
|
||||
### 3. Настройка Telegram
|
||||
|
||||
#### 3.1. Создание бота
|
||||
|
||||
1. Найдите @BotFather в Telegram
|
||||
2. Отправьте команду `/newbot`
|
||||
3. Следуйте инструкциям для создания бота
|
||||
4. Получите **Bot Token** (формат: `123456789:ABCdefGHIjklMNOpqrsTUVwxyz`)
|
||||
|
||||
#### 3.2. Настройка в системе
|
||||
|
||||
1. Откройте "Интеграции с мессенджерами" → "Добавить"
|
||||
2. Выберите тип: **Telegram**
|
||||
3. Заполните поля:
|
||||
- **Включена**: ✓
|
||||
- **Статус**: Active
|
||||
- **API ключ**: `<Bot Token от BotFather>`
|
||||
- **Webhook URL**: `https://your-domain/communications/webhooks/telegram/`
|
||||
|
||||
4. В разделе "Дополнительные настройки":
|
||||
```json
|
||||
{
|
||||
"bot_username": "your_bot_name",
|
||||
"allowed_updates": ["message", "edited_message", "callback_query"]
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3. Установка webhook
|
||||
|
||||
Выполните запрос (замените токен):
|
||||
```bash
|
||||
curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"url": "https://your-domain/communications/webhooks/telegram/"}'
|
||||
```
|
||||
|
||||
### 4. Настройка WeChat
|
||||
|
||||
#### 4.1. Регистрация WeChat Official Account
|
||||
|
||||
1. Зарегистрируйтесь на https://mp.weixin.qq.com/
|
||||
2. Создайте Official Account
|
||||
3. Получите `AppID` и `AppSecret`
|
||||
|
||||
#### 4.2. Настройка в системе
|
||||
|
||||
1. Откройте "Интеграции с мессенджерами" → "Добавить"
|
||||
2. Выберите тип: **WeChat**
|
||||
3. Заполните поля:
|
||||
- **Включена**: ✓
|
||||
- **Статус**: Active
|
||||
- **API ключ**: `<AppID>`
|
||||
- **API секрет**: `<AppSecret>`
|
||||
- **Webhook URL**: `https://your-domain/communications/webhooks/wechat/`
|
||||
|
||||
4. В разделе "Дополнительные настройки":
|
||||
```json
|
||||
{
|
||||
"token": "YOUR_TOKEN",
|
||||
"encoding_aes_key": "YOUR_ENCODING_AES_KEY"
|
||||
}
|
||||
```
|
||||
|
||||
## Привязка аккаунтов сотрудников
|
||||
|
||||
После настройки интеграции нужно привязать аккаунты сотрудников:
|
||||
|
||||
### Автоматическая привязка
|
||||
|
||||
Сотрудники могут сами привязать аккаунты:
|
||||
1. Перейти в профиль → "Мессенджеры"
|
||||
2. Выбрать мессенджер
|
||||
3. Следовать инструкциям (QR-код, код подтверждения и т.д.)
|
||||
|
||||
### Ручная привязка (админ)
|
||||
|
||||
1. Откройте "Аккаунты в мессенджерах" → "Добавить"
|
||||
2. Выберите пользователя
|
||||
3. Выберите интеграцию
|
||||
4. Укажите:
|
||||
- **External ID**: ID пользователя в мессенджере
|
||||
- **External Username**: Имя/никнейм
|
||||
- **Phone Number**: Телефон (для WhatsApp)
|
||||
5. Установите галочку "Подтвержден"
|
||||
|
||||
## Синхронизация сообщений
|
||||
|
||||
### Настройка Celery задач
|
||||
|
||||
Добавьте в `celery.py`:
|
||||
|
||||
```python
|
||||
from celery.schedules import crontab
|
||||
|
||||
app.conf.beat_schedule = {
|
||||
'sync-messenger-messages': {
|
||||
'task': 'communications.tasks.sync_messenger_messages',
|
||||
'schedule': 60.0, # каждую минуту
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Ручная синхронизация
|
||||
|
||||
Через Django shell:
|
||||
|
||||
```python
|
||||
from communications.services.messenger_sync import MessengerSyncService
|
||||
|
||||
# Синхронизация всех мессенджеров
|
||||
sync_service = MessengerSyncService()
|
||||
sync_service.sync_all()
|
||||
|
||||
# Синхронизация конкретного мессенджера
|
||||
sync_service.sync_messenger('whatsapp')
|
||||
```
|
||||
|
||||
## Webhook эндпоинты
|
||||
|
||||
Система автоматически создает эндпоинты для получения входящих сообщений:
|
||||
|
||||
- **WhatsApp**: `POST /communications/webhooks/whatsapp/`
|
||||
- **Telegram**: `POST /communications/webhooks/telegram/`
|
||||
- **WeChat**: `POST /communications/webhooks/wechat/`
|
||||
|
||||
Эти URL должны быть доступны извне (HTTPS обязателен для production).
|
||||
|
||||
## Безопасность
|
||||
|
||||
### Шифрование API ключей
|
||||
|
||||
В production используйте `django-cryptography` для шифрования:
|
||||
|
||||
```python
|
||||
# settings.py
|
||||
INSTALLED_APPS = [
|
||||
...
|
||||
'django_cryptography',
|
||||
]
|
||||
|
||||
# Генерация ключа
|
||||
from cryptography.fernet import Fernet
|
||||
FIELD_ENCRYPTION_KEY = Fernet.generate_key().decode()
|
||||
```
|
||||
|
||||
Обновите модель:
|
||||
```python
|
||||
from django_cryptography.fields import encrypt
|
||||
|
||||
class MessengerIntegration(models.Model):
|
||||
api_key = encrypt(models.CharField(max_length=500))
|
||||
api_secret = encrypt(models.CharField(max_length=500))
|
||||
```
|
||||
|
||||
### Проверка подписи webhook
|
||||
|
||||
Всегда проверяйте подпись входящих запросов:
|
||||
|
||||
```python
|
||||
# views.py
|
||||
def verify_whatsapp_signature(request):
|
||||
signature = request.headers.get('X-Hub-Signature-256')
|
||||
# Проверка HMAC
|
||||
...
|
||||
```
|
||||
|
||||
## Мониторинг
|
||||
|
||||
### Просмотр статистики
|
||||
|
||||
В админ-панели "Интеграции с мессенджерами" отображается:
|
||||
- Количество отправленных сообщений
|
||||
- Количество полученных сообщений
|
||||
- Время последней синхронизации
|
||||
- Последняя ошибка (если есть)
|
||||
|
||||
### Логирование
|
||||
|
||||
Все операции логируются:
|
||||
|
||||
```python
|
||||
import logging
|
||||
logger = logging.getLogger('communications.messenger')
|
||||
|
||||
# В settings.py
|
||||
LOGGING = {
|
||||
'loggers': {
|
||||
'communications.messenger': {
|
||||
'level': 'INFO',
|
||||
'handlers': ['file'],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Проблема: Webhook не получает сообщения
|
||||
|
||||
1. Проверьте, что URL доступен извне:
|
||||
```bash
|
||||
curl https://your-domain/communications/webhooks/telegram/
|
||||
```
|
||||
|
||||
2. Проверьте SSL сертификат (должен быть валидным)
|
||||
|
||||
3. Проверьте логи Django:
|
||||
```bash
|
||||
tail -f logs/django.log | grep webhook
|
||||
```
|
||||
|
||||
### Проблема: Сообщения не синхронизируются
|
||||
|
||||
1. Проверьте статус интеграции (должен быть "Active")
|
||||
2. Проверьте поле "Последняя ошибка"
|
||||
3. Запустите синхронизацию вручную через shell
|
||||
4. Проверьте Celery tasks (если используется)
|
||||
|
||||
### Проблема: Неверный API ключ
|
||||
|
||||
1. Перегенерируйте ключ в соответствующем сервисе
|
||||
2. Обновите в админ-панели
|
||||
3. Измените статус на "Active" после обновления
|
||||
|
||||
## Дальнейшее развитие
|
||||
|
||||
### Планируемые функции
|
||||
|
||||
- [ ] Групповые чаты в мессенджерах
|
||||
- [ ] Отправка медиа-файлов
|
||||
- [ ] Голосовые сообщения
|
||||
- [ ] Статусы доставки
|
||||
- [ ] Typing indicators
|
||||
- [ ] Реакции на сообщения
|
||||
- [ ] Шаблоны сообщений для WhatsApp Business
|
||||
|
||||
### API endpoints для разработчиков
|
||||
|
||||
```
|
||||
POST /api/v1/messenger/send/
|
||||
GET /api/v1/messenger/accounts/
|
||||
GET /api/v1/messenger/messages/
|
||||
POST /api/v1/messenger/link-account/
|
||||
```
|
||||
|
||||
Документация API: `https://your-domain/api/docs/`
|
||||
|
||||
## Поддержка
|
||||
|
||||
При возникновении проблем:
|
||||
1. Проверьте документацию мессенджера
|
||||
2. Проверьте логи системы
|
||||
3. Обратитесь к системному администратору
|
||||
@ -8,9 +8,6 @@ from .models import (
|
||||
Message,
|
||||
MessageAttachment,
|
||||
MessageReply,
|
||||
MessengerIntegration,
|
||||
MessengerAccount,
|
||||
MessengerMessage,
|
||||
)
|
||||
|
||||
|
||||
@ -172,176 +169,3 @@ class CrossChatMessageAdmin(admin.ModelAdmin):
|
||||
list_filter = ("status", "requires_moderation", "sent_at")
|
||||
search_fields = ("sender__last_name", "target_chat__name")
|
||||
ordering = ("-sent_at",)
|
||||
|
||||
|
||||
# ===== АДМИН-ПАНЕЛЬ ДЛЯ ИНТЕГРАЦИЙ С МЕССЕНДЖЕРАМИ =====
|
||||
|
||||
@admin.register(MessengerIntegration)
|
||||
class MessengerIntegrationAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"messenger_type",
|
||||
"is_enabled",
|
||||
"status",
|
||||
"messages_sent",
|
||||
"messages_received",
|
||||
"last_sync_at",
|
||||
"updated_at"
|
||||
)
|
||||
list_filter = ("messenger_type", "is_enabled", "status")
|
||||
search_fields = ("messenger_type",)
|
||||
ordering = ("messenger_type",)
|
||||
|
||||
fieldsets = (
|
||||
("Основная информация", {
|
||||
"fields": ("messenger_type", "is_enabled", "status")
|
||||
}),
|
||||
("API Настройки", {
|
||||
"fields": ("api_key", "api_secret", "webhook_url", "settings"),
|
||||
"classes": ("collapse",)
|
||||
}),
|
||||
("Статистика", {
|
||||
"fields": (
|
||||
"messages_sent",
|
||||
"messages_received",
|
||||
"last_sync_at",
|
||||
"last_error"
|
||||
),
|
||||
"classes": ("collapse",)
|
||||
}),
|
||||
("Системная информация", {
|
||||
"fields": ("created_at", "updated_at"),
|
||||
"classes": ("collapse",)
|
||||
}),
|
||||
)
|
||||
|
||||
readonly_fields = (
|
||||
"messages_sent",
|
||||
"messages_received",
|
||||
"last_sync_at",
|
||||
"created_at",
|
||||
"updated_at"
|
||||
)
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
if obj and obj.status == 'active':
|
||||
return self.readonly_fields + ("messenger_type",)
|
||||
return self.readonly_fields
|
||||
|
||||
|
||||
@admin.register(MessengerAccount)
|
||||
class MessengerAccountAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"user",
|
||||
"integration",
|
||||
"external_username",
|
||||
"phone_number",
|
||||
"is_verified",
|
||||
"is_active",
|
||||
"updated_at"
|
||||
)
|
||||
list_filter = (
|
||||
"integration__messenger_type",
|
||||
"is_verified",
|
||||
"is_active"
|
||||
)
|
||||
search_fields = (
|
||||
"user__last_name",
|
||||
"user__first_name",
|
||||
"external_username",
|
||||
"phone_number",
|
||||
"external_id"
|
||||
)
|
||||
ordering = ("-created_at",)
|
||||
|
||||
fieldsets = (
|
||||
("Пользователь", {
|
||||
"fields": ("user", "integration")
|
||||
}),
|
||||
("Данные в мессенджере", {
|
||||
"fields": (
|
||||
"external_id",
|
||||
"external_username",
|
||||
"phone_number"
|
||||
)
|
||||
}),
|
||||
("Статус", {
|
||||
"fields": ("is_verified", "is_active")
|
||||
}),
|
||||
("Дополнительно", {
|
||||
"fields": ("metadata",),
|
||||
"classes": ("collapse",)
|
||||
}),
|
||||
("Системная информация", {
|
||||
"fields": ("created_at", "updated_at"),
|
||||
"classes": ("collapse",)
|
||||
}),
|
||||
)
|
||||
|
||||
readonly_fields = ("created_at", "updated_at")
|
||||
|
||||
|
||||
@admin.register(MessengerMessage)
|
||||
class MessengerMessageAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"id",
|
||||
"integration",
|
||||
"direction",
|
||||
"status",
|
||||
"sender_account",
|
||||
"content_preview",
|
||||
"external_timestamp",
|
||||
"synced_at"
|
||||
)
|
||||
list_filter = (
|
||||
"integration__messenger_type",
|
||||
"direction",
|
||||
"status",
|
||||
"external_timestamp"
|
||||
)
|
||||
search_fields = (
|
||||
"external_id",
|
||||
"content",
|
||||
"sender_account__external_username"
|
||||
)
|
||||
ordering = ("-external_timestamp",)
|
||||
|
||||
fieldsets = (
|
||||
("Основная информация", {
|
||||
"fields": (
|
||||
"integration",
|
||||
"internal_message",
|
||||
"external_id"
|
||||
)
|
||||
}),
|
||||
("Участники", {
|
||||
"fields": (
|
||||
"sender_account",
|
||||
"recipient_account",
|
||||
"direction"
|
||||
)
|
||||
}),
|
||||
("Содержимое", {
|
||||
"fields": ("content", "attachments")
|
||||
}),
|
||||
("Статус и время", {
|
||||
"fields": (
|
||||
"status",
|
||||
"external_timestamp",
|
||||
"synced_at"
|
||||
)
|
||||
}),
|
||||
("Дополнительно", {
|
||||
"fields": ("raw_data",),
|
||||
"classes": ("collapse",)
|
||||
}),
|
||||
)
|
||||
|
||||
readonly_fields = ("synced_at",)
|
||||
|
||||
def content_preview(self, obj):
|
||||
"""Превью содержимого сообщения"""
|
||||
if len(obj.content) > 50:
|
||||
return obj.content[:50] + "..."
|
||||
return obj.content
|
||||
|
||||
content_preview.short_description = "Содержимое"
|
||||
|
||||
@ -850,289 +850,3 @@ class ChatMembership(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user} в {self.chat} ({self.get_role_display()})"
|
||||
|
||||
|
||||
# ===== МОДЕЛИ ДЛЯ ИНТЕГРАЦИИ МЕССЕНДЖЕРОВ =====
|
||||
|
||||
class MessengerIntegration(models.Model):
|
||||
"""
|
||||
Настройки интеграции с внешними мессенджерами (WhatsApp, Telegram, WeChat)
|
||||
"""
|
||||
MESSENGER_TYPES = [
|
||||
('whatsapp', 'WhatsApp'),
|
||||
('telegram', 'Telegram'),
|
||||
('wechat', 'WeChat'),
|
||||
]
|
||||
|
||||
STATUS_CHOICES = [
|
||||
('inactive', 'Не активна'),
|
||||
('active', 'Активна'),
|
||||
('error', 'Ошибка'),
|
||||
]
|
||||
|
||||
messenger_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=MESSENGER_TYPES,
|
||||
unique=True,
|
||||
verbose_name="Тип мессенджера"
|
||||
)
|
||||
|
||||
is_enabled = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="Включена"
|
||||
)
|
||||
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
default='inactive',
|
||||
verbose_name="Статус"
|
||||
)
|
||||
|
||||
# API настройки (зашифрованы в production)
|
||||
api_key = models.CharField(
|
||||
max_length=500,
|
||||
blank=True,
|
||||
verbose_name="API ключ"
|
||||
)
|
||||
|
||||
api_secret = models.CharField(
|
||||
max_length=500,
|
||||
blank=True,
|
||||
verbose_name="API секрет"
|
||||
)
|
||||
|
||||
webhook_url = models.URLField(
|
||||
max_length=500,
|
||||
blank=True,
|
||||
verbose_name="Webhook URL"
|
||||
)
|
||||
|
||||
# Дополнительные настройки (JSON)
|
||||
settings = models.JSONField(
|
||||
default=dict,
|
||||
blank=True,
|
||||
verbose_name="Дополнительные настройки"
|
||||
)
|
||||
|
||||
# Статистика
|
||||
last_sync_at = models.DateTimeField(
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name="Последняя синхронизация"
|
||||
)
|
||||
|
||||
messages_sent = models.IntegerField(
|
||||
default=0,
|
||||
verbose_name="Отправлено сообщений"
|
||||
)
|
||||
|
||||
messages_received = models.IntegerField(
|
||||
default=0,
|
||||
verbose_name="Получено сообщений"
|
||||
)
|
||||
|
||||
last_error = models.TextField(
|
||||
blank=True,
|
||||
verbose_name="Последняя ошибка"
|
||||
)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Создано")
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name="Обновлено")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Интеграция с мессенджером"
|
||||
verbose_name_plural = "Интеграции с мессенджерами"
|
||||
indexes = [
|
||||
models.Index(fields=['messenger_type', 'is_enabled']),
|
||||
models.Index(fields=['status']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_messenger_type_display()} - {self.get_status_display()}"
|
||||
|
||||
|
||||
class MessengerAccount(models.Model):
|
||||
"""
|
||||
Привязка аккаунта сотрудника к мессенджеру
|
||||
"""
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='messenger_accounts',
|
||||
verbose_name="Пользователь"
|
||||
)
|
||||
|
||||
integration = models.ForeignKey(
|
||||
MessengerIntegration,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='accounts',
|
||||
verbose_name="Интеграция"
|
||||
)
|
||||
|
||||
# ID пользователя в мессенджере
|
||||
external_id = models.CharField(
|
||||
max_length=200,
|
||||
verbose_name="ID в мессенджере"
|
||||
)
|
||||
|
||||
# Имя/никнейм в мессенджере
|
||||
external_username = models.CharField(
|
||||
max_length=200,
|
||||
blank=True,
|
||||
verbose_name="Имя в мессенджере"
|
||||
)
|
||||
|
||||
# Телефон (для WhatsApp)
|
||||
phone_number = models.CharField(
|
||||
max_length=20,
|
||||
blank=True,
|
||||
verbose_name="Номер телефона"
|
||||
)
|
||||
|
||||
is_verified = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="Подтвержден"
|
||||
)
|
||||
|
||||
is_active = models.BooleanField(
|
||||
default=True,
|
||||
verbose_name="Активен"
|
||||
)
|
||||
|
||||
# Дополнительные данные
|
||||
metadata = models.JSONField(
|
||||
default=dict,
|
||||
blank=True,
|
||||
verbose_name="Метаданные"
|
||||
)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Создано")
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name="Обновлено")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Аккаунт в мессенджере"
|
||||
verbose_name_plural = "Аккаунты в мессенджерах"
|
||||
unique_together = [('integration', 'external_id')]
|
||||
indexes = [
|
||||
models.Index(fields=['user', 'integration']),
|
||||
models.Index(fields=['external_id']),
|
||||
models.Index(fields=['phone_number']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user} - {self.integration.get_messenger_type_display()} ({self.external_username or self.external_id})"
|
||||
|
||||
|
||||
class MessengerMessage(models.Model):
|
||||
"""
|
||||
Синхронизированные сообщения из внешних мессенджеров
|
||||
"""
|
||||
DIRECTION_CHOICES = [
|
||||
('incoming', 'Входящее'),
|
||||
('outgoing', 'Исходящее'),
|
||||
]
|
||||
|
||||
STATUS_CHOICES = [
|
||||
('pending', 'В ожидании'),
|
||||
('sent', 'Отправлено'),
|
||||
('delivered', 'Доставлено'),
|
||||
('read', 'Прочитано'),
|
||||
('failed', 'Ошибка'),
|
||||
]
|
||||
|
||||
integration = models.ForeignKey(
|
||||
MessengerIntegration,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='messenger_messages',
|
||||
verbose_name="Интеграция"
|
||||
)
|
||||
|
||||
# Связь с внутренним сообщением (если синхронизировано)
|
||||
internal_message = models.OneToOneField(
|
||||
Message,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='messenger_sync',
|
||||
verbose_name="Внутреннее сообщение"
|
||||
)
|
||||
|
||||
# ID сообщения во внешнем мессенджере
|
||||
external_id = models.CharField(
|
||||
max_length=200,
|
||||
verbose_name="ID в мессенджере"
|
||||
)
|
||||
|
||||
# Отправитель/получатель
|
||||
sender_account = models.ForeignKey(
|
||||
MessengerAccount,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
related_name='sent_messages',
|
||||
verbose_name="Отправитель"
|
||||
)
|
||||
|
||||
recipient_account = models.ForeignKey(
|
||||
MessengerAccount,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='received_messages',
|
||||
verbose_name="Получатель"
|
||||
)
|
||||
|
||||
direction = models.CharField(
|
||||
max_length=10,
|
||||
choices=DIRECTION_CHOICES,
|
||||
verbose_name="Направление"
|
||||
)
|
||||
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
default='pending',
|
||||
verbose_name="Статус"
|
||||
)
|
||||
|
||||
# Содержимое
|
||||
content = models.TextField(verbose_name="Текст")
|
||||
|
||||
# Вложения (JSON с URLs)
|
||||
attachments = models.JSONField(
|
||||
default=list,
|
||||
blank=True,
|
||||
verbose_name="Вложения"
|
||||
)
|
||||
|
||||
# Временные метки
|
||||
external_timestamp = models.DateTimeField(
|
||||
verbose_name="Время в мессенджере"
|
||||
)
|
||||
|
||||
synced_at = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
verbose_name="Синхронизировано"
|
||||
)
|
||||
|
||||
# Дополнительные данные из мессенджера
|
||||
raw_data = models.JSONField(
|
||||
default=dict,
|
||||
blank=True,
|
||||
verbose_name="Исходные данные"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Сообщение из мессенджера"
|
||||
verbose_name_plural = "Сообщения из мессенджеров"
|
||||
unique_together = [('integration', 'external_id')]
|
||||
indexes = [
|
||||
models.Index(fields=['integration', 'external_timestamp']),
|
||||
models.Index(fields=['sender_account', 'external_timestamp']),
|
||||
models.Index(fields=['status']),
|
||||
models.Index(fields=['-synced_at']),
|
||||
]
|
||||
ordering = ['-external_timestamp']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.integration.get_messenger_type_display()} - {self.external_id}"
|
||||
|
||||
@ -460,22 +460,10 @@ def chat_mark_read(request, pk: int):
|
||||
def whatsapp_view(request):
|
||||
"""WhatsApp интеграция"""
|
||||
from django.shortcuts import render
|
||||
from .models import MessengerIntegration
|
||||
|
||||
try:
|
||||
integration = MessengerIntegration.objects.get(
|
||||
messenger_type='whatsapp'
|
||||
)
|
||||
integration_status = integration.status if integration.is_enabled else 'inactive'
|
||||
except MessengerIntegration.DoesNotExist:
|
||||
integration_status = 'not_configured'
|
||||
|
||||
return render(request, 'communications/messengers/whatsapp.html', {
|
||||
'messenger_name': 'WhatsApp',
|
||||
'messenger_icon': 'bi-whatsapp',
|
||||
'messenger_color': '#25D366',
|
||||
'integration_status': integration_status,
|
||||
'is_admin': request.user.is_staff or request.user.is_superuser,
|
||||
'messenger_color': '#25D366'
|
||||
})
|
||||
|
||||
|
||||
@ -483,22 +471,10 @@ def whatsapp_view(request):
|
||||
def telegram_view(request):
|
||||
"""Telegram интеграция"""
|
||||
from django.shortcuts import render
|
||||
from .models import MessengerIntegration
|
||||
|
||||
try:
|
||||
integration = MessengerIntegration.objects.get(
|
||||
messenger_type='telegram'
|
||||
)
|
||||
integration_status = integration.status if integration.is_enabled else 'inactive'
|
||||
except MessengerIntegration.DoesNotExist:
|
||||
integration_status = 'not_configured'
|
||||
|
||||
return render(request, 'communications/messengers/telegram.html', {
|
||||
'messenger_name': 'Telegram',
|
||||
'messenger_icon': 'bi-telegram',
|
||||
'messenger_color': '#0088cc',
|
||||
'integration_status': integration_status,
|
||||
'is_admin': request.user.is_staff or request.user.is_superuser,
|
||||
'messenger_color': '#0088cc'
|
||||
})
|
||||
|
||||
|
||||
@ -506,20 +482,8 @@ def telegram_view(request):
|
||||
def wechat_view(request):
|
||||
"""WeChat интеграция"""
|
||||
from django.shortcuts import render
|
||||
from .models import MessengerIntegration
|
||||
|
||||
try:
|
||||
integration = MessengerIntegration.objects.get(
|
||||
messenger_type='wechat'
|
||||
)
|
||||
integration_status = integration.status if integration.is_enabled else 'inactive'
|
||||
except MessengerIntegration.DoesNotExist:
|
||||
integration_status = 'not_configured'
|
||||
|
||||
return render(request, 'communications/messengers/wechat.html', {
|
||||
'messenger_name': 'WeChat',
|
||||
'messenger_icon': 'bi-wechat',
|
||||
'messenger_color': '#09B83E',
|
||||
'integration_status': integration_status,
|
||||
'is_admin': request.user.is_staff or request.user.is_superuser,
|
||||
'messenger_color': '#09B83E'
|
||||
})
|
||||
|
||||
@ -7,130 +7,73 @@
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
|
||||
<style>
|
||||
.messenger-container {
|
||||
min-height: 70vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.messenger-icon {
|
||||
font-size: 6rem;
|
||||
color: {{ messenger_color }};
|
||||
margin-bottom: 2rem;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
}
|
||||
|
||||
.messenger-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 600;
|
||||
color: {{ messenger_color }};
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.messenger-description {
|
||||
font-size: 1.2rem;
|
||||
color: var(--bs-secondary);
|
||||
max-width: 600px;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
.messenger-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.messenger-btn {
|
||||
padding: 0.75rem 2rem;
|
||||
font-size: 1.1rem;
|
||||
.messenger-iframe-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100vh - 180px);
|
||||
min-height: 600px;
|
||||
border: 1px solid var(--bs-border-color);
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.messenger-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
.messenger-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.messenger-loading {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.messenger-loading i {
|
||||
font-size: 3rem;
|
||||
color: {{ messenger_color }};
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="container-fluid px-3">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{% include "includes/components/page_header.html" with icon=messenger_icon title=messenger_name %}
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body messenger-container">
|
||||
<i class="{{ messenger_icon }} messenger-icon"></i>
|
||||
|
||||
<h2 class="messenger-title">{{ messenger_name }} интеграция</h2>
|
||||
|
||||
<p class="messenger-description">
|
||||
{% if integration_status == 'active' %}
|
||||
Интеграция активна. Вы можете отправлять и получать сообщения через Telegram.
|
||||
{% elif integration_status == 'inactive' %}
|
||||
Интеграция не настроена. Обратитесь к администратору для настройки.
|
||||
{% else %}
|
||||
Здесь будет отображаться интеграция с {{ messenger_name }}.
|
||||
Функционал находится в разработке.
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="messenger-actions">
|
||||
<a href="{% url 'communications:chat_list' %}" class="btn btn-outline-secondary messenger-btn">
|
||||
<i class="bi-arrow-left"></i> Вернуться к чатам
|
||||
</a>
|
||||
{% if is_admin %}
|
||||
<a href="/admin/communications/messengerintegration/" class="btn btn-primary messenger-btn" style="background-color: {{ messenger_color }}; border-color: {{ messenger_color }};">
|
||||
<i class="bi-gear"></i> Настроить интеграцию
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-primary messenger-btn" style="background-color: {{ messenger_color }}; border-color: {{ messenger_color }};" disabled>
|
||||
<i class="bi-link-45deg"></i> Подключить {{ messenger_name }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
{% if is_admin %}
|
||||
<div class="alert alert-success d-inline-block">
|
||||
<i class="bi-shield-check"></i> У вас есть права администратора
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<h5>Инструкции для настройки:</h5>
|
||||
<ol class="text-start" style="max-width: 600px; margin: 0 auto;">
|
||||
<li>Создайте бота через @BotFather в Telegram</li>
|
||||
<li>Получите Bot Token</li>
|
||||
<li>Откройте <a href="/admin/communications/messengerintegration/">админ-панель интеграций</a></li>
|
||||
<li>Создайте новую интеграцию для Telegram</li>
|
||||
<li>Укажите Bot Token в поле API ключ</li>
|
||||
<li>Настройте webhook</li>
|
||||
<li>Активируйте интеграцию</li>
|
||||
</ol>
|
||||
<div class="mt-3">
|
||||
<a href="/static/communications/MESSENGER_INTEGRATION_GUIDE.md" target="_blank" class="btn btn-sm btn-outline-info">
|
||||
<i class="bi-book"></i> Полная документация
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info d-inline-block">
|
||||
<i class="bi-info-circle"></i> Для настройки интеграции обратитесь к администратору
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body p-0">
|
||||
<div class="messenger-iframe-container">
|
||||
<div class="messenger-loading">
|
||||
<i class="bi-arrow-repeat"></i>
|
||||
<p class="mt-2 text-muted">Загрузка {{ messenger_name }}...</p>
|
||||
</div>
|
||||
<iframe
|
||||
class="messenger-iframe"
|
||||
src="https://web.telegram.org/"
|
||||
allow="microphone; camera"
|
||||
onload="document.querySelector('.messenger-loading').style.display='none'">
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{% url 'communications:chat_list' %}" class="btn btn-outline-secondary">
|
||||
<i class="bi-arrow-left"></i> Вернуться к чатам
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -7,130 +7,87 @@
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
|
||||
<style>
|
||||
.messenger-container {
|
||||
min-height: 70vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.messenger-icon {
|
||||
font-size: 6rem;
|
||||
color: {{ messenger_color }};
|
||||
margin-bottom: 2rem;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
}
|
||||
|
||||
.messenger-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 600;
|
||||
color: {{ messenger_color }};
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.messenger-description {
|
||||
font-size: 1.2rem;
|
||||
color: var(--bs-secondary);
|
||||
max-width: 600px;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
.messenger-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.messenger-btn {
|
||||
padding: 0.75rem 2rem;
|
||||
font-size: 1.1rem;
|
||||
.messenger-iframe-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100vh - 180px);
|
||||
min-height: 600px;
|
||||
border: 1px solid var(--bs-border-color);
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.messenger-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
.messenger-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.messenger-loading {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.messenger-loading i {
|
||||
font-size: 3rem;
|
||||
color: {{ messenger_color }};
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.wechat-notice {
|
||||
padding: 1rem;
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffc107;
|
||||
border-radius: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="container-fluid px-3">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{% include "includes/components/page_header.html" with icon=messenger_icon title=messenger_name %}
|
||||
|
||||
<div class="wechat-notice">
|
||||
<i class="bi-info-circle text-warning"></i>
|
||||
<strong>Внимание:</strong> WeChat не имеет полноценной веб-версии.
|
||||
Используйте <a href="https://www.wechat.com/en/" target="_blank">официальное приложение</a>.
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body messenger-container">
|
||||
<i class="{{ messenger_icon }} messenger-icon"></i>
|
||||
|
||||
<h2 class="messenger-title">{{ messenger_name }} интеграция</h2>
|
||||
|
||||
<p class="messenger-description">
|
||||
{% if integration_status == 'active' %}
|
||||
Интеграция активна. Вы можете отправлять и получать сообщения через WeChat.
|
||||
{% elif integration_status == 'inactive' %}
|
||||
Интеграция не настроена. Обратитесь к администратору для настройки.
|
||||
{% else %}
|
||||
Здесь будет отображаться интеграция с {{ messenger_name }}.
|
||||
Функционал находится в разработке.
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="messenger-actions">
|
||||
<a href="{% url 'communications:chat_list' %}" class="btn btn-outline-secondary messenger-btn">
|
||||
<i class="bi-arrow-left"></i> Вернуться к чатам
|
||||
</a>
|
||||
{% if is_admin %}
|
||||
<a href="/admin/communications/messengerintegration/" class="btn btn-primary messenger-btn" style="background-color: {{ messenger_color }}; border-color: {{ messenger_color }};">
|
||||
<i class="bi-gear"></i> Настроить интеграцию
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-primary messenger-btn" style="background-color: {{ messenger_color }}; border-color: {{ messenger_color }};" disabled>
|
||||
<i class="bi-link-45deg"></i> Подключить {{ messenger_name }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
{% if is_admin %}
|
||||
<div class="alert alert-success d-inline-block">
|
||||
<i class="bi-shield-check"></i> У вас есть права администратора
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<h5>Инструкции для настройки:</h5>
|
||||
<ol class="text-start" style="max-width: 600px; margin: 0 auto;">
|
||||
<li>Зарегистрируйте WeChat Official Account</li>
|
||||
<li>Получите AppID и AppSecret</li>
|
||||
<li>Откройте <a href="/admin/communications/messengerintegration/">админ-панель интеграций</a></li>
|
||||
<li>Создайте новую интеграцию для WeChat</li>
|
||||
<li>Укажите AppID и AppSecret</li>
|
||||
<li>Настройте webhook</li>
|
||||
<li>Активируйте интеграцию</li>
|
||||
</ol>
|
||||
<div class="mt-3">
|
||||
<a href="/static/communications/MESSENGER_INTEGRATION_GUIDE.md" target="_blank" class="btn btn-sm btn-outline-info">
|
||||
<i class="bi-book"></i> Полная документация
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info d-inline-block">
|
||||
<i class="bi-info-circle"></i> Для настройки интеграции обратитесь к администратору
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body p-0">
|
||||
<div class="messenger-iframe-container">
|
||||
<div class="messenger-loading">
|
||||
<i class="bi-arrow-repeat"></i>
|
||||
<p class="mt-2 text-muted">Загрузка {{ messenger_name }}...</p>
|
||||
</div>
|
||||
<iframe
|
||||
class="messenger-iframe"
|
||||
src="https://www.wechat.com/"
|
||||
allow="microphone; camera"
|
||||
onload="document.querySelector('.messenger-loading').style.display='none'">
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{% url 'communications:chat_list' %}" class="btn btn-outline-secondary">
|
||||
<i class="bi-arrow-left"></i> Вернуться к чатам
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -7,128 +7,73 @@
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
|
||||
<style>
|
||||
.messenger-container {
|
||||
min-height: 70vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.messenger-icon {
|
||||
font-size: 6rem;
|
||||
color: {{ messenger_color }};
|
||||
margin-bottom: 2rem;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
}
|
||||
|
||||
.messenger-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 600;
|
||||
color: {{ messenger_color }};
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.messenger-description {
|
||||
font-size: 1.2rem;
|
||||
color: var(--bs-secondary);
|
||||
max-width: 600px;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
.messenger-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.messenger-btn {
|
||||
padding: 0.75rem 2rem;
|
||||
font-size: 1.1rem;
|
||||
.messenger-iframe-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100vh - 180px);
|
||||
min-height: 600px;
|
||||
border: 1px solid var(--bs-border-color);
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.3s ease;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.messenger-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
.messenger-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.messenger-loading {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.messenger-loading i {
|
||||
font-size: 3rem;
|
||||
color: {{ messenger_color }};
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="container-fluid px-3">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{% include "includes/components/page_header.html" with icon=messenger_icon title=messenger_name %}
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body messenger-container">
|
||||
<i class="{{ messenger_icon }} messenger-icon"></i>
|
||||
|
||||
<h2 class="messenger-title">{{ messenger_name }} интеграция</h2>
|
||||
|
||||
<p class="messenger-description">
|
||||
{% if integration_status == 'active' %}
|
||||
Интеграция активна. Вы можете отправлять и получать сообщения через WhatsApp.
|
||||
{% elif integration_status == 'inactive' %}
|
||||
Интеграция не настроена. Обратитесь к администратору для настройки.
|
||||
{% else %}
|
||||
Здесь будет отображаться интеграция с {{ messenger_name }}.
|
||||
Функционал находится в разработке.
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="messenger-actions">
|
||||
<a href="{% url 'communications:chat_list' %}" class="btn btn-outline-secondary messenger-btn">
|
||||
<i class="bi-arrow-left"></i> Вернуться к чатам
|
||||
</a>
|
||||
{% if is_admin %}
|
||||
<a href="/admin/communications/messengerintegration/" class="btn btn-primary messenger-btn" style="background-color: {{ messenger_color }}; border-color: {{ messenger_color }};">
|
||||
<i class="bi-gear"></i> Настроить интеграцию
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-primary messenger-btn" style="background-color: {{ messenger_color }}; border-color: {{ messenger_color }};" disabled>
|
||||
<i class="bi-link-45deg"></i> Подключить {{ messenger_name }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
{% if is_admin %}
|
||||
<div class="alert alert-success d-inline-block">
|
||||
<i class="bi-shield-check"></i> У вас есть права администратора
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<h5>Инструкции для настройки:</h5>
|
||||
<ol class="text-start" style="max-width: 600px; margin: 0 auto;">
|
||||
<li>Получите API ключи от WhatsApp Business API</li>
|
||||
<li>Откройте <a href="/admin/communications/messengerintegration/">админ-панель интеграций</a></li>
|
||||
<li>Создайте новую интеграцию для WhatsApp</li>
|
||||
<li>Укажите API ключ и webhook URL</li>
|
||||
<li>Активируйте интеграцию</li>
|
||||
</ol>
|
||||
<div class="mt-3">
|
||||
<a href="/static/communications/MESSENGER_INTEGRATION_GUIDE.md" target="_blank" class="btn btn-sm btn-outline-info">
|
||||
<i class="bi-book"></i> Полная документация
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info d-inline-block">
|
||||
<i class="bi-info-circle"></i> Для настройки интеграции обратитесь к администратору
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body p-0">
|
||||
<div class="messenger-iframe-container">
|
||||
<div class="messenger-loading">
|
||||
<i class="bi-arrow-repeat"></i>
|
||||
<p class="mt-2 text-muted">Загрузка {{ messenger_name }}...</p>
|
||||
</div>
|
||||
<iframe
|
||||
class="messenger-iframe"
|
||||
src="https://web.whatsapp.com/"
|
||||
allow="microphone; camera"
|
||||
onload="document.querySelector('.messenger-loading').style.display='none'">
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{% url 'communications:chat_list' %}" class="btn btn-outline-secondary">
|
||||
<i class="bi-arrow-left"></i> Вернуться к чатам
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user