feat: port stroy-bot-objects as objects page

Project object tree with add/edit/delete, drag & drop re-parenting,
context menu and Excel export, 1:1 with the legacy web part. The tree
widgets live in pages/_tree so the works page can reuse them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-10-16 09:48:04 +05:00
parent 99a7631b65
commit e12fce6032
30 changed files with 2399 additions and 2 deletions
@@ -0,0 +1,64 @@
// Тексты страницы «Объекты» — дословно из stroy-bot-objects (ObjectsByProjectWebPart.ts).
export const OBJECTS_TEXTS = {
header: {
label: 'Объекты проекта',
titleLoading: 'Загрузка...',
titleError: 'Ошибка',
addRoot: 'Добавить объект',
addRootTooltip: 'Добавить корневой объект',
export: 'Экспорт',
exporting: 'Экспортируется...',
exportTooltip: 'Скачать в Excel'
},
loading: 'Загружаем данные...',
noProject: 'Вы не выбрали проект',
projectNotFound: (projectId: string): string => `Проект с ID=${projectId} не найден`,
listLoadError: (listName: string): string => `Ошибка загрузки списка "${listName}"`,
loadError: (message: string): string => `Ошибка: ${message}`,
empty: 'Объекты не найдены',
emptyAdd: '+ Добавить объект',
toolbar: {
total: (count: number): string => `${count} объектов`,
expandAll: '↕ Развернуть',
collapseAll: '↙ Свернуть'
},
nodeMenuTooltip: 'Действия',
menu: {
add: 'Добавить объект',
edit: 'Редактировать',
works: 'Работы',
delete: 'Удалить'
},
modal: {
addRootTitle: 'Добавить Объект-пятно',
addTitle: (label: string): string => `Добавить ${label}`,
editTitle: (label: string): string => `Редактировать ${label}`,
/** Что добавляется в узел уровня N. */
childLabels: ['Раздел', 'Вид работ'] as readonly string[],
/** Как называется узел уровня N. */
levelLabels: ['Объект-пятно', 'Раздел', 'Вид работ'] as readonly string[],
fallbackLabel: 'объект',
titleLabel: 'Название',
titlePlaceholder: 'Введите название объекта',
titleRequired: 'Поле обязательно для заполнения',
parentLabel: 'Родительский объект',
parentEmpty: '—',
parentRoot: '— (корневой)',
projectLabel: 'Проект',
cancel: 'Отмена',
add: 'Добавить',
save: 'Сохранить'
},
deleteConfirm: (title: string, childCount: number): string => {
const childWarning =
childCount > 0 ? `\n\n⚠️ У этого объекта есть дочерние элементы (${childCount} шт.).` : '';
return `Удалить объект «${title}»?${childWarning}\n\nЭто действие нельзя отменить.`;
},
deleteFallbackTitle: (id: number): string => `ID ${id}`,
serverError: (status: number): string => `Ошибка сервера: ${status}`,
saveError: (message: string): string => `Ошибка сохранения: ${message}`,
moveError: (message: string): string => `Не удалось переместить: ${message}`,
deleteError: (message: string): string => `Не удалось удалить: ${message}`,
exportError: (message: string): string => `Не удалось скачать файл: ${message}`
} as const;