Add "Plan"
101
Plan.md
Normal file
101
Plan.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# План рассылок
|
||||
|
||||
## Yonote интеграция
|
||||
|
||||
План рассылок загружается из базы данных Yonote (аналог Notion, российский).
|
||||
|
||||
### Настройка
|
||||
|
||||
В settings.json → `yonoteConfig`:
|
||||
|
||||
```json
|
||||
{
|
||||
"databaseId": "abc123", // ID базы в Yonote
|
||||
"statusProperty": "Статус", // название колонки статуса
|
||||
"dateProperty": "Дата", // дата отправки
|
||||
"subjectProperty": "Тема", // тема письма
|
||||
"preheaderProperty": "Прехедер",
|
||||
"idProperty": "ID товаров", // IDs для блоков товаров
|
||||
"extraProperties": ["Проект", "Теги", "Тип"] // доп. колонки
|
||||
}
|
||||
```
|
||||
|
||||
Токен Yonote — в `config.json` → `yonote_token`.
|
||||
|
||||
### Загрузка данных
|
||||
|
||||
`fetchPlanRows()`:
|
||||
1. GET `/api/yonote/database/:id/rows` — пагинация по 100, макс 500 строк
|
||||
2. Сортировка по `updatedAt` DESC
|
||||
3. Фильтр по дате: -7 дней ... +60 дней
|
||||
4. Извлечение полей из Yonote properties → плоская структура
|
||||
|
||||
### Polling
|
||||
|
||||
`startPlanPolling()` — каждые 3 минуты загружает обновления:
|
||||
- Сравнивает fingerprints (JSON hash каждой строки)
|
||||
- При изменениях → toast уведомление + browser Notification
|
||||
- Кэширует в localStorage (`va-plan-cache`)
|
||||
|
||||
## Календарь
|
||||
|
||||
Мини-календарь в сайдбаре и на странице плана:
|
||||
|
||||
- Точки под датами обозначают запланированные рассылки
|
||||
- Клик на дату → показывает письма этого дня
|
||||
- Навигация по месяцам (← →)
|
||||
- Текущий день подсвечен
|
||||
|
||||
## Группировка на странице плана
|
||||
|
||||
Письма группируются по периодам:
|
||||
- Просрочено (красный)
|
||||
- Сегодня
|
||||
- Завтра
|
||||
- На этой неделе
|
||||
- На следующей неделе
|
||||
- Позже
|
||||
|
||||
## Карточка сборки (Assembly Card)
|
||||
|
||||
Когда письмо привязано к строке из Yonote, в сайдбаре показывается карточка:
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ ПЕРЕДАНО В СБОРКУ │ ← статус (цветной бейдж)
|
||||
│ 📮 Тема письма 🧥 │ ← тема из Yonote
|
||||
│ Подзаголовок │ ← preheader
|
||||
│ [Тег1] [Тег2] │ ← теги/тип
|
||||
│ ⎕ Figma │ ← ссылки из extra
|
||||
│ │
|
||||
│ [Mindbox] [Отправлено]│ ← кнопки действий
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
### Auto-matching
|
||||
|
||||
При открытии письма `assemblyInfo` автоматически матчится со строкой в плане:
|
||||
- По `rowId` (если сохранён в письме)
|
||||
- Или по совпадению title + date
|
||||
|
||||
### Статусы
|
||||
|
||||
`setPlanRowStatus(row, newStatus)` — обновляет статус в Yonote.
|
||||
|
||||
Кнопка "Отправлено" → статус "Отправлено" + останавливает трекинг времени.
|
||||
|
||||
## Начало сборки
|
||||
|
||||
`startAssemble(row)`:
|
||||
1. Создаёт новое письмо с заполненным title, date, preheader из Yonote
|
||||
2. Или открывает существующее (если уже привязано к rowId)
|
||||
3. Автозаполняет ID pool из свойства "ID товаров"
|
||||
4. Устанавливает assemblyInfo
|
||||
|
||||
## Трекинг времени
|
||||
|
||||
- `statsStart(letterId, ...)` — запускает 1-секундный интервал
|
||||
- Считает активные секунды (паузится когда вкладка скрыта — `document.hidden`)
|
||||
- `statsMarkHtmlCopied()` — отмечает что HTML скопирован
|
||||
- `statsStop(finalStatus)` — сохраняет если >= 1 минуты
|
||||
- Данные: `{letterId, letterName, userId, userName, project, tag, startedAt, finishedAt, activeSeconds, htmlCopied}`
|
||||
Reference in New Issue
Block a user