d606f8371c
Ports the weather check added to stroy-bot-main on 2026-10-16: daily station weather, report positions with weather per shift and the AI assessment of working conditions. Opens as ?page=weather&start=&end= instead of the #weathercheck hash, and hub dates survive the way back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
307 lines
38 KiB
Markdown
307 lines
38 KiB
Markdown
# Чек-лист миграции StroyBot → монорепо
|
||
|
||
Каждый раздел считается перенесённым только когда все пункты проверены в workbench.
|
||
Пишущие операции (создание / правка / удаление / импорт) проверяем **только на тестовом проекте «ТЕСТ StroyBot»**.
|
||
|
||
Правила переноса:
|
||
- Запросы, поля, фильтры, права и тексты переносятся **1:1** из исходного репозитория.
|
||
- Известные баги переносятся как есть (помечены 🐞) — исправляем позже отдельными коммитами.
|
||
- Старые страницы и web parts не трогаем, поддержка старых URL не нужна.
|
||
|
||
Легенда: `[ ]` — не проверено, `[x]` — проверено в workbench.
|
||
|
||
---
|
||
|
||
## 0. Общее (оболочка)
|
||
|
||
> 🔧 **Исправлено при проверке T-RPL (2026-10-19):** «Отчёты по проекту» и форма отчёта брали id пользователя из контекста страницы (`legacyPageContext.userId`) и путь к DocLib — от сайта страницы. У каждого сайта свой id пользователя, поэтому в workbench корневого сайта «Отчёты» показывали «Нет доступа». Теперь всё — от сайта со списками (`settings.siteUrl`): id через `_api/web/currentuser`, путь папки фото — от `siteUrl`. Workbench по умолчанию открывается на `/sites/stroy`.
|
||
|
||
- [ ] Одна web part, разделы переключаются через `?page=…`, проект — через `?projectId=…`
|
||
- [ ] Кнопки «назад/вперёд» браузера переключают разделы
|
||
- [ ] Ссылку на любой раздел можно скопировать и открыть в новой вкладке
|
||
- [ ] Выбранный проект сохраняется между перезагрузками (`sessionStorage`, ключ `stroybot_selected_project`)
|
||
- [ ] Шрифты Inter и Lora подгружаются (раньше грузили report-list и assigner)
|
||
- [ ] `webApiPermissionRequests` в одном пакете: `api.tnsu.kz` (`9232d9e2-…`, `Reports.Read` и `user_impersonation`) + Dataverse `https://tansu.crm5.dynamics.com` (`user_impersonation`)
|
||
|
||
**Сознательные изменения (не функционал, а настройка):**
|
||
- Настройки property pane из 8 web parts сведены в одну группу «Подключение». Имена списков больше не настраиваются в property pane — они в константах.
|
||
- `worksPageUrl` (objects → works) больше не нужен: переход внутри приложения.
|
||
|
||
---
|
||
|
||
## 1. Главная (stroy-bot-main)
|
||
|
||
### Выбор проекта
|
||
- [ ] Поле «Проект:», плейсхолдер «Выберите проект», иконка поиска
|
||
- [ ] Список грузится при первом фокусе, «Загрузка проектов…»
|
||
- [ ] При фокусе текст выделяется
|
||
- [ ] Фильтр по Title (без учёта регистра, подстрока), максимум **7** результатов
|
||
- [ ] У каждого — бейдж статуса, «Без статуса» если пусто
|
||
- [ ] Сообщения: «Нет доступных проектов», «Проекты не найдены», «Ошибка загрузки. Попробуйте ещё раз.»
|
||
- [ ] Клик вне / Esc — закрыть и вернуть выбранное название (или очистить)
|
||
- [ ] Бейдж статуса рядом с полем: текущий — зелёный, завершен/завершён — серый, архивный — золотой, иначе — нейтральный
|
||
- [ ] Сортировка по алфавиту, затем до 7 недавно активных (из Dataverse `cree9_reports`) — наверх
|
||
- [ ] Права из «Доступы»: `read | edit0 | aproove`, `canEdit` = OR по `edit0`
|
||
- [ ] Подсказка «Выберите проект, чтобы активировать ссылки ниже»
|
||
|
||
### Разделы проекта
|
||
- [ ] Объекты / «Объекты по проекту»
|
||
- [ ] Отчёты по проекту / «Просмотр отчётности»
|
||
- [ ] Отправить отчёт / «Отправка отчёта по проекту»
|
||
- [ ] Загрузить работы из сметы / «Импорт работ в систему»
|
||
- [ ] Архив проекта / «Библиотека документов» → `{SITE}/Shared Documents/Архив/{Title}` (внешняя ссылка, новая вкладка)
|
||
- [ ] Ресурсы проекта / «Профессии и компании»
|
||
- [ ] Без выбранного проекта карточки неактивны
|
||
- [ ] Статус «архивный» — неактивно всё, кроме Архива; экспорт тоже неактивен
|
||
- [ ] Статус «завершен/завершён» — неактивно «Отправить отчёт»
|
||
- [ ] `canEdit = false` — неактивно «Отправить отчёт»
|
||
|
||
### Экспорт данных «Выгрузить за период»
|
||
- [ ] Кнопка «?» — поповер с 3 строками (день / Пн–Вс / произвольный), закрытие по клику мимо
|
||
- [ ] Поля «Начало» и «Конец» видны только при выбранном проекте
|
||
- [ ] «Укажите период для активации ссылки», пока даты не заданы
|
||
- [ ] Ошибка «Дата начала не может быть позже даты конца», кнопка неактивна
|
||
- [ ] Бейдж: «Ежедневный отчёт» (`daily`) / «Еженедельный отчёт» (Пн–Вс, `weekly`) / «Отчёт за период» (`period`)
|
||
- [ ] «Выгрузить» → спиннер «Формируется…» → файл `{prefix}_{from}_{to}.xlsx`
|
||
- [ ] Запрос `GET https://api.tnsu.kz/Report/StroyBot?start=…&end=…&projectId=…` (unix UTC 00:00:00 / 23:59:59)
|
||
- [ ] Ошибки: «Ошибка API: {status} {statusText}» / «Ошибка при загрузке отчёта»
|
||
|
||
**Сознательные отличия от main:**
|
||
- Лишний запрос к «Доступы» без фильтра по пользователю (его результат не использовался) — убран, на поведение не влияет.
|
||
- Список проектов грузится сразу при открытии, а не при первом фокусе: от статуса и прав проекта теперь зависит и меню слева.
|
||
- Карточки разделов открывают раздел в этой же вкладке; новая вкладка — Ctrl+клик или средняя кнопка (раньше всегда `_blank`). Архив — по-прежнему в новой вкладке.
|
||
- Ошибки выгрузки показываются под кнопкой, а не через `alert()`. Тексты те же.
|
||
- Поповер «?» всегда открывается вниз (раньше переворачивался вверх у края экрана).
|
||
- Адрес выгрузки берётся из настройки «Базовый URL API» (по умолчанию тот же `https://api.tnsu.kz`).
|
||
- Меню слева скрывает разделы по правилам карточек: архивный — только «Проект»; завершён или нет `edit0` — без «Отправить отчёт»; «Привязка к справочнику» — только с `edit0`.
|
||
|
||
### Сверка погодных условий — `?page=weather&projectId=&start=&end=`
|
||
Добавлена в stroy-bot-main 16.10.2026 (коммиты `d54a581`…`594fc7b`, Mariya Trishina), перенесена 20.10.2026.
|
||
- [ ] Кнопка «Сверка погодных условий» рядом с «Выгрузить», активна при обоих датах и верном периоде
|
||
- [ ] Ссылка «‹ Разделы проекта» — на главную с теми же датами
|
||
- [ ] Шапка: «Сверка погодных условий», название проекта, «Период: ДД.ММ.ГГГГ — ДД.ММ.ГГГГ» (один день — одна дата)
|
||
- [ ] Без проекта — «Проект не выбран…», без периода — «Период не указан…», загрузка — «Загрузка данных…»
|
||
- [ ] Запрос `GET https://api.tnsu.kz/Report/StroyBot/WeatherCheck?start=…&end=…&projectId=…` (unix как у выгрузки); ошибка — «Не удалось загрузить данные: {status} {statusText}»
|
||
- [ ] Метеостанция: «Метеостанция {name}», «WIGOS {code} · {N} км от объекта»
|
||
- [ ] «Погода по дням»: Дата, Наблюдений, T мин/макс, Ветер, Порывы, Осадки, Явления; пусто — «Нет данных наблюдений за период»
|
||
- [ ] «Позиции и оценка условий труда»: Дата, Профессия / вид работ, Смена (+время), Часы, Тип работ (`hours_type`), Чел., Погода в смену, Оценка, Комментарий, Акт простоя; пусто — «Нет позиций за период»
|
||
- [ ] Погода в смену: T мин…макс, ветер (+порывы), осадки, точка росы, видимость (от 1000 м — км), наблюдений, явления; нет — «нет данных»
|
||
- [ ] «Запросить оценку ИИ…» → `POST …/WeatherCheck/Assess` с `{ positions }` → «Идёт оценка, это может занять до минуты…» → позиции заменяются ответом, «Оценено позиций: N[, пропущено: M]»; ошибка — «Не удалось получить оценку: …»
|
||
- [ ] Оценка «В пределах нормы» — зелёная, другая — жёлтая; акт простоя: «Рекомендован» (+причина) / «Не требуется» / «—»
|
||
- [ ] «Примечания» — список, если API их прислал
|
||
- [ ] Числа с запятой, пустые — «—»
|
||
|
||
**Сознательные отличия от main:**
|
||
- Вид открывается обычным разделом `?page=weather&start=&end=` вместо хэша `#weathercheck?start=&end=`: «назад/вперёд» и ссылки работают, как у остальных разделов.
|
||
- Даты на главной сохраняются в адресе (`?start=&end=`), поэтому возвращаются и по ссылке «Разделы проекта», и кнопкой «назад» браузера (в main — только пока страницу не перезагрузили).
|
||
- Ошибки загрузки и оценки — плашкой ui-kit `Alert`, бейджи — `Badge` ui-kit; иконки облака и «искр» — локальный `InlineIcon` (в ките их пока нет).
|
||
- Пустое название проекта в списке (правка `?? ''`, которая была незакоммичена в main) у нас уже обработано в `projectRules.ts`.
|
||
|
||
---
|
||
|
||
## 2. Объекты (stroy-bot-objects) — `?page=objects&projectId=`
|
||
|
||
- [ ] Шапка «Объекты проекта» + название проекта («Загрузка...» / «Ошибка»)
|
||
- [ ] «Добавить объект» (только `canEdit`), «Экспорт» → «Экспортируется...» → `objects-{projectId}.xlsx` (`GET https://api.tnsu.kz/Report/ProjectObjects?projectId=`)
|
||
- [ ] Без projectId — «Вы не выбрали проект»; «Проект с ID={id} не найден»; «Ошибка: …»
|
||
- [ ] Пусто — «Объекты не найдены» + «+ Добавить объект» (если `canEdit`)
|
||
- [ ] Тулбар «{N} объектов» (рекурсивно), «Развернуть», «Свернуть»
|
||
- [ ] Дерево: отступ, иконка папки/файла, счётчик детей, шеврон, клик по строке — выделить + раскрыть
|
||
- [ ] Раскрытые и выделенный узлы сохраняются при перезагрузке дерева после операций (в памяти страницы, как в старом коде; при обновлении страницы браузера — сбрасываются)
|
||
- [ ] Уровни: 0 — Объект-пятно, 1 — Раздел, 2 — Вид работ (не глубже 3 уровней)
|
||
- [ ] Контекстное меню (⋮ и правый клик, только `canEdit`): Добавить объект (не на уровне 2), Редактировать, Работы, Удалить
|
||
- [ ] Модалка: «Название *» (обязательно, Enter — сохранить), «Родительский объект» (select только при правке Раздела: узлы уровня 0, сортировка ru, без себя и потомков), «Проект» (read-only)
|
||
- [ ] Заголовки модалки: «Добавить Объект-пятно / Раздел / Вид работ», «Редактировать …», «— (корневой)»
|
||
- [ ] Удаление: подтверждение с числом дочерних, «Это действие нельзя отменить.»
|
||
- [-] ~~Drag & drop~~ — **убрано по решению 2026-10-16** (неудобно, зона «внутрь» не работала, лишние случайные переносы). Родителя Раздела меняют через «Редактировать».
|
||
- [ ] «Работы» → раздел Работы с `objectId`
|
||
- [ ] После любой операции дерево перезагружается
|
||
- [ ] Список «Объекты»: `Title`, `project` (текст = название проекта), `parent` (self-lookup)
|
||
- [ ] Права: «Доступы» `projectId`/`userId` → `edit0`
|
||
|
||
🐞 Удаление узла не удаляет детей.
|
||
|
||
ℹ️ Экспорт падает с 500 на стороне `api.tnsu.kz`: «Failed to acquire Graph token … SPO_TENANT_ID, SPO_CLIENT_ID, SPO_CERT_PATH, SPO_CERT_PASS» — у API не настроен доступ к Graph (проверка 2026-10-16). Наш запрос доходит до API корректно; чинится на сервере.
|
||
|
||
**Сознательные отличия от objects:**
|
||
- `alert()` → сообщение `Alert` на странице (ошибки переноса, удаления, экспорта) или в модалке (ошибка сохранения). Тексты те же.
|
||
- `confirm()` удаления → `confirmModal` с кнопкой «Удалить»; текст тот же, но переносы строк ui-kit показывает одним абзацем.
|
||
- Адрес сайта — настройка «URL сайта SharePoint» (раньше `pageContext.web.absoluteUrl`), экспорт — через клиент корпоративного API и настройку «Базовый URL API» (по умолчанию тот же `https://api.tnsu.kz`).
|
||
|
||
---
|
||
|
||
## 3. Работы (stroy-bot-works) — `?page=works&projectId=&objectId=`
|
||
|
||
- [ ] Шапка с названием проекта
|
||
- [ ] «Добавить работу» (только `canEdit`)
|
||
- [ ] Таблица-дерево: #, Наименование, Ед. изм., Проектный объём (ru-RU, 3 знака), Дата (`dd.mm.yy`, «start – finish» / одна / «—»)
|
||
- [ ] Родители свёрнуты по умолчанию, шеврон «Свернуть/Развернуть», нумерация по видимым строкам
|
||
- [ ] «Загрузка данных...», «Работы не найдены» (+ кнопка), ошибки Dataverse
|
||
- [ ] Меню строки ⋮ (`canEdit`): Добавить дочернюю, Редактировать, Удалить
|
||
- [ ] Модалка: НАИМЕНОВАНИЕ *, ЕД. ИЗМ. (список «Единицы измерения», с пагинацией; текущее значение не из списка — добавить наверх), ПРОЕКТНЫЙ ОБЪЁМ (шаг 0.001), РОДИТЕЛЬСКАЯ РАБОТА (без себя и потомков), ОБЪЕКТ (read-only), ДАТА НАЧАЛА / ОКОНЧАНИЯ
|
||
- [ ] «Сохранить и добавить еще» (в режиме добавления: модалка остаётся, родитель сохраняется)
|
||
- [ ] Подтверждение удаления «Подтвердите удаление»
|
||
- [ ] Dataverse `cree9_tables`, фильтр `cree9_objectid eq '{objectId}'`; без objectId — все работы
|
||
- [ ] Навигационное свойство родителя определяется через `EntityDefinitions` (fallback `cree9_parentid`)
|
||
- [ ] Проект находится подъёмом по родителям объекта до непустого `project`
|
||
|
||
🐞 Путь объекта (`#headerTitle`) не выводится. 🐞 Отступы в списке «Родительская работа» — обычные пробелы, браузер их схлопывает (как было).
|
||
|
||
**Сознательные отличия от works:**
|
||
- `alert()` → сообщение `Alert`: ошибка сохранения — в модалке, ошибки удаления — над таблицей. Тексты те же.
|
||
- Своё окно подтверждения удаления → `confirmModal` из ui-kit с тем же заголовком, текстом и кнопками.
|
||
- PATCH и DELETE идут через тот же AAD-клиент Dataverse, а не через `fetch` с токеном вручную; заголовки те же.
|
||
- Адрес сайта — настройка «URL сайта SharePoint» (раньше `pageContext.web.absoluteUrl`), Dataverse — настройка «URL Dataverse»; имя таблицы — константа (раньше настройка `worksTable`).
|
||
- Таблица — `DataTable` из ui-kit; меню ⋮ — общее меню из `pages/_tree`.
|
||
- 🔧 **Исправлено при проверке T-WRK (2026-10-19):** дату окончания нельзя поставить раньше даты начала — календарь не даёт, а при сохранении ошибка «Дата окончания не может быть раньше даты начала» (в старом коде проверки не было).
|
||
- ✨ **Улучшено по просьбе (2026-10-19):** «Ед. изм.» — список с поиском: можно начать печатать, Enter выбирает первое найденное. Выбрать можно только значение из справочника, как и раньше.
|
||
|
||
---
|
||
|
||
## 4. Отчёты по проекту (stroy-bot-report-list) — `?page=reports&projectId=`
|
||
|
||
- [ ] Заголовок — название проекта
|
||
- [ ] Нет доступа — «Нет доступа» / «У вас нет прав на просмотр отчётов данного проекта.»
|
||
- [ ] Период по умолчанию — текущая неделя Пн–Вс; «С:», «По:», «Применить»
|
||
- [ ] Поиск «Поиск по любому полю...» (дата, номер, автор, компания, путь объекта, комментарий)
|
||
- [ ] Карточка «Отправить отчёт» (если `edit0 || aproove`)
|
||
- [ ] Карточки: `#номер`, дата, «✓ Утверждено», Пользователь, Компания (или «ID: n»), Объект (путь), Комментарий
|
||
- [ ] Копировать (`edit0 || aproove`) → форма отчёта с `copyFromId`
|
||
- [ ] Удалить (`aproove`, или `edit0` и не утверждён) → «Удалить отчёт?» → мягкое удаление `cree9_deleted = true`
|
||
- [ ] Клик / Enter / Space по карточке → форма отчёта с `reportId`
|
||
- [ ] Сортировка: дата desc, номер desc
|
||
- [ ] Пусто — «Отчёты не найдены за выбранный период.»
|
||
- [ ] Права: «Доступы» `user/Id` + `project/Id` (lookup)
|
||
|
||
🐞 Нет пагинации Dataverse (`@odata.nextLink` не читается). 🐞 Неделя по умолчанию считается в UTC.
|
||
|
||
**Сознательные отличия от report-list:**
|
||
- Карточка отчёта и «Создать на основе» открывают раздел «Форма отчёта» этого приложения (`?page=report&projectId=&reportId=` / `©FromId=`) — по-прежнему в новой вкладке. «Создать на основе» теперь настоящая ссылка (работает Ctrl+клик / средняя кнопка).
|
||
- «Отправить отчёт» — переход в раздел формы отчёта в этой же вкладке (раньше `SendReport.aspx?projectId=` тоже в этой вкладке).
|
||
- Списки читаются с сайта из настройки «URL сайта SharePoint» (по умолчанию `…/sites/stroy`), а не с сайта, где стоит web part. Id пользователя — по-прежнему `legacyPageContext.userId`.
|
||
- Тёмная тема (`onThemeChanged`) и загрузка шрифтов не переносились: шрифты грузит оболочка, оформление — ui-kit.
|
||
- Модалка удаления — `Dialog` из ui-kit (тексты те же, номер отчёта жирным).
|
||
|
||
---
|
||
|
||
## 5. Форма отчёта (stroy-bot-report) — `?page=report&projectId=[&reportId=|©FromId=]`
|
||
|
||
### Режимы
|
||
- [ ] Нет projectId — «Не указан projectId в URL»
|
||
- [ ] `reportId`: NoAccess / Approve (`aproove && !approved`) / Edit (`edit0 && !approved && дней < editDays`, по умолчанию 5) / ReadOnly
|
||
- [ ] `copyFromId`: Create, предзаполнены объект, компания, смена, комментарий, работы (с персоналом/техникой), персонал, техника; дата — сегодня, номер — 0, фото — пусто
|
||
- [ ] Без параметров — Create, смена — первая из «Смены», дата — сегодня
|
||
|
||
### Поля
|
||
- [ ] «← Вернуться назад»
|
||
- [ ] Заголовок «Отчет №N» / «Новый отчет», «Проект: …», бейдж «Утверждён» / «На утверждении»
|
||
- [ ] Дата отчета*, Смена*, Объект* (пикер с путями; смена объекта очищает работы), Компания* (с фильтром по «Компании по проекту», fallback — все)
|
||
- [ ] Работы: «+ Выбрать работу» («Сначала выберите объект»), Значение, План-факт (П / Ф / +/-, цвет), Комментарий
|
||
- [ ] Вложенные «Персонал на работе» / «Техника на работе»: Кол-во, Часы, «+ Добавить профессию / технику»
|
||
- [ ] Персонал: Кол-во, Часы, Тип часов (работы / простоя), Комментарий (обязателен для простоя)
|
||
- [ ] Техника: то же + «Часы ремонта» (комментарий обязателен для простоя и ремонта)
|
||
- [ ] Общий комментарий (contentEditable), Enter не отправляет форму SharePoint
|
||
- [ ] Фото: «Открыть папку с фото», «Добавить фото» (multiple), превью с удалением
|
||
|
||
### Пикер
|
||
- [ ] Поиск, группы для техники («Фильтры», чипы, «Все»), drill-down для работ (крошки «Все работы › …», «Выбрать «X»», «Нет работ на этом уровне»)
|
||
- [ ] Создание новой техники и новой работы (Ед. изм., План, Родительская работа)
|
||
|
||
### Сохранение
|
||
- [ ] Валидация (все сообщения из исходника)
|
||
- [ ] Номер = наибольший номер в проекте (включая удалённые) + 1 — в старом коде «количество неудалённых + 1», см. 🔧 ниже
|
||
- [ ] При правке — удалить все старые строки (сначала дочерние), создать заново
|
||
- [ ] Фото → `DocLib/{projectId}_{number}`
|
||
- [ ] «Отчет успешно сохранен!», кнопка меняется на «← Вернуться назад»
|
||
- [ ] Утверждение: подтверждение → `cree9_aprooved = true` → «Отчет утвержден!»
|
||
- [ ] Права: «Доступы» `projectId` + `userId*` (несколько вариантов имени поля)
|
||
|
||
🐞 Create без проверки NoAccess. 🐞 Дата «сегодня» — UTC.
|
||
|
||
🔧 **Исправлено при проверке T-REP (2026-10-19):**
|
||
- Только что созданная из пикера работа попадала в карточку с полным путём вместо названия, без ед. изм. и с планом 0 (в старом коде так же).
|
||
- Окно выбора на экране шире 640px — по центру (было всегда прижато к низу), поле «Значение» не вылезает за карточку.
|
||
- После «Утвердить отчет» бейдж оставался «На утверждении» до F5 — теперь сразу «Утверждён».
|
||
- «← Вернуться назад» во вкладке, открытой из списка отчётов (истории нет), ничего не делал — теперь ведёт в «Отчёты по проекту».
|
||
- Номер отчёта повторялся после мягкого удаления (номер = количество неудалённых + 1), а вместе с ним и папка фото `{projectId}_{номер}`. Теперь номер = наибольший номер в проекте, включая удалённые, + 1. Как нумерует отчёты Telegram-бот — уточнить у команды API.
|
||
|
||
**Сознательные отличия от report:**
|
||
- `confirm('Утвердить отчет? …')` → `confirmModal` из ui-kit, текст тот же.
|
||
- Адрес сайта для списков и ссылки на папку фото — настройка «URL сайта SharePoint» (раньше `pageContext.web.absoluteUrl`); путь папки при создании и id пользователя для проверки прав — тоже от этого сайта (раньше — от сайта, где стоит страница). По умолчанию это один и тот же сайт `/sites/stroy`.
|
||
- Если Dataverse ответит на создание записи `204` без тела, старый код брал id из заголовка `OData-EntityId`, а новый клиент заголовков не видит. С `Prefer: return=representation` Dataverse отвечает `201` с телом, поэтому на практике не встречается; при пустом id сохранение останавливается той же ошибкой `reportId is empty`.
|
||
- Логика режимов, валидации, сборки строк и порядка записи / удаления сверена со старым кодом построчно и покрыта тестами (45 тестов).
|
||
|
||
---
|
||
|
||
## 6. Импорт работ (stroy-bot-import-works) — `?page=import&projectId=`
|
||
|
||
- [ ] «ИМПОРТ РАБОТ» + название проекта
|
||
- [ ] Нет projectId — «Не указан projectId в URL»; нет `UniqueId0` — «Проект не привязан к справочнику проектов. Обратитесь к администратору.»
|
||
- [ ] Загрузка работ из API постранично по 200 с прогрессом «Загрузка работ... X из Y»
|
||
- [ ] Выбор объекта (модалка с поиском, сброс ×)
|
||
- [ ] Таблица: чекбокс, #, Наименование (+ бейдж объекта, «✓ импортировано», подзаголовок), Код СНБ, Ед. изм., Объём
|
||
- [ ] Поиск с debounce 250 мс по всем полям; пагинация по 100
|
||
- [ ] «Выделить всё на странице» / «Снять все на странице» (фактически — все отфильтрованные)
|
||
- [ ] Уже импортированные — неактивны, «Уже импортировано»
|
||
- [ ] «Импортировать» (нужен объект, иначе тост) и «Импорт с созданием объекта» (поиск/создание объекта и раздела по названиям из сметы)
|
||
- [ ] Подсказка «Объекты из сметы:» (3 строки + «ещё N»)
|
||
- [ ] Тосты «✓ Успешно импортировано: N» / «Импортировано: N, ошибок: M»
|
||
- [ ] Защита от дублей по `cree9_comment` = id работы из сметы
|
||
|
||
🐞 Пагинация в модалке объектов не выводится (видны только первые 100).
|
||
|
||
**Сознательные отличия от import-works:**
|
||
- Адрес Dataverse берётся из настройки «URL Dataverse», адрес сайта со списками — из «URL сайта SharePoint», API — из «Базовый URL API» (значения по умолчанию прежние; раньше Dataverse был захардкожен).
|
||
- Если объект выбрать до окончания загрузки работ, загрузка продолжается (раньше перерисовка показывала «Работы не найдены», пока загрузка не заканчивалась).
|
||
- Клик по ячейке с флажком вне самого флажка строку не переключает (флажок ui-kit обёрнут в label — иначе было бы двойное переключение). Клик по остальной части строки работает как раньше.
|
||
- Тосты при нескольких подряд показываются стопкой, а не друг поверх друга.
|
||
- Окно «Выбор объекта» — `Dialog` из ui-kit (у крестика появилась подпись «Закрыть»); поле «Объект» доступно с клавиатуры.
|
||
|
||
---
|
||
|
||
## 7. Ресурсы проекта (stroy-bot-project-assigner) — `?page=resources&projectId=`
|
||
|
||
- [ ] Нет projectId — «Проект не найден. Откройте страницу через список проектов.»
|
||
- [ ] Вкладки «Профессии (N)» и «Компании (N)»
|
||
- [ ] Слева «Доступные»: поиск, очистка ✕, «уже добавлено», «+», «Ничего не найдено» / «Нет элементов»
|
||
- [ ] Справа «Привязаны к проекту»: «−», «Ничего не добавлено»
|
||
- [ ] Оптимистичное добавление / удаление с откатом и ошибкой
|
||
- [ ] На узких экранах колонки друг под другом
|
||
|
||
🐞 Удаление ещё не сохранённой записи (временный отрицательный id) уходит на сервер, падает и откатывается с ошибкой. 🐞 Если запись удалили до ответа на добавление, она пропадает из списка, хотя на сервере создана. 🐞 Два добавления в одну миллисекунду получают одинаковый временный id.
|
||
|
||
**Сознательные отличия от assigner:**
|
||
- PnPjs заменён на SharePoint REST с теми же `$select` / `$expand` / `$filter`. Постраничная загрузка PnP (`for await`) → проход по `@odata.nextLink` / `odata.nextLink` до конца (без `$top`, страницы по умолчанию — 100).
|
||
- Добавление: `POST …/items` с тем же телом (`Title`, `projectIdId`, `professionIdId` / `companyIdId`), заголовки `Accept` и `Content-Type: application/json;odata=nometadata` + пустой `odata-version` (как в binder). Удаление: `POST …/items({id})` с `X-HTTP-Method: DELETE` и `IF-MATCH: *` — так удаляет сам PnP.
|
||
- Текст после префикса ошибки («Ошибка загрузки данных: …» и т.п.) — сообщение `HttpError` (`{status} {statusText}: {ответ сервера}`), а не формат ошибки PnP.
|
||
- Счётчик во вкладке — часть подписи («Профессии (0)»): `count` в Tabs ui-kit скрывает ноль.
|
||
- Кнопки «+» / «−» — `Button` ui-kit (с подсказками «Добавить» / «Удалить»), сообщение об ошибке закрывается крестиком рядом с `Alert`.
|
||
- 🔧 **Исправлено (найдено при проверке T-RES, 2026-10-16):** перед добавлением проверяется, нет ли уже такой привязки на сервере. Раньше при двух открытых вкладках (или двух пользователях) одна профессия / компания добавлялась дважды. Если привязка уже есть — новая запись не создаётся, показывается существующая.
|
||
|
||
---
|
||
|
||
## 8. Привязка к справочнику (stroy-bot-projects-binder) — `?page=binder&projectId=`
|
||
|
||
- [ ] Карточка проекта: название, Описание, Адрес, Статус (цвет), Начало, Окончание, Координаты
|
||
- [ ] Бейдж «Привязан» / «Не привязан», `UniqueName · UniqueId0`, «Отвязать»
|
||
- [ ] Поиск по справочнику (debounce 400 мс, пустой — все), пагинация ← / →, «{page} / {total} · всего: N»
|
||
- [ ] Карточки результатов: name, Код, Описание, Адрес, Координаты; выбор / снятие выбора; «Связать»
|
||
- [ ] Сообщения успеха и ошибок
|
||
- [ ] Запись `UniqueId0` и `UniqueName` в «Проекты»
|
||
|
||
🐞 Ответы поиска не сверяются с последним запросом — при быстром вводе может победить устаревший. 🐞 У результата без полей `latitude`/`longitude` выводится «Координаты: undefined, undefined» (проверка только на `null`).
|
||
|
||
**Сознательные отличия от binder:**
|
||
- Сайт списка «Проекты» — из общей настройки «URL сайта SharePoint» (было отдельное свойство `listSiteUrl`, значение по умолчанию то же), адрес API — из «Базовый URL API».
|
||
- У поля поиска своя кнопка очистки ✕ («Очистить») вместо встроенной в Fluent `SearchBox`; очистка по Esc не переносилась.
|
||
- Сообщения успеха / ошибки сохранения закрываются крестиком рядом с `Alert` (у `Alert` ui-kit нет закрытия).
|
||
- Статус, «Привязан» / «Не привязан» — `Badge` ui-kit тех же цветов; кнопка «Связать» — `primary` ui-kit вместо принудительно синей Fluent.
|
||
|
||
---
|
||
|
||
## Открытые вопросы
|
||
|
||
- ✅ Схема списка **«Доступы»** проверена на сайте (2026-10-16): `project` — Lookup на «Проекты», `user` — Person, права `read` / `edit0` / `aproove`. SharePoint отдаёт к ним `projectId` / `userId` — поэтому оба способа из старых репозиториев (`project/Id` + `$expand` и `projectId` / `userId`) обращаются к одним и тем же полям. Расхождения нет.
|
||
- ✅ Схема списка **«Объекты»** проверена на сайте (2026-10-16): `parent` — Lookup («Объект»), SharePoint отдаёт к нему `parentId` — чтение через `parent/Id` и запись через `parentId` обращаются к одному полю. `project` — Text (название проекта), как и ожидает код.
|
||
- ✅ В «Объектах» есть поля `level` (Number) и `skipLevelUpdate` (Boolean), которые не писал ни один старый репозиторий. Проверено 2026-10-16: `level` пустой и у старых настоящих объектов — поле никто не заполняет и ни на что не влияет. Новое приложение его тоже не трогает.
|