# Промпт для ИИ: Перенос паттерна Прайслист Используй этот документ как промпт для ИИ при переносе реализации прайслиста в другой проект. --- ## Задача Я имею рабочую реализацию окна "Прайслист" в проекте QuoteForge. Нужно перенести эту реализацию в проект [ДОП_ПРОЕКТ_НАЗВАНИЕ], сохраняя структуру, логику и UI/UX. ## Что перенести ### Frontend - Лист прайслистов (`/pricelists`) **Файл источник:** QuoteForge/web/templates/pricelists.html **Компоненты:** 1. **Таблица** - список прайслистов с колонками: - Версия (монофонт) - Тип (estimate/warehouse/competitor) - Дата создания - Автор (обычно "sync") - Позиций (количество товаров) - Исп. (использований) - Статус (зеленый "Активен" / серый "Неактивен") - Действия (Просмотр, Удалить если не используется) 2. **Пагинация** - навигация по страницам с активной страницей выделена 3. **Модальное окно** - "Создать прайслист" (если есть прав на запись) **Что копировать:** - HTML структуру таблицы из lines 10-30 - JavaScript функции: - `loadPricelists(page)` - загрузка списка - `renderPricelists(items)` - рендер таблицы - `renderPagination(total, page, perPage)` - пагинация - `checkPricelistWritePermission()` - проверка прав - Модальные функции: `openCreateModal()`, `closeCreateModal()`, `createPricelist()` - CSS классы Tailwind (скопируются как есть) **Где использовать в дочернем проекте:** - URL: `/pricelists` (или адаптировать под ваши маршруты) - API: `GET /api/pricelists?page=1&per_page=20` --- ### Frontend - Детали прайслиста (`/pricelists/:id`) **Файл источник:** QuoteForge/web/templates/pricelist_detail.html **Компоненты:** 1. **Хлебная крошка** - кнопка назад на список 2. **Инфо-панель** - сводка по прайслисту: - Версия (монофонт) - Дата создания - Автор - Позиций (количество) - Использований (в скольких конфигах) - Статус (зеленый/серый) - Истекает (дата или "-") 3. **Таблица товаров** - с поиском и пагинацией: - Артикул (монофонт, lot_name) - Категория (извлекается первая часть до "_") - Описание (обрезается до 60 символов с "...") - [УСЛОВНО] Доступно (qty) - только для warehouse источника - [УСЛОВНО] Partnumbers - только для warehouse источника - Цена, $ (с 2 знаками после запятой) - Настройки (аббревиатуры: РУЧН, Сред, Взвеш.мед, периоды (1н, 1м, 3м, 1г), коэффициент, МЕТА) 4. **Поиск** - дебаунс 300мс, поиск по lot_name 5. **Динамические колонки** - qty и partnumbers скрываются/показываются в зависимости от source (warehouse или нет) **Что копировать:** - HTML структуру из lines 4-78 - JavaScript функции: - `loadPricelistInfo()` - загрузка деталей прайслиста - `loadItems(page)` - загрузка товаров - `renderItems(items)` - рендер таблицы товаров - `renderItemsPagination(total, page, perPage)` - пагинация товаров - `isWarehouseSource()` - проверка источника - `toggleWarehouseColumns()` - показать/скрыть conditional колонки - `formatQty(qty)` - форматирование количества - `formatPriceSettings(item)` - форматирование строки настроек - `escapeHtml(text)` - экранирование HTML - Debounce для поиска (lines 300-306) - CSS классы Tailwind - Логику conditional колонок (lines 152-164) **Где использовать в дочернем проекте:** - URL: `/pricelists/:id` - API: - `GET /api/pricelists/:id` - `GET /api/pricelists/:id/items?page=1&per_page=50&search=...` --- ### Backend - Handler **Файл источник:** QuoteForge/internal/handlers/pricelist.go **Методы для реализации:** 1. **List** (lines 23-89) - Параметры: `page`, `per_page`, `source` (фильтр), `active_only` - Логика: - Получить все прайслисты - Отфильтровать по source (case-insensitive) - Отсортировать по CreatedAt DESC (свежее сверху) - Пагинировать - Для каждого: посчитать товары (CountLocalPricelistItems), использования (IsUsed) - Вернуть JSON с полями: id, source, version, created_by, item_count, usage_count, is_active, created_at, synced_from 2. **Get** (lines 92-116) - Параметр: `id` (uint из URL) - Логика: - Получить прайслист по ID - Вернуть его детали (id, source, version, item_count, is_active, created_at) - 404 если не найден 3. **GetItems** (lines 119-181) - Параметры: `id` (URL), `page`, `per_page`, `search` (query) - Логика: - Получить прайслист по ID - Получить товары этого прайслиста - Фильтровать по lot_name LIKE search (если передан) - Посчитать total - Пагинировать - Для каждого товара: извлечь категорию из lot_name (первая часть до "_") - Вернуть JSON: source, items (id, lot_name, price, category, available_qty, partnumbers), total, page, per_page 4. **GetLotNames** (lines 183-211) - Параметр: `id` (URL) - Логика: - Получить все lot_names из этого прайслиста - Отсортировать alphabetically - Вернуть JSON: lot_names (array of strings), total 5. **GetLatest** (lines 214-233) - Параметр: `source` (query, default "estimate") - Логика: - Нормализовать source (case-insensitive) - Получить самый свежий прайслист по этому source - Вернуть его детали - 404 если не найден **Регистрация маршрутов:** ```go pricelists := api.Group("/pricelists") { pricelists.GET("", handler.List) pricelists.GET("/latest", handler.GetLatest) pricelists.GET("/:id", handler.Get) pricelists.GET("/:id/items", handler.GetItems) pricelists.GET("/:id/lots", handler.GetLotNames) } ``` --- ## Адаптация для другого проекта ### Что нужно изменить 1. **Источник данных** - QuoteForge использует local DB (LocalPricelist, LocalPricelistItem) - В вашем проекте: замените на ваши структуры/таблицы - Сущность "прайслист" может называться по-другому 2. **API маршруты** - `/api/pricelists` → ваш путь - `:id` - может быть UUID вместо int, адаптировать parsing 3. **Имена полей** - Если у вас нет поля `version` - используйте ID или дату - Если нет `source` - опустить фильтр - Если нет `IsUsed` - считать как всегда 0 4. **Структуры данных** - Pricelist должна иметь: id, name/version, created_at, source, item_count - PricelistItem должна иметь: id, lot_name, price, available_qty, partnumbers 5. **Условные колонки** - Логика: если source == "warehouse", показать qty и partnumbers - Адаптировать под ваши источники/типы ### Что копировать как есть - **HTML структура** - таблицы, модали, классы Tailwind - **JavaScript логика** - все функции загрузки, рендера, пагинации - **CSS классы** - Tailwind работает везде одинаково - **Форматирование функций** - formatPrice, formatQty, formatDate --- ## Пошаговая инструкция для ИИ 1. **Прочитай оба файла:** - QuoteForge/web/templates/pricelists.html (список) - QuoteForge/web/templates/pricelist_detail.html (детали) - QuoteForge/internal/handlers/pricelist.go (backend) 2. **Определи структуры данных в дочернем проекте:** - Какая таблица хранит "прайслисты"? - Какие у неё поля? - Как связаны товары? 3. **Адаптируй Backend:** - Скопируй методы Handler - Замени DB вызовы на вызовы вашего хранилища - Замени имена полей в JSON ответах если нужно - Убедись, что API возвращает нужный формат 4. **Адаптируй Frontend - Список:** - Скопируй HTML таблицу - Скопируй функции load/render/pagination - Замени маршруты `/pricelists` → ваши - Замени API endpoint → ваш - Протестируй список загружается 5. **Адаптируй Frontend - Детали:** - Скопируй HTML для деталей - Скопируй функции loadInfo/loadItems/render - Замени маршруты и endpoints - Особое внимание на conditional колонки (toggleWarehouseColumns) - Протестируй поиск работает 6. **Протестируй:** - Список загружается - Пагинация работает - Детали открываются - Поиск работает - Conditional колонки показываются/скрываются правильно - Форматирование цен и дат работает --- ## Пример адаптации ### Backend (было): ```go func (h *PricelistHandler) List(c *gin.Context) { localPLs, err := h.localDB.GetLocalPricelists() // ... } ``` ### Backend (стало): ```go func (h *CatalogHandler) List(c *gin.Context) { catalogs, err := h.service.GetAllCatalogs(page, perPage) // ... } ``` ### Frontend (было): ```javascript const resp = await fetch(`/api/pricelists?page=${page}&per_page=20`); ``` ### Frontend (стало): ```javascript const resp = await fetch(`/api/catalogs?page=${page}&per_page=20`); ``` --- ## Качество результата Когда закончишь: - ✅ Список и детали выглядят идентично QuoteForge - ✅ Все функции работают (load, render, pagination, search, conditional columns) - ✅ Обработка ошибок (404, empty list, network errors) - ✅ Таблицы с Tailwind классами оформлены одинаково - ✅ Форматирование чисел/дат совпадает --- ## Вопросы для ИИ Перед тем как давать этот промпт, ответь на эти вопросы: 1. **Какие у тебя структуры данных для "прайслиста"?** - Пример: какие поля, как называется таблица 2. **Какие API endpoints уже есть?** - Или нужно создать с нуля? 3. **Есть ли уже разница в источниках (estimate/warehouse)?** - Или все одного типа? 4. **Нужна ли возможность создавать прайслисты?** - Или только просмотр? --- ## Чеклист для проверки После переноса проверь: - [ ] Backend: List возвращает правильный JSON - [ ] Backend: Get возвращает детали - [ ] Backend: GetItems возвращает товары с поиском - [ ] Frontend: Список загружается на `/pricelists` - [ ] Frontend: Клик на прайслист открывает `/pricelists/:id` - [ ] Frontend: Таблица на детальной странице рендеритсяся - [ ] Frontend: Поиск работает с дебаунсом - [ ] Frontend: Пагинация работает - [ ] Frontend: Conditional колонки показываются/скрываются - [ ] Frontend: Форматирование цен работает (2 знака) - [ ] Frontend: Форматирование дат работает (ru-RU) - [ ] UI: Выглядит идентично QuoteForge