109053e3af
Перенос, декомпозиция и перекраска форм CT/KPS/OID на @tnsu/ui-kit, config-driven дашборд-реестр по трём типам документов. Из отслеживания исключены артефакты сборки (lib-commonjs/jest-output/release) — забыты в .gitignore ранее.
165 lines
20 KiB
Markdown
165 lines
20 KiB
Markdown
# OID — перенос в ct-forms-portal (Фаза 4)
|
||
|
||
Порядок (тот же, что и CT): **Этап 1 перенос 1:1 → Этап 2 декомпозиция под структуру KPS → Этап 3 перекраска на ui-kit.**
|
||
Правило: сохранить 100% поведения; build после каждого этапа. Эталон структуры — `forms/kps/`, карта резки — `docs/CT-PORT.md` (Step2/3/4 у OID структурно близки к CT).
|
||
|
||
Источник: `oid-create-form/src/webparts/oidCreateForm/`. 10 файлов, самый большой — `Step3ComparisonTable.tsx` (2533 стр, ещё крупнее, чем был у CT).
|
||
|
||
## Разведка (перед переносом)
|
||
- `Step3ComparisonTable.tsx` (2533), `Step4Approval.tsx` (844), `Step1WorksInput.tsx` (646), `Step2CommercialOffers.tsx` (533), `hooks/useOidForm.ts` (299), `OidService.ts` (1470).
|
||
- **Шаг 1 у OID устроен ИНАЧЕ, чем у CT**: `Step1WorksInput` — это ручной ввод сгруппированных работ (`PositionGroup → OIDPosition[]`, поля `parentGroup`/`priceSmeta`/`summaSmeta`, `ComboBox` для группы), а не выборка из SP-списка потребностей (как `RequestsTable`+`useRequests` у CT). Ближе к паттерну ItemsTable из «СЗ на перемещение ТМЦ». Для Шага 1 нужен свой чертёж декомпозиции на Этапе 2 — карта CT/KPS сюда не подходит.
|
||
- Step2/Step3/Step4 структурно близки к CT (коммерческие предложения / матрица сравнения / согласование) — карта резки CT применима с поправкой на домен (parentGroup/priceSmeta вместо disciplineCode/SMR/agskCode).
|
||
- **0% ui-kit** — в отличие от CT (который уже частично сидел на `@tnsu/ui-kit@0.4.0`), OID полностью на raw Fluent. На Этапе 3 конвертировать всё, форы нет.
|
||
|
||
## Этап 1 — перенос 1:1 — ✅ ЗАВЕРШЁН
|
||
1. ✅ Скопированы `components/` и `services/` → `forms/oid/{components,services}/` (17 файлов, 1:1, без правок логики).
|
||
2. ✅ **`OidService.ts` НЕ ТРЕБУЕТ параметризации siteUrl** (в отличие от Ct/KpsCtFormService!): модуль-константа
|
||
`SITE_URL = "https://tnsukz.sharepoint.com/sites/sed"` уже прописана как раз на целевой сайт портала —
|
||
OID изначально жил на /sites/sed, миграции сайта (в отличие от CT/KPS) не было. Все ~15 обращений к SP-листам
|
||
используют эту константу напрямую (не `this.baseUrl`), so `context.pageContext.web.absoluteUrl` тоже будет
|
||
верно резолвиться при работе внутри портала. Решение: оставить `OidService.ts` полностью нетронутым —
|
||
любая правка (даже добавление неиспользуемого `siteUrl?`) была бы риском без пользы.
|
||
3. ✅ `IOidCreateFormProps.ts`: `hasTeamsContext` был объявлен, но нигде не читался (мёртвый пропс) —
|
||
сделан опциональным (`hasTeamsContext?: boolean`), чтобы порталу не нужно было его прокидывать.
|
||
`siteUrl?` НЕ добавлен (сервису он не нужен — см. п.2, не добавляем неиспользуемый пропс).
|
||
4. ✅ Обвязка портала:
|
||
- `oidDocumentConfig.ts`: добавлены `inPortal: true` + `buildInPortalParams` (условие `Черновик`/`formed` →
|
||
`oidId`, иначе → `oidid` — сверено с `useOidForm.ts`, который читает именно так; условие шире, чем у CT,
|
||
т.к. `oidDocumentConfig` уже поддерживал статус `formed` в `buildLinkUrl`).
|
||
- `CtFormsPortal.tsx`: добавлен импорт `OidCreateForm` + ветка `route.form === 'oid'` → `<OidCreateForm>` +
|
||
«← К реестру» (по образцу CT/KPS-веток). `FORM_ID_PARAMS` уже содержал `oidId`/`oidid` (задел на будущее).
|
||
- `Dashboard`/`config/index.ts` — уже были готовы (`createOidDocumentConfig()` зарегистрирован, `Dashboard.tsx`
|
||
полностью generic по `DOCUMENT_TYPES`, без хардкода typeKey) — правок не потребовалось.
|
||
5. ✅ `heft build` — зелёный (после фикса ниже), запущено и открывается в workbench.
|
||
|
||
**Build-фикс (tsconfig):** первый прогон дал ошибки `TS2550 flatMap/Object.entries does not exist` +
|
||
каскадные `TS7006 implicit any`. Причина: у исходного `oid-create-form/tsconfig.json` был явный
|
||
`"lib": ["es2019", "dom", "dom.iterable"]`, а у `ct-forms-portal/tsconfig.json` — только базовый
|
||
rig-конфиг (`dom, es5, es2015.core/collection/iterable/promise/proxy`, без ES2017/ES2019). Код OID
|
||
использует `Array.flatMap`/`Object.entries`, которых там нет. **Решение:** добавлен тот же `lib`-оверрайд
|
||
в `ct-forms-portal/tsconfig.json` (а не переписывание кода OID под ES5-совместимые аналоги) — так
|
||
проще, ничего не меняет в поведении, и это чистая надстройка типов (не влияет на CT/KPS, которые эти
|
||
методы не используют). Файлы OID остались нетронутыми.
|
||
|
||
## Этап 2 — декомпозиция
|
||
|
||
**Статус:** [x] Step2CommercialOffers ✅ | [x] Step4Approval ✅ | [ ] Step1WorksInput | [ ] Step3ComparisonTable
|
||
|
||
### ✅ Step2CommercialOffers (533) — СДЕЛАНО (build+workbench ок)
|
||
533 → контейнер `Step2CommercialOffers.tsx` (165) + `useKpProcessing.ts` (248, конвейер Syntex/Flow +
|
||
стейт uploadedFiles/suppliers/kpFiles) + `step2Persist.ts` (54, handleSave→функция, возвращает patch)
|
||
+ вьюхи `SupplierList.tsx` (43) / `UploadedKpList.tsx` (45) / `AddNoOfferDialog.tsx` (53, диалог
|
||
«Добавить без КП» — держит своё UI-состояние формы). Отличие от CT: список поставщиков ведётся прямо
|
||
на Шаге 2 (не как у CT), диалог вместо инлайн-формы добавления. Сохранён silent-guard
|
||
`if (!formData.oid) return;` перед вызовом persist (было тихим no-op, не стало видимой ошибкой).
|
||
|
||
### ✅ Step4Approval (844) — СДЕЛАНО (build+workbench ок)
|
||
844 → `useStep4Approval.ts` (478: цепочка-операции, add/delete/replace, handleActionConfirm,
|
||
send/export/restart, производные флаги + удобные методы selectAddSuggestion/cancelAddRow/openReplace/…)
|
||
+ view `Step4Approval.tsx` (426, только разметка + helpers STATUS_LABELS/getStatusClass/formatDate;
|
||
Fluent). Структурно почти идентично CT (кроме `handleExport`≈CT `handleSendToIncore`, методы сервиса
|
||
называются иначе: `generateOidReport`/`updateOIDStatus`/`resetApprovalChainToDraft`). Финальное
|
||
дробление вьюхи (add-member/replace-dialog поиск в под-компоненты) — отложено на Этап 3, как у CT.
|
||
|
||
### ✅ Step1WorksInput (646) — СДЕЛАНО (build ожидается)
|
||
646 → `useStep1WorksInput.ts` (445, перенос ВЕРБАТИМ: весь стейт/рефы(projectSearchTimer/groupsRef/
|
||
isMounted/dirtyRef/syncTimer/pendingOidRef/persistRef/scheduleSyncRef)/эффекты(sessionStorage-sync,
|
||
гидратация из formData с dirty-guard, cleanup-flush на unmount)/хендлеры(loadProjects/persistPositions/
|
||
scheduleSync/markDirtyAndSync/handleWorkNameBlur/handleProjectChange/updateGroupName/updatePosition/
|
||
addGroup/removeGroup/addPosition/removePosition/validate/handleSave)) + view `Step1WorksInput.tsx`
|
||
(239, только разметка). Риск: клубок рефов/дебаунс-синхронизации позиций в SP + защита от потери правок
|
||
при F5/гидратации (dirtyRef) — того же класса, что CP4 у CT, только меньшего масштаба. `dirtyRef`
|
||
экспортирован из хука как есть (вьюха дёргает `dirtyRef.current = true` инлайн в одном месте — сохранено
|
||
дословно, не оборачивал в сеттер). ✅ build+workbench-тест пройден пользователем (создание группы/позиции, debounce-запись, F5, blur
|
||
наименования работ → авто-создание ОИД) — без регрессий.
|
||
|
||
### ✅ Step3ComparisonTable (2533) — СДЕЛАНО по чекпоинтам (build ожидается)
|
||
Разведка подтвердила: структура похожа на CT (Step3+Step4-согласование смешаны), но домен другой
|
||
(группы позиций с колонкой «Группа» в шапке, нет валют/тумблера ед.изм., смета price/summa как read-only
|
||
референс) — и **два независимых debounce-автосейва** (офферы + критерии, оба по 1500мс) поверх
|
||
unmount-persist и beforeunload-persist — риск выше, чем был у CT.
|
||
- ✅ CP1 согласование → `useStep3Approval.ts` + `InlineApprovalChain.tsx` (голосование/делегат, 1:1,
|
||
NormalPeoplePicker/IPersonaProps оставлены как есть — Fluent, трогать на Этапе 3).
|
||
- ✅ CP2 AI/отчёт → `useAiComment.ts` (комментарий ИИ + отдельная генерация Excel-отчёта
|
||
`handleGenerateReport`/`generateOidReport` — своя фича, отсутствует в CT в таком виде) +
|
||
`AiCommentBlock.tsx` (проще, чем у CT — нет удаления комментария).
|
||
- ✅ CP3 хелперы/типы → `matrixTypes.ts` (CriteriaEntry/CellEdit/EditableOffers/ExtraSupplier/
|
||
ExtraPosition/PositionRow) + `matrixHelpers.ts` (FIXED_CRITERIA/FIXED_COLS/genId/fmt/fmtKzt/
|
||
buildOfferKey).
|
||
- ✅ CP4 ядро матрицы → `useStep3Matrix.ts` (1186 строк, перенос ВЕРБАТИМ: весь стейт/рефы/эффекты
|
||
ОБОИХ автосейвов(офферы+критерии)/unmount-persist/beforeunload-persist/мемо/хендлеры/handleSave).
|
||
`extraIdCounter` — модульная переменная в этом файле (как у CT). `getPosRowSpan` (для rowSpan группы
|
||
в шапке таблицы) тоже переехал в хук и возвращается наружу.
|
||
- **Контейнер: 2533 → 877 строк.** Финальное дробление render (таблица цен как отдельные
|
||
под-компоненты) сознательно НЕ делали — как и у CT/OID Step1/2/4, откладывается на Этап 3 вместе
|
||
с перекраской (не трогать вьюху дважды).
|
||
- ✅ Build+workbench-тест подтверждён пользователем — без регрессий (матрица, оба автосейва, F5,
|
||
unmount-persist, добавление/удаление поставщика/позиции, согласование, отчёт, AI).
|
||
|
||
## ✅✅✅ ЭТАП 2 ДЛЯ OID ПОЛНОСТЬЮ ЗАВЕРШЁН
|
||
Все 4 god-файла (Step1WorksInput/Step2CommercialOffers/Step3ComparisonTable/Step4Approval) разобраны,
|
||
build+workbench-тест пройден по каждому. Самый рискованный кусок всего OID (Step3, два автосейва) —
|
||
подтверждён рабочим. Дальше — **Этап 3: перекраска на @tnsu/ui-kit** (полный объём, 0% ui-kit форы нет,
|
||
как у KPS изначально; не забыть полный проход по цветовым токенам + проверить локальные компоненты
|
||
типа Breadcrumbs на скрытые Fluent-цвета вне `@fluentui`-импортов — урок с CT).
|
||
|
||
## Доменные отличия OID (НЕ терять при декомпозиции!)
|
||
- Шаг 1 — **ручной ввод** групп работ (`PositionGroup`/`OIDPosition`), не SP-список потребностей.
|
||
- Позиции: `parentGroup`, `positionType` ('Услуга' | 'Дополнительные затраты'), `priceSmeta`/`summaSmeta` (сметная цена — своё, у CT такого нет).
|
||
- Списки SP: суффикс «ОИД» уже в названиях (`Сравнительная таблица ОИД`, `Позиции СТ ОИД`, ...) — коллизий с CT/KPS нет.
|
||
- `SupplierOffer` в OID проще, чем у CT: нет `currencyCode`/мульти-валюты в базовых полях (нет `deliveryDistanceKm` тоже) — проверить при декомпозиции, не тащить из CT лишнюю доменку.
|
||
|
||
## ✅✅ Этап 3 — перекраска (механика) ЗАВЕРШЕНА
|
||
Все 13 файлов с Fluent → @tnsu/ui-kit (0 импортов `@fluentui` в forms/oid/, включая .tsx и .scss —
|
||
проверено grep). Порядок: тривиальные (Step2 IconButton-файлы) → простые (AiCommentBlock/
|
||
AddNoOfferDialog/Step2CommercialOffers) → Step1WorksInput → сложные (useStep3Approval+InlineApprovalChain,
|
||
Step4Approval) → главный контейнер Step3ComparisonTable.tsx (877 строк) → OidCreateForm+Breadcrumbs → токены.
|
||
|
||
- **ComboBox не тянется на ui-kit** (нет автокомплита с готовыми опциями) — сделан локальный
|
||
`Step1WorksInput/ComboField.tsx` (свободный ввод + подсказки, паттерн как у поиска участника в
|
||
Step4Approval: TextInput/native input + `<ul>` подсказок, debounce уже был в хуке). Используется для
|
||
«Проект» (серверный поиск через `a.loadProjects`) и «Ед. изм.» (локальная фильтрация статичного списка).
|
||
Эскейп-хэтч: поле «Наименование работ» тоже осталось на native `<input>` (не TextInput) — нужен `onBlur`
|
||
(создаёт ОИД по потере фокуса), которого у ui-kit `TextInput` нет.
|
||
- **`TextInput`/`TextArea` из ui-kit не имеют пропа `className`** — все места, где раньше вешали кастомный
|
||
класс на инпут (ячейки матрицы `offerInput`/`qtyInput`/`dataCellName`, критерии, тулбар) переведены на
|
||
обёртку `<div className={styles.xxx}><TextInput .../></div>` (как в CT `MatrixRowView`/`CriteriaTable`).
|
||
- **useStep3Approval/InlineApprovalChain**: `NormalPeoplePicker`+`IPersonaProps` заменены на паттерн CT —
|
||
`delegateDialog.query/suggestions/selected` + debounce 300мс через `service.searchUsers`, `Dialog`
|
||
open/title/subText/footer вместо `DialogType.normal`/`DialogFooter`.
|
||
- **Иконки**: Fluent→ui-kit спрайт (Add→plus, Delete/Cancel→trash/close, ChevronLeft→arrow-left,
|
||
ExcelDocument→document, Forward→chevron-right, Accept→check, Up/Down→arrow-up/arrow-down,
|
||
Switch→swap, AddFriend→(без иконки, нет аналога), Lightbulb→(без иконки, как у CT)).
|
||
- **Токены**: создан `forms/oid/components/common/_theme.scss` — точное зеркало CT/KPS-моста (тот же
|
||
navy/gold маппинг). Полный проход по hex-литералам (~30 уникальных кодов, ~200+ вхождений) →
|
||
bulk-sed по всем `*.module.scss` (кроме `OidCreateForm.module.scss`, где 2 литерала `#1b1a19`/`#252423`
|
||
сознательно оставлены как есть в `.dark`-блоке — тот же паттерн, что и у CT, dark-theme не токенизируем).
|
||
По ходу найдены и убраны 2 мёртвых класса (`.winBtn`/`.winBtnActive`, не использовались в разметке).
|
||
`OidCreateForm.module.scss` переписан по образцу `CtCreateForm.module.scss` (root/content/dark), Fluent
|
||
`References.scss`-импорт и мёртвые классы `.welcome`/`.welcomeImage`/`.links` убраны.
|
||
- ✅ Build+workbench-тест перекраски пройден пользователем. По итогам визуальной проверки — 2 доп. фикса:
|
||
- Билд-гоча: SPFx typings-генератор для scss выкидывает из `IExportStyles` **пустые CSS-правила**
|
||
(`.class {}` без объявлений) — TS2339 "Property does not exist", хотя класс использован в TSX.
|
||
Столкнулись дважды: (1) `.addRowBtn` в Step4Approval.module.scss забыт при переносе JSX-паттерна из
|
||
CT (там кнопки стилизовались инлайново); (2) при удалении заливки `.extraRow` (см. ниже) правило
|
||
стало пустым — пришлось оставить с `background: transparent;` вместо полного удаления класса.
|
||
Написан bash/awk-скрипт для проверки styles.X (tsx) ↔ определение класса (scss) по всему дереву —
|
||
полезно на будущее при переносе JSX между формами.
|
||
- Цвет: `.colSel`/`.thSupplierSel` (подсветка выбранного поставщика) были на `$warn-bg` — заменены на
|
||
`rgba($gold-500, 0.02)`, как у CT. `.extraRow` (доп. затраты) — заливка `$warn-bg` убрана полностью
|
||
(только `background: transparent`, класс сохранён пустым не может — см. гочу выше).
|
||
- ✅✅ **Финальное дробление render `Step3ComparisonTable.tsx` ЗАВЕРШЕНО** (877→138 строк контейнер),
|
||
по точному образцу CT: `ComparisonMatrix.tsx`(228, вся `<table>`)/`MatrixRowView.tsx`(258, обычная
|
||
позиция+bundle, с доменной ячейкой «Группа» rowSpan — которой нет у CT)/`ExtraPositionRow.tsx`(123,
|
||
доп.затраты, без bundle)/`AddExtraRow.tsx`(73)/`CriteriaTable.tsx`(125). Логика не трогалась — чистая
|
||
перекладка JSX, единый проп `matrix: Step3Matrix` (уже был экспортирован из useStep3Matrix.ts). Порядок
|
||
строк в `<tbody>` сохранён точно: позиции по группам → `AddExtraRow` → subtotal обычных → extra-позиции
|
||
→ subtotal доп.затрат → grand total. Проверка styles.X↔scss после дробления — чисто, `@fluentui` — 0
|
||
вхождений.
|
||
- ✅ Build + беглый workbench-прогон (Шаг 1→4) подтверждён пользователем после дробления — без регрессий.
|
||
|
||
## ✅✅✅ ФОРМА OID ПОЛНОСТЬЮ ЗАВЕРШЕНА
|
||
Этап 1 (перенос) + Этап 2 (декомпозиция логики) + Этап 3 (перекраска на @tnsu/ui-kit) + финальное
|
||
дробление render — всё сделано и подтверждено сборкой/workbench. OID теперь на одном уровне готовности
|
||
с CT. Три формы портала (CT/KPS/OID) в состоянии Fluent→ui-kit переведены полностью.
|