ci / build-test (push) Canceled after 0s
SaaS-мониторинг Telegram: ядро (модули Cards/Kanban/Pipeline/Tenants/Settings/ Discovery, Api, Infrastructure), сервисы telegram/ai/ml/storage, фронт Vue, контракты и grpc-hosting, деплой-конфиги (dev/prod/observability/CI-раннер), Gitea Actions CI, документация (ТЗ, техдок, api-map, код-стайл, планы, бэклог). Текущее состояние: все этапы роадмапа 0–12 закрыты, сборка 5 sln 0/0, тесты 1340/130/52/38/9 зелёные.
8.6 KiB
8.6 KiB
Task 8 — Отчёт: Фронтенд — store + каркас подвкладки «Поиск»
Статус
Выполнено. npm run build проходит без ошибок.
Файлы
- Изменён:
frontend/src/store.js— состояние Discovery, сброс при разлогине, 13 функций. - Изменён:
frontend/src/views/ChannelsView.vue— сегмент «Каналы | Поиск каналов» и рендер по табу. - Создан:
frontend/src/views/DiscoveryView.vue— список задач + панель активной задачи/мастер.
Что сделано
store.js
- Состояние (по интерфейсу брифа):
channelsTab: 'list' | 'search'(init'list'),discTasks,discCandidates,discBlacklist,discLog,discActiveTaskId: null,discCandidateStatus: 'review',discBusy: false. Добавлено вstate(блок «Каналы») и вresetLocal()(разлогин → чистый Discovery,channelsTabвозвращается в'list'). - Функции названы точно по брифу:
gotoChannelsTab(tab),loadDiscTasks(),saveDiscTask(form, id=null),deleteDiscTask(id),startDiscTask(id),pauseDiscTask(id),generateDiscKeywords(taskId),loadDiscCandidates(taskId, status),joinDiscCandidate(c),rejectDiscCandidate(c),loadDiscBlacklist(),removeDiscBlacklist(id),loadDiscLog(taskId). - Контракт в camelCase как в API:
minSubscribers,sampleSize,planJoins,autoJoin,dialogIdи т.д. Тела задач собираются в camelCase (POST/PATCH /api/discovery/tasks), списки читаются из{"items": [...]}. - Паттерны проекта:
api.get/post/patch/delete,toast/errMsgна действиях; тихиеcatch → falseна фоновых чтениях списков (какloadPipelineQueue/loadRejected). saveDiscTask— создаёт/патчит, кладёт задачу вdiscTasks, ставитdiscActiveTaskId, возвращает задачу илиnull.generateDiscKeywords— error-ветка API ({"keywords": [], "error": "..."}) →toast(error), возвращаетnull; успех → массивkeywords(может быть пустым).deleteDiscTask— после удаления активной задачи выбирает первую оставшуюся.loadDiscTasks— сохраняет активную задачу, если она ещё существует, иначе выбирает первую (правая панель не пустует).join/rejectDiscCandidate— на успехе убирают кандидата из текущего спискаdiscCandidates+ toast;removeDiscBlacklistфильтрует поdialogId. Поля кандидата/блэклиста не используются в UI до Task 9.
ChannelsView.vue
- В шапке — сегмент «Каналы | Поиск каналов» (мелкие кнопки в контейнере
bg-ink/60 border border-white/5, активный —bg-white/8 text-hi), переключение черезgotoChannelsTab. Подзаголовок шапки и правые действия («Перечитать», «Включить все», поиск по имени) показываются только на табе'list'. - Синхронизация списка каналов (watch по
state.view+onMounted) ограничена условиемchannelsTab === 'list'; добавлен отдельный watch поchannelsTab— возврат на таб «Каналы» освежает список. - При
channelsTab === 'search'вместо списка каналов рендерится<DiscoveryView/>(импорт из./DiscoveryView.vue).
DiscoveryView.vue (каркас: задачи + мастер)
- Слева: колонка
w-[300px]со списком задач (state.discTasks; имя + чип статуса + ключи/найдено/вступили), кнопка «Новая задача», refresh. Пустое состояние — с подсказкой. - Справа: панель активной задачи (
state.discActiveTaskId). Нет выбора — приветственный экран с кнопкой «Новая задача». - Мастер:
name,description, кнопка «Сгенерировать ключи ИИ» (иконка sparkles), редактируемые чипы ключей (ввод + Enter/плюс, удаление крестиком), числовые поляminSubscribers/threshold/sampleSize/planJoins(дефолты 0/40/10/1),langselect ru/any, toggleautoJoin. Стили в духе SettingsView:rounded-xl border border-white/8 bg-raise/40 p-4, инпутыh-9 bg-ink/70 border-white/10 focus:border-brand/50, чипы как у стоп-фраз/сферы. - Кнопки: «Запустить» (градиент; disabled пока
keywordsпустые; подпись «Продолжить» для paused, «Запустить заново» для done/failed), «Сохранить», «Удалить» (сaskConfirm, скрыта для черновика и на паузе выполнения), «Поставить на паузу» (только running). - Статус задачи: чип статуса (draft/running/paused/done/failed с цветами online/warn/brand/danger), при прогрессе — счётчики found/evaluated/joined/rejected, дата создания. Пока задача running — поля задизейблены (overlay) и список тихо опрашивается раз в 4.5 c (статус/счётчики живут на бэке у воркера).
- Без заглушек-обещаний: панель кандидатов/лога не рисовалась (ожидаемо — Task 9).
- UX-детали: «Запустить» и «Сгенерировать ключи ИИ» при необходимости сначала сохраняют форму (
saveDiscTask), т.к. старт и генерация идут по id задачи на сервере; черновик «Новой задачи» не затирается ручным refresh списка.
Вывод проверок
cd /c/telbase/frontend && npm run build→✓ built in 1.32s,42 modules transformed, ошибок нет.diagnosticsпоstore.js,ChannelsView.vue,DiscoveryView.vue— ошибок/предупреждений нет.
Concerns
- Живой API/UI не гонялся (нет запущенного бэкенда/дев-сервера в этой сессии); поведение функций опирается на контракт Task 7 (
{"items": [...]}, camelCase, 200/400/404). Ручная проверка сценариев — за Task 10. - Генерация ключей ИИ по API идёт от id задачи (
POST /tasks/{id}/generate-keywords), поэтому при генерации из нового черновика кнопка сначала создаёт задачу (нужно название — при пустом показывается toast «Укажите название задачи»). После генерации ключи кладутся в форму, в БД фиксируются кнопкой «Сохранить» (или автоматически при «Запустить»). - Дефолты формы (threshold 40 / sampleSize 10) повторяют дефолты сервиса; при создании бэкенд может подставить значения настроек
discEvalThreshold/discEvalSample— после «Сохранить» форма перечитывается из ответа сервера (pickFromTask), так что расхождение схлопывается. channelsTabглобальный и переживает уход/возврат на экран «Каналы» (какsettingsTab); активная задача Discovery тоже сохраняется между визитами, при её удалении/исчезновении выбирается первая.- Опрос статуса running-задачи — простой
setInterval4.5 c на время нахождения на вкладке; при большом числе задач можно позже перевести на точечныйGET /tasks/{id}или SSE.