// pm-data.jsx — поглиблені дані для «Управління проєктами» // Доповнює window.DATA: склад документації (розділи/марки), план-графік етапів, // дозвільні по об'єктах, додаткові поля задач (час, коментарі, залежності, історія). // Завантажується ПІСЛЯ data.jsx. window.PM = window.PM || {}; // =================================================================== // КАТАЛОГ МАРОК (розділів проєктної документації) // =================================================================== const SECTION_CATALOG = { "ПЗ": "Пояснювальна записка", "ГП": "Генеральний план", "АР": "Архітектурні рішення", "КЖ": "Конструкції залізобетонні", "КМ": "Конструкції металеві", "КД": "Конструкції дерев'яні", "ТХ": "Технологічні рішення", "ОВ": "Опалення, вентиляція, кондиціонування", "ВК": "Водопостачання та каналізація", "ТМ": "Теплові мережі", "ЕО": "Електрообладнання та освітлення", "СС": "Системи зв'язку та сигналізації", "ПС": "Пожежна сигналізація", "ПОБ": "Проєкт організації будівництва", "КЕ": "Кошторисна документація", "ЕЕ": "Енергоефективність", "ООНС":"Оцінка впливу на довкілля", }; window.PM.SECTION_CATALOG = SECTION_CATALOG; // Статуси розділу (життєвий цикл марки) const SECTION_STATUS = { not_started: { label: "Не почато", tone: "neutral", order: 0, done: false }, in_progress: { label: "У роботі", tone: "live", order: 1, done: false }, review: { label: "Нормоконтроль", tone: "amber", order: 2, done: false }, remarks: { label: "Зауваження", tone: "warn", order: 3, done: false }, expertise: { label: "В експертизі", tone: "blue", order: 4, done: false }, issued: { label: "Видано", tone: "live", order: 5, done: true }, corrected: { label: "Відкориговано", tone: "live", order: 6, done: true }, }; window.PM.SECTION_STATUS = SECTION_STATUS; // Будівник розділу з компактного запису // S(mark, status, lead, checker, rev, sheets, due, pct, [note]) function S(mark, status, lead, checker, rev, sheets, due, pct, note) { return { mark, name: SECTION_CATALOG[mark] || mark, status, lead, checker, rev, sheets, due, pct, note: note || "" }; } // Розділи по об'єктах. due — ISO; pct — готовність 0..100. const SECTIONS = { // === ЖК «Подільський» — СС2, робочий проєкт, Ред.2 === "ukp-47": [ S("ПЗ", "in_progress", "ok", "ok", 1, 12, "2026-06-10", 60), S("ГП", "issued", "tm", "ok", 1, 8, "2026-05-15", 100), S("АР", "review", "tm", "ok", 2, 34, "2026-06-09", 85, "На нормоконтролі у ГІПа"), S("КЖ", "in_progress", "ap", "ok", 2, 48, "2026-06-12", 70, "Перерахунок плит за А500С"), S("ОВ", "in_progress", "vs", "ok", 1, 18, "2026-06-11", 55), S("ВК", "in_progress", "vs", "ok", 0, 14, "2026-06-14", 30), S("ЕО", "in_progress", "dl", "ok", 1, 22, "2026-06-13", 45), S("СС", "not_started", "dl", "ok", 0, 0, "2026-06-20", 0), S("ПС", "not_started", "dl", "ok", 0, 0, "2026-06-22", 0), S("ПОБ", "not_started", "ap", "ok", 0, 0, "2026-06-25", 0), S("ЕЕ", "not_started", "tm", "ok", 0, 0, "2026-06-24", 0), S("КЕ", "in_progress", "ok", "ok", 0, 6, "2026-06-28", 15, "Збір цін постачальників"), ], // === Школа №14 — СС2, робочий проєкт, Ред.1 === "ukp-32": [ S("ПЗ", "in_progress", "ok", "ok", 1, 10, "2026-06-20", 50), S("ГП", "issued", "tm", "ok", 1, 9, "2026-04-30", 100), S("АР", "in_progress", "tm", "ok", 1, 40, "2026-06-22", 65), S("КЖ", "remarks", "ap", "ok", 1, 36, "2026-05-25", 80, "Зауваження експерта по фундаментах — виправити"), S("ТХ", "not_started", "vs", "ok", 0, 0, "2026-06-18", 10, "Технологія харчоблоку"), S("ОВ", "in_progress", "vs", "ok", 1, 20, "2026-06-24", 40), S("ВК", "not_started", "vs", "ok", 0, 0, "2026-06-24", 0), S("ЕО", "not_started", "dl", "ok", 0, 0, "2026-06-26", 0), S("ПС", "not_started", "dl", "ok", 0, 0, "2026-06-26", 0), S("ПОБ", "not_started", "ap", "ok", 0, 0, "2026-06-27", 0), S("КЕ", "in_progress", "ok", "ok", 0, 8, "2026-06-28", 35, "В експертизі кошторису"), ], // === «Соснові гаї» — СС1, котеджне містечко, Ред.1 === "ukp-51": [ S("ПЗ", "in_progress", "ok", "ok", 1, 8, "2026-07-10", 45), S("ГП", "in_progress", "tm", "ok", 1, 10, "2026-07-08", 60), S("АР", "in_progress", "tm", "ok", 1, 24, "2026-07-12", 50), S("КЖ", "not_started", "ap", "ok", 0, 0, "2026-07-14", 0), S("ОВ", "not_started", "vs", "ok", 0, 0, "2026-07-15", 0), S("ВК", "not_started", "vs", "ok", 0, 0, "2026-07-15", 0), S("ЕО", "in_progress", "dl", "ok", 0, 6, "2026-07-13", 25, "ТЗ електропостачання"), S("КЕ", "not_started", "ok", "ok", 0, 0, "2026-07-18", 0), ], // === Реконструкція адмінбудівлі Мін'юст — СС2, авторський нагляд === "ukp-89": [ S("ПЗ", "issued", "ok", "ok", 2, 9, "2024-12-20", 100), S("ГП", "issued", "tm", "ok", 1, 6, "2024-11-15", 100), S("АР", "corrected", "tm", "ok", 2, 28, "2025-02-10", 100), S("КЖ", "corrected", "ap", "ok", 2, 31, "2025-02-15", 100), S("ОВ", "issued", "vs", "ok", 1, 16, "2024-12-25", 100), S("ВК", "issued", "vs", "ok", 1, 12, "2024-12-25", 100), S("ЕО", "issued", "dl", "ok", 1, 14, "2024-12-28", 100), S("ПОБ", "issued", "ap", "ok", 1, 8, "2024-12-30", 100), S("КЕ", "corrected", "ok", "ok", 2, 10, "2025-08-15", 100), ], }; window.PM.SECTIONS = SECTIONS; window.PM.sectionsFor = (objId) => SECTIONS[objId] || []; // =================================================================== // ПЛАН-ГРАФІК (реальні дати етапів для Ганта по об'єкту) // from/to — вікно відображення; stages — [початок, кінець] по етапах. // =================================================================== const SCHEDULE = { "ukp-47": { from: "2026-01-01", to: "2026-09-01", stages: { project: ["2026-01-15", "2026-06-12"], estimate: ["2026-05-10", "2026-06-28"], expertise: ["2026-06-20", "2026-08-15"], edessb: ["2026-08-15", "2026-08-30"], }}, "ukp-32": { from: "2026-01-01", to: "2026-10-01", stages: { project: ["2026-01-10", "2026-06-28"], estimate: ["2026-03-01", "2026-05-30"], expertise: ["2026-06-25", "2026-09-15"], edessb: ["2026-09-15", "2026-09-30"], }}, "ukp-51": { from: "2026-01-01", to: "2026-09-01", stages: { project: ["2026-01-05", "2026-07-15"], estimate: ["2026-05-01", "2026-07-20"], expertise: ["2026-07-15", "2026-08-10"], edessb: ["2026-08-10", "2026-08-25"], }}, "ukp-89": { from: "2025-08-01", to: "2026-12-31", stages: { edessb: ["2025-03-01", "2025-08-30"], supervision: ["2025-09-01", "2026-12-31"], "c-project": ["2025-10-01", "2025-11-15"], "c-estimate":["2025-11-10", "2025-11-30"], "c-expertise":["2025-11-25","2025-12-20"], "c-edessb": ["2025-12-18", "2026-01-10"], }}, }; window.PM.scheduleFor = (objId) => SCHEDULE[objId] || null; // Контракт за об'єктом + майбутні платіжні віхи (для Ганта і фінансів) window.PM.contractFor = (objId) => (window.DATA.CONTRACTS || []).find(c => c.obj === objId) || null; // =================================================================== // ДОЗВІЛЬНІ ДОКУМЕНТИ по об'єктах (ТУ / узгодження) — для Огляду і Нагляду // =================================================================== window.PM.permits = [ { obj: "ukp-47", kind: "ТУ", title: "Водопостачання + каналізація", body: "Київводоканал", status: "received", date: "2025-05-22" }, { obj: "ukp-47", kind: "ТУ", title: "Електропостачання", body: "ДТЕК", status: "received", date: "2025-06-08" }, { obj: "ukp-47", kind: "Узгодження", title: "Пожежна безпека", body: "ДСНС", status: "received", date: "2025-05-18" }, { obj: "ukp-47", kind: "Узгодження", title: "Благоустрій території", body: "Управління благоустрою", status: "pending", date: "2026-05-01" }, { obj: "ukp-32", kind: "ТУ", title: "Теплопостачання", body: "Київтеплоенерго", status: "pending", date: "2025-10-01", note: "Простій 4 міс" }, { obj: "ukp-32", kind: "Узгодження", title: "Пожежна безпека", body: "ДСНС", status: "pending", date: "2026-05-12", note: "14 днів очікування" }, { obj: "ukp-51", kind: "ТУ", title: "Електропостачання", body: "Київобленерго", status: "received", date: "2026-02-15" }, { obj: "ukp-51", kind: "ТУ", title: "Водопостачання (свердловина)", body: "Сільрада Лісники", status: "in_progress", date: "2026-01-08", note: "Сесія 28.05" }, ]; window.PM.permitsFor = (objId) => window.PM.permits.filter(p => p.obj === objId); // =================================================================== // ДОДАТКОВІ ДАНІ ЗАДАЧ — час, коментарі, залежності, файли, історія // =================================================================== const TASK_EXTRAS = { t1: { timeLogged: 1.5, timeEst: 2.5, deps: { blockedBy: [], blocks: ["t9"] }, files: [ { name: "Розрахунок_плит_ЛІРА.rpt", size: "2.4 МБ", by: "ap", date: "2026-05-26" }, { name: "Специфікація_А500С.xlsx", size: "118 КБ", by: "ap", date: "2026-05-25" }, ], comments: [ { by: "ok", date: "2026-05-26 09:12", text: "Андрію, врахуй нову специфікацію арматури — замовник наполягає на А500С." }, { by: "ap", date: "2026-05-26 10:40", text: "Прийняв. Модель оновив, армування основних балок до обіду закінчу." }, ], activity: [ { date: "2026-05-26 10:30", by: "ap", text: "перевів у статус «У роботі»" }, { date: "2026-05-26 09:05", by: "ok", text: "призначив виконавцем Петренко А." }, ], }, t3: { timeLogged: 6, timeEst: 8, deps: { blockedBy: ["t-found-geo"], blocks: [] }, files: [{ name: "КЖ_Фундаменти_Р3.dwg", size: "5.1 МБ", by: "ap", date: "2026-05-24" }], comments: [ { by: "ok", date: "2026-05-25 17:30", text: "Прострочено на день. Завершуємо сьогодні до 18:00 — експертиза чекає." }, ], activity: [ { date: "2026-05-25 18:00", by: "ok", text: "позначив як прострочену" }, { date: "2026-05-20 11:00", by: "ap", text: "додав файл КЖ_Фундаменти_Р3.dwg" }, ], }, t6: { timeLogged: 0, timeEst: 2.5, deps: { blockedBy: [], blocks: [] }, files: [], comments: [ { by: "ok", date: "2026-05-25 14:00", text: "Взяти журнал авт. нагляду та фотоапарат. Перевірити вузли примикання покрівлі." }, ], activity: [{ date: "2026-05-24 12:00", by: "ok", text: "запланував виїзд на 26.05" }], }, t2: { timeLogged: 0.5, timeEst: 1.5, deps: { blockedBy: [], blocks: [] }, files: [{ name: "Фасади_3варіанти.pdf", size: "8.7 МБ", by: "tm", date: "2026-05-25" }], comments: [ { by: "tm", date: "2026-05-26 11:00", text: "Підготував 3 варіанти фасадів. О 14:00 Zoom із замовником." }, ], activity: [{ date: "2026-05-25 16:20", by: "tm", text: "додав файл Фасади_3варіанти.pdf" }], }, }; window.PM.taskExtras = (taskId) => TASK_EXTRAS[taskId] || { timeLogged: 0, timeEst: null, deps: { blockedBy: [], blocks: [] }, files: [], comments: [], activity: [], }; // =================================================================== // СТРІЧКА АКТИВНОСТІ по об'єкту (для Огляду) // =================================================================== const ACTIVITY = { "ukp-47": [ { date: "2026-05-26 10:40", by: "ap", text: "коментар у задачі «Розрахунок плит перекриття»" }, { date: "2026-05-26 08:30", by: "ok", text: "провела планерку по об'єкту" }, { date: "2026-05-25 16:20", by: "tm", text: "виклав 3 варіанти фасадів на узгодження" }, { date: "2026-05-24 12:10", by: "ap", text: "видав розділ ГП — статус «Видано»" }, { date: "2026-05-22 09:00", by: "ok", text: "підписала акт 47-АКТ-03 на 1,26 млн ₴" }, ], "ukp-32": [ { date: "2026-05-26 09:00", by: "ok", text: "ескалувала зауваження експерта по КЖ фундаментів" }, { date: "2026-05-25 14:30", by: "ap", text: "отримав зауваження експертизи по розділу КЖ" }, { date: "2026-05-20 11:00", by: "tm", text: "оновив розділ АР — спортзал" }, ], "ukp-51": [ { date: "2026-05-26 10:00", by: "dl", text: "почав ТЗ електропостачання" }, { date: "2026-05-22 15:00", by: "ok", text: "отримала аванс 425 000 ₴ за ескізний проєкт" }, ], "ukp-89": [ { date: "2026-05-26 15:00", by: "ok", text: "виїзд авт. нагляду — вузли покрівлі" }, { date: "2026-04-15 11:00", by: "ok", text: "контроль монтажу вентиляції — без зауважень" }, ], }; window.PM.activityFor = (objId) => ACTIVITY[objId] || []; // =================================================================== // ХЕЛПЕРИ // =================================================================== window.PM.TODAY_ISO = "2026-05-26"; // Парс ISO → мілісекунди (00:00) window.PM.ms = (iso) => new Date((iso || "").slice(0, 10) + "T00:00:00").getTime(); // Днів між сьогодні та ISO (від'ємне = прострочено) window.PM.daysTo = (iso) => Math.round((window.PM.ms(iso) - window.PM.ms(window.PM.TODAY_ISO)) / 86400000); // Короткий формат "12.06" window.PM.dm = (iso) => { if (!iso) return "—"; const [, m, d] = iso.split("-"); return `${d}.${m}`; }; // Готовність розділів об'єкта (середньозважена за аркушами, мін.1) window.PM.sectionProgress = (objId) => { const list = window.PM.sectionsFor(objId); if (!list.length) return 0; let w = 0, acc = 0; list.forEach(s => { const ww = Math.max(1, s.sheets); w += ww; acc += ww * s.pct; }); return Math.round(acc / w); }; // Дедлайн об'єкта як ISO (для розрахунку днів) — доповнюємо існуючі об'єкти const DEADLINE_ISO = { "ukp-47": "2026-06-12", "ukp-32": "2026-06-28", "ukp-51": "2026-07-15", "ukp-89": "2026-12-31" }; (window.DATA.OBJECTS || []).forEach(o => { if (DEADLINE_ISO[o.id] && !o.deadlineISO) o.deadlineISO = DEADLINE_ISO[o.id]; }); // Зведення по статусах розділів window.PM.sectionSummary = (objId) => { const list = window.PM.sectionsFor(objId); const issued = list.filter(s => SECTION_STATUS[s.status]?.done).length; const remarks = list.filter(s => s.status === "remarks").length; const sheets = list.reduce((a, s) => a + s.sheets, 0); return { total: list.length, issued, remarks, sheets }; };