327 lines
9.9 KiB
Markdown
327 lines
9.9 KiB
Markdown
# Система управления реакциями из БД
|
||
|
||
## Обзор
|
||
|
||
Система доступных реакций теперь полностью управляется через базу данных вместо жёсткого кодирования в JavaScript.
|
||
|
||
## Архитектура
|
||
|
||
### Backend
|
||
|
||
#### Модель `AvailableReaction`
|
||
```python
|
||
# communications/models.py
|
||
class AvailableReaction(models.Model):
|
||
emoji = models.CharField(max_length=10, unique=True)
|
||
name = models.CharField(max_length=50)
|
||
order = models.IntegerField(default=0)
|
||
is_active = models.BooleanField(default=True)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
```
|
||
|
||
**Поля:**
|
||
- `emoji` - Unicode эмодзи (👍, ❤️, и т.д.)
|
||
- `name` - Человекочитаемое название ("Лайк", "Сердце")
|
||
- `order` - Порядок отображения (меньше = выше)
|
||
- `is_active` - Вкл/выкл реакцию без удаления
|
||
- `created_at` - Дата добавления
|
||
|
||
#### API Endpoint
|
||
|
||
**GET** `/api/v1/communications/reactions/available/`
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"reactions": [
|
||
{
|
||
"emoji": "👍",
|
||
"name": "Лайк",
|
||
"order": 1
|
||
},
|
||
{
|
||
"emoji": "❤️",
|
||
"name": "Сердце",
|
||
"order": 2
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Требования:**
|
||
- Требуется авторизация (`@login_required`)
|
||
- Возвращает только активные реакции (`is_active=True`)
|
||
- Отсортировано по полю `order`
|
||
|
||
#### Admin-панель
|
||
|
||
```python
|
||
# communications/admin.py
|
||
@admin.register(AvailableReaction)
|
||
class AvailableReactionAdmin(admin.ModelAdmin):
|
||
list_display = ('emoji', 'name', 'order', 'is_active', 'created_at')
|
||
list_editable = ('order', 'is_active')
|
||
ordering = ('order', 'created_at')
|
||
```
|
||
|
||
**Возможности:**
|
||
- Добавление/удаление реакций через admin
|
||
- Редактирование порядка прямо в списке
|
||
- Быстрое включение/выключение реакций
|
||
- Поиск по эмодзи и названию
|
||
|
||
### Frontend
|
||
|
||
#### ReactionsConfig (Синглтон)
|
||
```javascript
|
||
// static/js/config/reactionsConfig.js
|
||
import reactionsConfig from './config/reactionsConfig.js';
|
||
|
||
// Загрузка из API
|
||
await reactionsConfig.load();
|
||
|
||
// Получить массив эмодзи
|
||
const emojis = reactionsConfig.getEmojis(); // ['👍', '❤️', ...]
|
||
|
||
// Проверить доступность
|
||
if (reactionsConfig.isAvailable('👍')) { ... }
|
||
|
||
// Получить название
|
||
const name = reactionsConfig.getName('👍'); // "Лайк"
|
||
```
|
||
|
||
**Особенности:**
|
||
- Загружается один раз при инициализации чата
|
||
- Кэширует результат (повторные вызовы `.load()` возвращают кэш)
|
||
- Fallback на дефолтные реакции при ошибке API
|
||
- Promise-based (поддержка async/await)
|
||
|
||
#### Использование в chat-detail-enhanced.js
|
||
|
||
```javascript
|
||
// До инициализации компонентов загружаем реакции
|
||
await reactionsConfig.load();
|
||
const availableEmojis = reactionsConfig.getEmojis();
|
||
|
||
// Передаём в MessageContextMenu
|
||
const contextMenu = new MessageContextMenu({
|
||
currentUserId: meId,
|
||
emojis: availableEmojis, // ← Из БД!
|
||
onReactionSelect: async (messageId, emoji) => {
|
||
await reactions.addReaction(messageId, emoji);
|
||
}
|
||
});
|
||
```
|
||
|
||
## Инициализация
|
||
|
||
### 1. Создание миграции
|
||
```bash
|
||
cd backend
|
||
python manage.py makemigrations communications
|
||
python manage.py migrate communications
|
||
```
|
||
|
||
### 2. Добавление дефолтных реакций
|
||
```bash
|
||
python manage.py init_reactions
|
||
```
|
||
|
||
Эта команда создаст 8 стандартных реакций:
|
||
- 👍 Лайк
|
||
- ❤️ Сердце
|
||
- 😂 Смех
|
||
- 😮 Удивление
|
||
- 😢 Грусть
|
||
- 🙏 Спасибо
|
||
- 👏 Аплодисменты
|
||
- 🔥 Огонь
|
||
|
||
### 3. Проверка
|
||
```bash
|
||
python check_reactions.py
|
||
```
|
||
|
||
## Управление реакциями
|
||
|
||
### Через Admin-панель
|
||
|
||
1. Перейти в `/admin/communications/availablereaction/`
|
||
2. Добавить новую реакцию:
|
||
- Emoji: вставить эмодзи (Ctrl+V)
|
||
- Name: название на русском
|
||
- Order: порядковый номер
|
||
- Is active: ✓
|
||
3. Сохранить
|
||
|
||
**Изменение порядка:**
|
||
- В списке реакций отредактировать поле "Order"
|
||
- Нажать "Сохранить" внизу страницы
|
||
|
||
**Отключение реакции:**
|
||
- Снять галочку "Is active"
|
||
- Нажать "Сохранить"
|
||
|
||
### Программно
|
||
|
||
```python
|
||
from communications.models import AvailableReaction
|
||
|
||
# Добавить новую реакцию
|
||
AvailableReaction.objects.create(
|
||
emoji='🎉',
|
||
name='Праздник',
|
||
order=9,
|
||
is_active=True
|
||
)
|
||
|
||
# Изменить порядок
|
||
reaction = AvailableReaction.objects.get(emoji='👍')
|
||
reaction.order = 1
|
||
reaction.save()
|
||
|
||
# Отключить реакцию
|
||
reaction.is_active = False
|
||
reaction.save()
|
||
|
||
# Удалить реакцию (не рекомендуется, лучше is_active=False)
|
||
reaction.delete()
|
||
```
|
||
|
||
## Data Flow
|
||
|
||
```
|
||
[БД] AvailableReaction
|
||
↓
|
||
[Backend API] /api/v1/communications/reactions/available/
|
||
↓
|
||
[Frontend] reactionsConfig.load()
|
||
↓
|
||
[Cache] reactionsConfig.reactions
|
||
↓
|
||
[Component] MessageContextMenu({ emojis: [...] })
|
||
↓
|
||
[UI] Контекстное меню с реакциями
|
||
```
|
||
|
||
## Преимущества
|
||
|
||
1. **Централизованное управление** - одно место для изменений
|
||
2. **Без deploy** - изменения через admin без перезапуска
|
||
3. **Гибкость** - разные реакции для разных чатов (будущее)
|
||
4. **Локализация** - названия реакций на нужном языке
|
||
5. **Аналитика** - можно отслеживать популярность реакций
|
||
6. **Валидация** - можно проверять доступность эмодзи перед использованием
|
||
|
||
## Миграция со старого подхода
|
||
|
||
### Было (hardcoded):
|
||
```javascript
|
||
const contextMenu = new MessageContextMenu({
|
||
emojis: ['👍', '❤️', '😂', '😮', '😢', '🙏', '👏', '🔥']
|
||
});
|
||
```
|
||
|
||
### Стало (из БД):
|
||
```javascript
|
||
await reactionsConfig.load();
|
||
const contextMenu = new MessageContextMenu({
|
||
emojis: reactionsConfig.getEmojis()
|
||
});
|
||
```
|
||
|
||
## Совместимость
|
||
|
||
- **Fallback** - если API недоступен, используются дефолтные реакции
|
||
- **Кэширование** - одна загрузка на сессию чата
|
||
- **Promise-safe** - множественные вызовы `.load()` возвращают один промис
|
||
|
||
## Расширения
|
||
|
||
### Реакции по категориям чата
|
||
```python
|
||
class AvailableReaction(models.Model):
|
||
...
|
||
chat_types = models.JSONField(
|
||
default=list,
|
||
help_text="['personal', 'group', 'department']"
|
||
)
|
||
```
|
||
|
||
### Кастомные реакции
|
||
```python
|
||
class AvailableReaction(models.Model):
|
||
...
|
||
is_custom = models.BooleanField(default=False)
|
||
uploaded_by = models.ForeignKey('employees.Employee', ...)
|
||
image = models.ImageField(...) # Для не-эмодзи реакций
|
||
```
|
||
|
||
### Статистика
|
||
```python
|
||
class ReactionStats(models.Model):
|
||
reaction = models.ForeignKey(AvailableReaction, ...)
|
||
usage_count = models.IntegerField(default=0)
|
||
last_used = models.DateTimeField(...)
|
||
```
|
||
|
||
## Troubleshooting
|
||
|
||
### Реакции не загружаются
|
||
1. Проверить консоль браузера: `[ReactionsConfig] Loading...`
|
||
2. Проверить Network tab: `/api/v1/communications/reactions/available/`
|
||
3. Проверить авторизацию (требуется `@login_required`)
|
||
4. Проверить наличие реакций в БД: `python check_reactions.py`
|
||
|
||
### Старые реакции всё ещё показываются
|
||
1. Очистить кэш браузера (Ctrl+Shift+Delete)
|
||
2. Hard reload (Ctrl+Shift+R)
|
||
3. Проверить что используется новый `chat-detail-enhanced.js`
|
||
|
||
### Ошибка "reactionsConfig is not defined"
|
||
1. Проверить импорт в `chat-detail-enhanced.js`:
|
||
```javascript
|
||
import reactionsConfig from './config/reactionsConfig.js';
|
||
```
|
||
2. Проверить что файл существует: `static/js/config/reactionsConfig.js`
|
||
|
||
## Производительность
|
||
|
||
- **Запросов к БД:** 1 на загрузку страницы чата
|
||
- **Кэш frontend:** Да (весь сеанс)
|
||
- **Кэш backend:** Можно добавить Redis (будущее)
|
||
- **Размер ответа:** ~200-500 байт (8 реакций)
|
||
- **Время загрузки:** <50ms
|
||
|
||
## Тестирование
|
||
|
||
```bash
|
||
# Проверка БД
|
||
python check_reactions.py
|
||
|
||
# Проверка API (через curl, нужна авторизация)
|
||
curl -X GET http://localhost:9000/api/v1/communications/reactions/available/ \
|
||
-H "Cookie: sessionid=YOUR_SESSION"
|
||
|
||
# Проверка frontend (открыть консоль браузера)
|
||
# Должны увидеть:
|
||
# [ReactionsConfig] ✓ Loaded reactions from API: [...]
|
||
```
|
||
|
||
## Команды управления
|
||
|
||
```bash
|
||
# Инициализация дефолтных реакций
|
||
python manage.py init_reactions
|
||
|
||
# Проверка состояния
|
||
python check_reactions.py
|
||
|
||
# Сброс порядка (будущее)
|
||
python manage.py reset_reaction_order
|
||
|
||
# Импорт из JSON (будущее)
|
||
python manage.py import_reactions reactions.json
|
||
```
|