{"id":712,"date":"2026-07-16T12:12:41","date_gmt":"2026-07-16T12:12:41","guid":{"rendered":"https:\/\/vikassrivastava.in\/academy\/?page_id=712"},"modified":"2026-07-16T12:13:27","modified_gmt":"2026-07-16T12:13:27","slug":"project-planning-tracker","status":"publish","type":"page","link":"https:\/\/vikassrivastava.in\/academy\/project-planning-tracker\/","title":{"rendered":"Project Planning Tracker"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"712\" class=\"elementor elementor-712\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ed504a7 e-con e-atomic-element e-flexbox-base e-1e2baf6 \" data-id=\"ed504a7\" data-element_type=\"e-flexbox\" data-e-type=\"e-flexbox\" data-interaction-id=\"ed504a7\">\n    \t\t<div class=\"elementor-element elementor-element-9f65043 elementor-widget elementor-widget-html\" data-id=\"9f65043\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!--\r\nPROJECT MANAGEMENT & MIS STUDIO\r\nPaste into WordPress Custom HTML block or WPCode HTML snippet.\r\nAll data is stored locally in the browser. No server\/API required.\r\n-->\r\n<div id=\"pmis-app\" class=\"pmis-app\">\r\n  <header class=\"pmis-topbar\">\r\n    <div class=\"pmis-brand\">\r\n      <span class=\"pmis-logo\">PM<\/span>\r\n      <div><strong>Project Management & MIS Studio<\/strong><small>Plan \u2022 Track \u2022 Control \u2022 Report<\/small><\/div>\r\n    <\/div>\r\n    <div class=\"pmis-top-actions\">\r\n      <button id=\"pmis-theme\" class=\"pmis-icon-btn\" type=\"button\" title=\"Theme\">\u25d0<\/button>\r\n      <button id=\"pmis-save\" class=\"pmis-btn pmis-btn-light\" type=\"button\">Save<\/button>\r\n      <button id=\"pmis-export-json\" class=\"pmis-btn pmis-btn-light\" type=\"button\">Backup<\/button>\r\n      <label class=\"pmis-btn pmis-btn-light pmis-file-label\">Restore<input id=\"pmis-import-json\" type=\"file\" accept=\".json\" hidden><\/label>\r\n    <\/div>\r\n  <\/header>\r\n\r\n  <section class=\"pmis-hero\">\r\n    <div>\r\n      <span class=\"pmis-pill\">Browser-Based Project Management<\/span>\r\n      <h1>Complete Project Planning, Tracking & MIS Dashboard<\/h1>\r\n      <p>Manage tasks, dependencies, milestones, resources, risks, budgets and progress in one professional workspace.<\/p>\r\n    <\/div>\r\n  <\/section>\r\n\r\n  <main class=\"pmis-main\">\r\n    <nav id=\"pmis-tabs\" class=\"pmis-tabs\">\r\n      <button class=\"active\" data-tab=\"dashboard\">Dashboard<\/button>\r\n      <button data-tab=\"project\">Project Details<\/button>\r\n      <button data-tab=\"tasks\">Task Planner<\/button>\r\n      <button data-tab=\"activities\">Activity Register<\/button>\r\n      <button data-tab=\"gantt\">Gantt Chart<\/button>\r\n      <button data-tab=\"resources\">Resources<\/button>\r\n      <button data-tab=\"milestones\">Milestones<\/button>\r\n      <button data-tab=\"risks\">Risks & Issues<\/button>\r\n      <button data-tab=\"budget\">Budget<\/button>\r\n      <button data-tab=\"reports\">MIS Reports<\/button>\r\n    <\/nav>\r\n\r\n    <div id=\"pmis-alert\" class=\"pmis-alert\" hidden><\/div>\r\n\r\n    <!-- DASHBOARD -->\r\n    <section class=\"pmis-panel active\" data-panel=\"dashboard\">\r\n      <div class=\"pmis-panel-head\">\r\n        <div><h2>Executive Dashboard<\/h2><p>Real-time project health and performance summary.<\/p><\/div>\r\n        <button id=\"pmis-refresh-dashboard\" class=\"pmis-btn pmis-btn-primary\">Refresh Dashboard<\/button>\r\n      <\/div>\r\n\r\n      <div id=\"pmis-kpis\" class=\"pmis-kpis\"><\/div>\r\n\r\n      <div class=\"pmis-grid-2\">\r\n        <article class=\"pmis-card\"><h3>Task Status<\/h3><canvas id=\"pmis-status-chart\"><\/canvas><\/article>\r\n        <article class=\"pmis-card\"><h3>Planned vs Actual Progress<\/h3><canvas id=\"pmis-progress-chart\"><\/canvas><\/article>\r\n      <\/div>\r\n\r\n      <div class=\"pmis-grid-2\">\r\n        <article class=\"pmis-card\"><h3>Budget Overview<\/h3><canvas id=\"pmis-budget-chart\"><\/canvas><\/article>\r\n        <article class=\"pmis-card\"><h3>Priority Distribution<\/h3><canvas id=\"pmis-priority-chart\"><\/canvas><\/article>\r\n      <\/div>\r\n\r\n      <div class=\"pmis-grid-2\">\r\n        <article class=\"pmis-card\"><h3>Upcoming Activities<\/h3><div id=\"pmis-upcoming\"><\/div><\/article>\r\n        <article class=\"pmis-card\"><h3>Management Attention<\/h3><div id=\"pmis-attention\"><\/div><\/article>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- PROJECT -->\r\n    <section class=\"pmis-panel\" data-panel=\"project\">\r\n      <div class=\"pmis-panel-head\"><div><h2>Project Details<\/h2><p>Maintain project charter and baseline information.<\/p><\/div><\/div>\r\n      <div class=\"pmis-form-grid\">\r\n        <label>Project Name<input id=\"p-name\" type=\"text\" value=\"New Project\"><\/label>\r\n        <label>Project Code<input id=\"p-code\" type=\"text\" value=\"PRJ-001\"><\/label>\r\n        <label>Project Manager<input id=\"p-manager\" type=\"text\"><\/label>\r\n        <label>Department<input id=\"p-department\" type=\"text\"><\/label>\r\n        <label>Start Date<input id=\"p-start\" type=\"date\"><\/label>\r\n        <label>Target Finish Date<input id=\"p-finish\" type=\"date\"><\/label>\r\n        <label>Approved Budget<input id=\"p-budget\" type=\"number\" min=\"0\" step=\"0.01\" value=\"0\"><\/label>\r\n        <label>Project Status<select id=\"p-status\"><option>Not Started<\/option><option selected>In Progress<\/option><option>On Hold<\/option><option>Completed<\/option><option>Cancelled<\/option><\/select><\/label>\r\n        <label class=\"pmis-span-2\">Objective<textarea id=\"p-objective\"><\/textarea><\/label>\r\n        <label class=\"pmis-span-2\">Scope<textarea id=\"p-scope\"><\/textarea><\/label>\r\n        <label class=\"pmis-span-2\">Key Deliverables<textarea id=\"p-deliverables\"><\/textarea><\/label>\r\n        <label class=\"pmis-span-2\">Management Remarks<textarea id=\"p-remarks\"><\/textarea><\/label>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- TASKS -->\r\n    <section class=\"pmis-panel\" data-panel=\"tasks\">\r\n      <div class=\"pmis-panel-head\">\r\n        <div><h2>Task Planner<\/h2><p>Create WBS activities, dependencies, owners, dates and progress.<\/p><\/div>\r\n        <div class=\"pmis-inline-actions\">\r\n          <button id=\"pmis-add-task\" class=\"pmis-btn pmis-btn-primary\">+ Add Task<\/button>\r\n          <label class=\"pmis-btn pmis-btn-light pmis-file-label\">Import Excel<input id=\"pmis-import-excel\" type=\"file\" accept=\".xlsx,.xls,.csv\" hidden><\/label>\r\n          <button id=\"pmis-export-excel\" class=\"pmis-btn pmis-btn-light\">Export Excel<\/button>\r\n        <\/div>\r\n      <\/div>\r\n      <div class=\"pmis-toolbar\">\r\n        <input id=\"pmis-task-search\" type=\"search\" placeholder=\"Search tasks, owners or status\u2026\">\r\n        <select id=\"pmis-task-status-filter\"><option value=\"\">All Status<\/option><option>Not Started<\/option><option>In Progress<\/option><option>Completed<\/option><option>On Hold<\/option><option>Delayed<\/option><\/select>\r\n        <select id=\"pmis-task-priority-filter\"><option value=\"\">All Priority<\/option><option>Critical<\/option><option>High<\/option><option>Medium<\/option><option>Low<\/option><\/select>\r\n      <\/div>\r\n      <div class=\"pmis-table-wrap\">\r\n        <table class=\"pmis-table\">\r\n          <thead><tr>\r\n            <th>ID<\/th><th>WBS<\/th><th>Task Name<\/th><th>Owner<\/th><th>Start<\/th><th>Finish<\/th><th>Duration<\/th>\r\n            <th>Predecessor<\/th><th>Priority<\/th><th>Status<\/th><th>% Complete<\/th><th>Planned Cost<\/th><th>Actual Cost<\/th><th>Actions<\/th>\r\n          <\/tr><\/thead>\r\n          <tbody id=\"pmis-task-body\"><\/tbody>\r\n        <\/table>\r\n      <\/div>\r\n    <\/section>\r\n\r\n\r\n    <!-- ACTIVITIES -->\r\n    <section class=\"pmis-panel\" data-panel=\"activities\">\r\n      <div class=\"pmis-panel-head\">\r\n        <div>\r\n          <h2>Activity Register<\/h2>\r\n          <p>Record daily activities, progress updates, responsible persons and follow-up actions.<\/p>\r\n        <\/div>\r\n        <div class=\"pmis-inline-actions\">\r\n          <button id=\"pmis-add-activity\" class=\"pmis-btn pmis-btn-primary\">+ Add Activity<\/button>\r\n          <button id=\"pmis-export-activities\" class=\"pmis-btn pmis-btn-light\">Download Activities<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"pmis-toolbar\">\r\n        <input id=\"pmis-activity-search\" type=\"search\" placeholder=\"Search activity, owner, location or remarks\u2026\">\r\n        <select id=\"pmis-activity-status-filter\">\r\n          <option value=\"\">All Status<\/option>\r\n          <option>Planned<\/option>\r\n          <option>In Progress<\/option>\r\n          <option>Completed<\/option>\r\n          <option>On Hold<\/option>\r\n          <option>Delayed<\/option>\r\n        <\/select>\r\n        <input id=\"pmis-activity-date-filter\" type=\"date\" title=\"Filter by activity date\">\r\n      <\/div>\r\n\r\n      <div class=\"pmis-table-wrap\">\r\n        <table class=\"pmis-table\">\r\n          <thead>\r\n            <tr>\r\n              <th>ID<\/th>\r\n              <th>Activity Date<\/th>\r\n              <th>Activity<\/th>\r\n              <th>Related Task<\/th>\r\n              <th>Owner<\/th>\r\n              <th>Location<\/th>\r\n              <th>Status<\/th>\r\n              <th>% Progress<\/th>\r\n              <th>Next Action<\/th>\r\n              <th>Target Date<\/th>\r\n              <th>Remarks<\/th>\r\n              <th>Actions<\/th>\r\n            <\/tr>\r\n          <\/thead>\r\n          <tbody id=\"pmis-activity-body\"><\/tbody>\r\n        <\/table>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <!-- GANTT -->\r\n    <section class=\"pmis-panel\" data-panel=\"gantt\">\r\n      <div class=\"pmis-panel-head\">\r\n        <div><h2>Gantt Chart<\/h2><p>Visual timeline of project activities and progress.<\/p><\/div>\r\n        <div class=\"pmis-inline-actions\"><button id=\"pmis-gantt-zoom-out\" class=\"pmis-btn pmis-btn-light\">\u2212 Zoom<\/button><button id=\"pmis-gantt-zoom-in\" class=\"pmis-btn pmis-btn-light\">+ Zoom<\/button><\/div>\r\n      <\/div>\r\n      <div id=\"pmis-gantt\" class=\"pmis-gantt\"><\/div>\r\n    <\/section>\r\n\r\n    <!-- RESOURCES -->\r\n    <section class=\"pmis-panel\" data-panel=\"resources\">\r\n      <div class=\"pmis-panel-head\"><div><h2>Resource Management<\/h2><p>Track resource capacity, allocation and utilization.<\/p><\/div><button id=\"pmis-add-resource\" class=\"pmis-btn pmis-btn-primary\">+ Add Resource<\/button><\/div>\r\n      <div class=\"pmis-table-wrap\"><table class=\"pmis-table\"><thead><tr><th>Name<\/th><th>Role<\/th><th>Department<\/th><th>Capacity Hours<\/th><th>Allocated Hours<\/th><th>Utilization<\/th><th>Rate\/Hour<\/th><th>Actions<\/th><\/tr><\/thead><tbody id=\"pmis-resource-body\"><\/tbody><\/table><\/div>\r\n    <\/section>\r\n\r\n    <!-- MILESTONES -->\r\n    <section class=\"pmis-panel\" data-panel=\"milestones\">\r\n      <div class=\"pmis-panel-head\"><div><h2>Milestones<\/h2><p>Track key review dates and major deliverables.<\/p><\/div><button id=\"pmis-add-milestone\" class=\"pmis-btn pmis-btn-primary\">+ Add Milestone<\/button><\/div>\r\n      <div class=\"pmis-table-wrap\"><table class=\"pmis-table\"><thead><tr><th>Milestone<\/th><th>Planned Date<\/th><th>Actual Date<\/th><th>Owner<\/th><th>Status<\/th><th>Remarks<\/th><th>Actions<\/th><\/tr><\/thead><tbody id=\"pmis-milestone-body\"><\/tbody><\/table><\/div>\r\n    <\/section>\r\n\r\n    <!-- RISKS -->\r\n    <section class=\"pmis-panel\" data-panel=\"risks\">\r\n      <div class=\"pmis-panel-head\"><div><h2>Risks & Issues<\/h2><p>Maintain risk register, impact, mitigation and ownership.<\/p><\/div><button id=\"pmis-add-risk\" class=\"pmis-btn pmis-btn-primary\">+ Add Risk \/ Issue<\/button><\/div>\r\n      <div class=\"pmis-table-wrap\"><table class=\"pmis-table\"><thead><tr><th>ID<\/th><th>Type<\/th><th>Description<\/th><th>Probability<\/th><th>Impact<\/th><th>Score<\/th><th>Owner<\/th><th>Mitigation \/ Action<\/th><th>Status<\/th><th>Actions<\/th><\/tr><\/thead><tbody id=\"pmis-risk-body\"><\/tbody><\/table><\/div>\r\n    <\/section>\r\n\r\n    <!-- BUDGET -->\r\n    <section class=\"pmis-panel\" data-panel=\"budget\">\r\n      <div class=\"pmis-panel-head\"><div><h2>Budget & Cost Control<\/h2><p>Track planned, committed and actual costs.<\/p><\/div><button id=\"pmis-add-budget\" class=\"pmis-btn pmis-btn-primary\">+ Add Cost Item<\/button><\/div>\r\n      <div id=\"pmis-budget-kpis\" class=\"pmis-kpis\"><\/div>\r\n      <div class=\"pmis-table-wrap\"><table class=\"pmis-table\"><thead><tr><th>Category<\/th><th>Description<\/th><th>Planned<\/th><th>Committed<\/th><th>Actual<\/th><th>Variance<\/th><th>Vendor \/ Owner<\/th><th>Actions<\/th><\/tr><\/thead><tbody id=\"pmis-budget-body\"><\/tbody><\/table><\/div>\r\n    <\/section>\r\n\r\n    <!-- REPORTS -->\r\n    <section class=\"pmis-panel\" data-panel=\"reports\">\r\n      <div class=\"pmis-panel-head\"><div><h2>MIS Reports<\/h2><p>Generate management-ready reports and exports.<\/p><\/div><\/div>\r\n      <div class=\"pmis-report-grid\">\r\n        <button data-report=\"summary\">Executive Summary<\/button>\r\n        <button data-report=\"task\">Task Status Report<\/button>\r\n        <button data-report=\"activity\">Activity Report<\/button>\r\n        <button data-report=\"delay\">Delay & Overdue Report<\/button>\r\n        <button data-report=\"resource\">Resource Utilization<\/button>\r\n        <button data-report=\"risk\">Risk Register<\/button>\r\n        <button data-report=\"budget\">Budget Variance<\/button>\r\n        <button data-report=\"milestone\">Milestone Status<\/button>\r\n        <button data-report=\"full\">Full Project MIS<\/button>\r\n      <\/div>\r\n      <div id=\"pmis-report-preview\" class=\"pmis-report-preview\">\r\n        <h3>Select a report<\/h3><p>The generated report will appear here.<\/p>\r\n      <\/div>\r\n      <div class=\"pmis-inline-actions pmis-report-actions\">\r\n        <button id=\"pmis-download-report-html\" class=\"pmis-btn pmis-btn-primary\" disabled>Download HTML Report<\/button>\r\n        <button id=\"pmis-print-report\" class=\"pmis-btn pmis-btn-light\" disabled>Print \/ Save PDF<\/button>\r\n      <\/div>\r\n    <\/section>\r\n  <\/main>\r\n\r\n  <!-- MODAL -->\r\n  <div id=\"pmis-modal\" class=\"pmis-modal\" hidden>\r\n    <div class=\"pmis-modal-box\">\r\n      <div class=\"pmis-modal-head\"><h3 id=\"pmis-modal-title\">Add Record<\/h3><button id=\"pmis-modal-close\" type=\"button\">\u00d7<\/button><\/div>\r\n      <form id=\"pmis-modal-form\" class=\"pmis-form-grid\"><\/form>\r\n      <div class=\"pmis-modal-actions\"><button id=\"pmis-modal-cancel\" class=\"pmis-btn pmis-btn-light\" type=\"button\">Cancel<\/button><button id=\"pmis-modal-save\" class=\"pmis-btn pmis-btn-primary\" type=\"button\">Save<\/button><\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<style>\r\n#pmis-app{--p:#1d4ed8;--p2:#6d5dfc;--g:#16865f;--r:#c43d4b;--o:#d88700;--bg:#f4f7fb;--s:#fff;--s2:#eef3f8;--t:#172033;--m:#687386;--b:#dbe3ee;--sh:0 16px 40px rgba(31,48,83,.1);font-family:Inter,system-ui,-apple-system,\"Segoe UI\",sans-serif;color:var(--t);background:var(--bg);border-radius:22px;overflow:hidden;line-height:1.45}\r\n#pmis-app.dark{--bg:#0f141d;--s:#171e29;--s2:#222b38;--t:#f4f7fb;--m:#aab4c3;--b:#303b4c;--sh:0 16px 40px rgba(0,0,0,.3)}\r\n#pmis-app *{box-sizing:border-box}#pmis-app button,#pmis-app input,#pmis-app select,#pmis-app textarea{font:inherit}#pmis-app button{cursor:pointer}\r\n.pmis-topbar{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:16px clamp(14px,4vw,50px);background:var(--s);border-bottom:1px solid var(--b)}\r\n.pmis-brand{display:flex;align-items:center;gap:12px}.pmis-brand div{display:flex;flex-direction:column}.pmis-brand strong{font-size:20px}.pmis-brand small{color:var(--m)}.pmis-logo{display:grid;place-items:center;width:48px;height:48px;border-radius:14px;background:linear-gradient(135deg,var(--p),var(--p2));color:#fff;font-weight:900}.pmis-top-actions,.pmis-inline-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}\r\n.pmis-btn,.pmis-file-label{border:0;border-radius:10px;padding:10px 14px;font-weight:780;display:inline-flex;align-items:center;justify-content:center;gap:7px}.pmis-btn-primary{background:linear-gradient(135deg,var(--p),var(--p2));color:#fff}.pmis-btn-light{background:var(--s2);border:1px solid var(--b);color:var(--t)}.pmis-icon-btn{width:40px;height:40px;border:1px solid var(--b);border-radius:10px;background:var(--s2);color:var(--t)}\r\n.pmis-hero{padding:46px 18px;text-align:center;background:radial-gradient(circle at 12% 20%,rgba(29,78,216,.14),transparent 28%),radial-gradient(circle at 87% 25%,rgba(109,93,252,.12),transparent 28%),var(--s)}.pmis-pill{display:inline-block;padding:7px 13px;border-radius:999px;background:rgba(29,78,216,.1);color:var(--p);font-size:12px;font-weight:850}.pmis-hero h1{max-width:1000px;margin:15px auto 10px;font-size:clamp(32px,5vw,56px);line-height:1.08;letter-spacing:-.04em}.pmis-hero p{max-width:820px;margin:auto;color:var(--m);font-size:18px}\r\n.pmis-main{max-width:1450px;margin:auto;padding:24px clamp(10px,2vw,26px) 44px}.pmis-tabs{display:flex;gap:8px;overflow:auto;padding-bottom:10px;margin-bottom:18px}.pmis-tabs button{white-space:nowrap;border:1px solid var(--b);background:var(--s);color:var(--t);padding:10px 14px;border-radius:10px;font-weight:760}.pmis-tabs button.active{background:var(--p);color:#fff;border-color:var(--p)}\r\n.pmis-panel{display:none}.pmis-panel.active{display:block}.pmis-panel-head{display:flex;justify-content:space-between;align-items:flex-start;gap:18px;margin-bottom:18px}.pmis-panel-head h2{margin:0 0 4px;font-size:28px}.pmis-panel-head p{margin:0;color:var(--m)}\r\n.pmis-alert{padding:12px 14px;margin-bottom:15px;border-radius:10px;background:rgba(196,61,75,.1);border:1px solid rgba(196,61,75,.25);color:var(--r)}\r\n.pmis-kpis{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:16px}.pmis-kpi{padding:16px;border:1px solid var(--b);border-radius:14px;background:var(--s);box-shadow:var(--sh)}.pmis-kpi b{display:block;font-size:26px}.pmis-kpi small{color:var(--m)}.pmis-kpi.good b{color:var(--g)}.pmis-kpi.warn b{color:var(--o)}.pmis-kpi.bad b{color:var(--r)}\r\n.pmis-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:15px;margin-bottom:15px}.pmis-card{padding:18px;border:1px solid var(--b);border-radius:15px;background:var(--s);box-shadow:var(--sh);min-height:290px}.pmis-card h3{margin:0 0 12px}.pmis-card canvas{max-height:245px}\r\n.pmis-form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:13px}.pmis-form-grid label{display:flex;flex-direction:column;gap:6px;font-size:13px;font-weight:720}.pmis-form-grid input,.pmis-form-grid select,.pmis-form-grid textarea,.pmis-toolbar input,.pmis-toolbar select{width:100%;border:1px solid var(--b);border-radius:9px;background:var(--s);color:var(--t);padding:10px 11px}.pmis-form-grid textarea{min-height:90px;resize:vertical}.pmis-span-2{grid-column:1\/-1}\r\n.pmis-toolbar{display:grid;grid-template-columns:2fr 1fr 1fr;gap:10px;margin-bottom:12px}.pmis-table-wrap{overflow:auto;border:1px solid var(--b);border-radius:12px;background:var(--s)}.pmis-table{border-collapse:collapse;width:100%;font-size:12px}.pmis-table th,.pmis-table td{padding:8px 9px;border-right:1px solid var(--b);border-bottom:1px solid var(--b);white-space:nowrap}.pmis-table th{position:sticky;top:0;background:var(--s2);z-index:2;text-align:left}.pmis-table td.task-name{min-width:220px;white-space:normal}.pmis-table input,.pmis-table select{min-width:90px;border:1px solid var(--b);border-radius:7px;background:var(--s);color:var(--t);padding:6px}.pmis-row-actions{display:flex;gap:5px}.pmis-mini{border:1px solid var(--b);background:var(--s2);color:var(--t);border-radius:7px;padding:5px 7px}.pmis-mini.danger{color:var(--r)}\r\n.pmis-status{padding:4px 8px;border-radius:999px;font-size:11px;font-weight:800}.pmis-status.completed{background:rgba(22,134,95,.13);color:var(--g)}.pmis-status.delayed{background:rgba(196,61,75,.12);color:var(--r)}.pmis-status.progress{background:rgba(29,78,216,.12);color:var(--p)}.pmis-status.hold{background:rgba(216,135,0,.13);color:var(--o)}\r\n.pmis-gantt{overflow:auto;border:1px solid var(--b);border-radius:12px;background:var(--s);min-height:350px}.pmis-gantt-grid{display:grid;min-width:1000px}.pmis-gantt-row{display:grid;grid-template-columns:240px 1fr;border-bottom:1px solid var(--b);min-height:38px}.pmis-gantt-name{position:sticky;left:0;z-index:3;background:var(--s);padding:9px;border-right:1px solid var(--b);font-size:12px}.pmis-gantt-track{position:relative;background-image:linear-gradient(to right,var(--b) 1px,transparent 1px);background-size:var(--gantt-day,24px) 100%}.pmis-gantt-bar{position:absolute;top:7px;height:24px;border-radius:6px;background:linear-gradient(90deg,var(--p),var(--p2));color:#fff;font-size:10px;padding:5px 7px;overflow:hidden}.pmis-gantt-progress{position:absolute;left:0;top:0;bottom:0;background:rgba(255,255,255,.28)}.pmis-gantt-head{display:grid;grid-template-columns:240px 1fr;position:sticky;top:0;z-index:4;background:var(--s2);border-bottom:1px solid var(--b)}.pmis-gantt-days{display:flex}.pmis-gantt-day{flex:0 0 var(--gantt-day,24px);font-size:9px;padding:7px 1px;text-align:center;border-right:1px solid var(--b)}\r\n.pmis-report-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.pmis-report-grid button{padding:18px;border:1px solid var(--b);border-radius:12px;background:var(--s);color:var(--t);font-weight:800}.pmis-report-grid button:hover{border-color:var(--p)}.pmis-report-preview{margin-top:16px;padding:22px;border:1px solid var(--b);border-radius:14px;background:var(--s);min-height:240px}.pmis-report-actions{margin-top:14px}\r\n.pmis-list{display:grid;gap:8px}.pmis-list-item{padding:10px 12px;border:1px solid var(--b);border-radius:10px;background:var(--s2)}.pmis-list-item b{display:block}.pmis-list-item small{color:var(--m)}\r\n#pmis-app [hidden]{display:none!important}.pmis-modal{position:fixed;inset:0;z-index:999999;background:rgba(9,14,25,.62);display:grid;place-items:center;padding:16px}.pmis-modal-box{width:min(760px,100%);max-height:90vh;overflow:auto;background:var(--s);border-radius:16px;padding:20px;box-shadow:0 20px 60px rgba(0,0,0,.35)}.pmis-modal-head{display:flex;justify-content:space-between;align-items:center}.pmis-modal-head h3{margin:0}.pmis-modal-head button{border:0;background:transparent;color:var(--t);font-size:28px}.pmis-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}\r\n@media(max-width:1000px){.pmis-kpis{grid-template-columns:repeat(3,1fr)}.pmis-grid-2{grid-template-columns:1fr}.pmis-report-grid{grid-template-columns:repeat(2,1fr)}}\r\n@media(max-width:720px){#pmis-app{border-radius:0}.pmis-brand small{display:none}.pmis-brand strong{font-size:15px}.pmis-topbar{padding:12px}.pmis-top-actions .pmis-btn{display:none}.pmis-kpis{grid-template-columns:repeat(2,1fr)}.pmis-form-grid{grid-template-columns:1fr}.pmis-span-2{grid-column:auto}.pmis-toolbar{grid-template-columns:1fr}.pmis-panel-head{flex-direction:column}.pmis-report-grid{grid-template-columns:1fr}}\r\n<\/style>\r\n\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js@4.4.3\/dist\/chart.umd.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/xlsx@0.18.5\/dist\/xlsx.full.min.js\"><\/script>\r\n\r\n<script>\r\n(function(){\r\n'use strict';\r\nconst app=document.getElementById('pmis-app'); if(!app||app.dataset.ready)return; app.dataset.ready='1';\r\nconst $=id=>document.getElementById(id);\r\nconst TODAY=new Date().toISOString().slice(0,10);\r\nconst addDays=(d,n)=>{const x=new Date(d||TODAY);x.setDate(x.getDate()+Number(n||0));return x.toISOString().slice(0,10)};\r\nconst daysBetween=(a,b)=>Math.max(1,Math.round((new Date(b)-new Date(a))\/86400000)+1);\r\nconst money=n=>Number(n||0).toLocaleString(undefined,{maximumFractionDigits:2});\r\nconst esc=s=>String(s??'').replace(\/[&<>\"']\/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#039;'}[c]));\r\nconst uid=()=>Date.now().toString(36)+Math.random().toString(36).slice(2,6);\r\n\r\nlet state={\r\n project:{name:'New Project',code:'PRJ-001',manager:'',department:'',start:TODAY,finish:addDays(TODAY,60),budget:0,status:'In Progress',objective:'',scope:'',deliverables:'',remarks:''},\r\n tasks:[\r\n  {id:1,wbs:'1.0',name:'Project Kick-off',owner:'Project Manager',start:TODAY,finish:addDays(TODAY,1),pred:'',priority:'High',status:'Completed',progress:100,planned:0,actual:0},\r\n  {id:2,wbs:'2.0',name:'Requirement Finalization',owner:'Business Team',start:addDays(TODAY,2),finish:addDays(TODAY,7),pred:'1',priority:'High',status:'In Progress',progress:40,planned:0,actual:0}\r\n ],\r\n activities:[],resources:[],milestones:[],risks:[],budgetItems:[],\r\n settings:{ganttDay:24}\r\n};\r\nlet charts={},currentReportHtml='',editing={type:null,index:null};\r\n\r\nfunction showAlert(msg){$('pmis-alert').textContent=msg;$('pmis-alert').hidden=false;setTimeout(()=>$('pmis-alert').hidden=true,4500)}\r\nfunction save(){readProjectForm();localStorage.setItem('pmis-project-data',JSON.stringify(state));showAlert('Project saved in this browser.')}\r\nfunction load(){try{const x=localStorage.getItem('pmis-project-data');if(x)state=JSON.parse(x)}catch(e){} state.activities=state.activities||[];state.resources=state.resources||[];state.milestones=state.milestones||[];state.risks=state.risks||[];state.budgetItems=state.budgetItems||[];populateProjectForm();renderAll()}\r\nfunction downloadBlob(blob,name){const u=URL.createObjectURL(blob),a=document.createElement('a');a.href=u;a.download=name;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(u),1200)}\r\nfunction readProjectForm(){\r\n state.project={name:$('p-name').value,code:$('p-code').value,manager:$('p-manager').value,department:$('p-department').value,start:$('p-start').value,finish:$('p-finish').value,budget:Number($('p-budget').value||0),status:$('p-status').value,objective:$('p-objective').value,scope:$('p-scope').value,deliverables:$('p-deliverables').value,remarks:$('p-remarks').value}\r\n}\r\nfunction populateProjectForm(){const p=state.project;['name','code','manager','department','start','finish','budget','status','objective','scope','deliverables','remarks'].forEach(k=>{const el=$('p-'+k);if(el)el.value=p[k]??''})}\r\nfunction activateTab(name){document.querySelectorAll('#pmis-tabs button').forEach(b=>b.classList.toggle('active',b.dataset.tab===name));document.querySelectorAll('.pmis-panel').forEach(p=>p.classList.toggle('active',p.dataset.panel===name));if(name==='dashboard')renderDashboard();if(name==='gantt')renderGantt();if(name==='reports'){}}\r\nfunction statusClass(s){return s==='Completed'?'completed':s==='Delayed'?'delayed':s==='In Progress'?'progress':s==='On Hold'?'hold':''}\r\nfunction taskDuration(t){return daysBetween(t.start,t.finish)}\r\nfunction filteredTasks(){const q=$('pmis-task-search').value.toLowerCase(),s=$('pmis-task-status-filter').value,p=$('pmis-task-priority-filter').value;return state.tasks.filter(t=>(!q||[t.name,t.owner,t.status,t.wbs].join(' ').toLowerCase().includes(q))&&(!s||t.status===s)&&(!p||t.priority===p))}\r\nfunction renderTasks(){\r\n const body=$('pmis-task-body');body.innerHTML='';\r\n filteredTasks().forEach((t)=>{\r\n  const idx=state.tasks.indexOf(t),tr=document.createElement('tr');\r\n  tr.innerHTML=`<td>${t.id}<\/td><td>${esc(t.wbs)}<\/td><td class=\"task-name\">${esc(t.name)}<\/td><td>${esc(t.owner)}<\/td><td>${t.start}<\/td><td>${t.finish}<\/td><td>${taskDuration(t)}<\/td><td>${esc(t.pred)}<\/td><td>${t.priority}<\/td><td><span class=\"pmis-status ${statusClass(t.status)}\">${t.status}<\/span><\/td><td>${t.progress}%<\/td><td>${money(t.planned)}<\/td><td>${money(t.actual)}<\/td><td><div class=\"pmis-row-actions\"><button class=\"pmis-mini\" data-edit-task=\"${idx}\">Edit<\/button><button class=\"pmis-mini danger\" data-del-task=\"${idx}\">Delete<\/button><\/div><\/td>`;\r\n  body.appendChild(tr);\r\n });\r\n}\r\n\r\nfunction filteredActivities(){\r\n const q=($('pmis-activity-search')?.value||'').toLowerCase();\r\n const s=$('pmis-activity-status-filter')?.value||'';\r\n const d=$('pmis-activity-date-filter')?.value||'';\r\n return state.activities.filter(a=>\r\n   (!q||[a.activity,a.task,a.owner,a.location,a.nextAction,a.remarks].join(' ').toLowerCase().includes(q))&&\r\n   (!s||a.status===s)&&(!d||a.date===d)\r\n );\r\n}\r\nfunction renderActivities(){\r\n const body=$('pmis-activity-body'); if(!body)return;\r\n body.innerHTML=filteredActivities().map(a=>{\r\n   const i=state.activities.indexOf(a);\r\n   return `<tr>\r\n    <td>${esc(a.id)}<\/td>\r\n    <td>${a.date||''}<\/td>\r\n    <td class=\"task-name\">${esc(a.activity)}<\/td>\r\n    <td class=\"task-name\">${esc(a.task)}<\/td>\r\n    <td>${esc(a.owner)}<\/td>\r\n    <td>${esc(a.location)}<\/td>\r\n    <td><span class=\"pmis-status ${statusClass(a.status)}\">${esc(a.status)}<\/span><\/td>\r\n    <td>${Number(a.progress||0)}%<\/td>\r\n    <td class=\"task-name\">${esc(a.nextAction)}<\/td>\r\n    <td>${a.targetDate||''}<\/td>\r\n    <td class=\"task-name\">${esc(a.remarks)}<\/td>\r\n    <td><div class=\"pmis-row-actions\"><button class=\"pmis-mini\" data-edit-activity=\"${i}\">Edit<\/button><button class=\"pmis-mini danger\" data-del-activity=\"${i}\">Delete<\/button><\/div><\/td>\r\n   <\/tr>`;\r\n }).join('');\r\n}\r\n\r\nfunction renderResources(){\r\n $('pmis-resource-body').innerHTML=state.resources.map((r,i)=>{const util=r.capacity?Math.round(r.allocated\/r.capacity*100):0;return `<tr><td>${esc(r.name)}<\/td><td>${esc(r.role)}<\/td><td>${esc(r.department)}<\/td><td>${r.capacity}<\/td><td>${r.allocated}<\/td><td>${util}%<\/td><td>${money(r.rate)}<\/td><td><button class=\"pmis-mini\" data-edit-resource=\"${i}\">Edit<\/button> <button class=\"pmis-mini danger\" data-del-resource=\"${i}\">Delete<\/button><\/td><\/tr>`}).join('');\r\n}\r\nfunction renderMilestones(){\r\n $('pmis-milestone-body').innerHTML=state.milestones.map((m,i)=>`<tr><td>${esc(m.name)}<\/td><td>${m.planned}<\/td><td>${m.actual||''}<\/td><td>${esc(m.owner)}<\/td><td><span class=\"pmis-status ${statusClass(m.status)}\">${m.status}<\/span><\/td><td>${esc(m.remarks)}<\/td><td><button class=\"pmis-mini\" data-edit-milestone=\"${i}\">Edit<\/button> <button class=\"pmis-mini danger\" data-del-milestone=\"${i}\">Delete<\/button><\/td><\/tr>`).join('');\r\n}\r\nfunction renderRisks(){\r\n $('pmis-risk-body').innerHTML=state.risks.map((r,i)=>`<tr><td>${esc(r.id)}<\/td><td>${r.type}<\/td><td class=\"task-name\">${esc(r.description)}<\/td><td>${r.probability}<\/td><td>${r.impact}<\/td><td>${Number(r.probability)*Number(r.impact)}<\/td><td>${esc(r.owner)}<\/td><td class=\"task-name\">${esc(r.action)}<\/td><td>${r.status}<\/td><td><button class=\"pmis-mini\" data-edit-risk=\"${i}\">Edit<\/button> <button class=\"pmis-mini danger\" data-del-risk=\"${i}\">Delete<\/button><\/td><\/tr>`).join('');\r\n}\r\nfunction renderBudget(){\r\n let planned=0,committed=0,actual=0;\r\n $('pmis-budget-body').innerHTML=state.budgetItems.map((b,i)=>{planned+=+b.planned||0;committed+=+b.committed||0;actual+=+b.actual||0;return `<tr><td>${esc(b.category)}<\/td><td>${esc(b.description)}<\/td><td>${money(b.planned)}<\/td><td>${money(b.committed)}<\/td><td>${money(b.actual)}<\/td><td>${money((+b.planned||0)-(+b.actual||0))}<\/td><td>${esc(b.owner)}<\/td><td><button class=\"pmis-mini\" data-edit-budget=\"${i}\">Edit<\/button> <button class=\"pmis-mini danger\" data-del-budget=\"${i}\">Delete<\/button><\/td><\/tr>`}).join('');\r\n $('pmis-budget-kpis').innerHTML=`<div class=\"pmis-kpi\"><b>${money(state.project.budget)}<\/b><small>Approved Budget<\/small><\/div><div class=\"pmis-kpi\"><b>${money(planned)}<\/b><small>Planned Cost<\/small><\/div><div class=\"pmis-kpi\"><b>${money(committed)}<\/b><small>Committed Cost<\/small><\/div><div class=\"pmis-kpi\"><b>${money(actual)}<\/b><small>Actual Cost<\/small><\/div><div class=\"pmis-kpi ${(state.project.budget-actual)<0?'bad':'good'}\"><b>${money(state.project.budget-actual)}<\/b><small>Budget Balance<\/small><\/div>`;\r\n}\r\nfunction calcMetrics(){\r\n const total=state.tasks.length,completed=state.tasks.filter(t=>t.status==='Completed').length,inProgress=state.tasks.filter(t=>t.status==='In Progress').length,delayed=state.tasks.filter(t=>t.status==='Delayed'||(t.finish<TODAY&&t.progress<100)).length;\r\n const avg=total?Math.round(state.tasks.reduce((s,t)=>s+(+t.progress||0),0)\/total):0;\r\n const planned=state.tasks.reduce((s,t)=>s+(+t.planned||0),0)+state.budgetItems.reduce((s,b)=>s+(+b.planned||0),0);\r\n const actual=state.tasks.reduce((s,t)=>s+(+t.actual||0),0)+state.budgetItems.reduce((s,b)=>s+(+b.actual||0),0);\r\n const highRisks=state.risks.filter(r=>(+r.probability)*(+r.impact)>=15&&r.status!=='Closed').length;\r\n return{total,completed,inProgress,delayed,avg,planned,actual,highRisks}\r\n}\r\nfunction chart(id,type,data,options={}){\r\n if(charts[id])charts[id].destroy();\r\n charts[id]=new Chart($(id),{type,data,options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'bottom'}},...options}});\r\n}\r\nfunction renderDashboard(){\r\n const m=calcMetrics(),budgetBalance=state.project.budget-m.actual;\r\n $('pmis-kpis').innerHTML=`<div class=\"pmis-kpi\"><b>${m.total}<\/b><small>Total Tasks<\/small><\/div><div class=\"pmis-kpi good\"><b>${m.completed}<\/b><small>Completed<\/small><\/div><div class=\"pmis-kpi\"><b>${m.avg}%<\/b><small>Overall Progress<\/small><\/div><div class=\"pmis-kpi ${m.delayed?'bad':'good'}\"><b>${m.delayed}<\/b><small>Delayed \/ Overdue<\/small><\/div><div class=\"pmis-kpi ${m.highRisks?'warn':'good'}\"><b>${m.highRisks}<\/b><small>High Risks<\/small><\/div><div class=\"pmis-kpi ${budgetBalance<0?'bad':'good'}\"><b>${money(budgetBalance)}<\/b><small>Budget Balance<\/small><\/div>`;\r\n const counts={};['Not Started','In Progress','Completed','On Hold','Delayed'].forEach(s=>counts[s]=state.tasks.filter(t=>t.status===s).length);\r\n chart('pmis-status-chart','doughnut',{labels:Object.keys(counts),datasets:[{data:Object.values(counts)}]});\r\n chart('pmis-progress-chart','bar',{labels:state.tasks.slice(0,10).map(t=>t.name),datasets:[{label:'Planned %',data:state.tasks.slice(0,10).map(t=>Math.min(100,Math.max(0,Math.round((new Date(TODAY)-new Date(t.start))\/(new Date(t.finish)-new Date(t.start))*100)||0)))},{label:'Actual %',data:state.tasks.slice(0,10).map(t=>t.progress)}]},{scales:{y:{beginAtZero:true,max:100}}});\r\n chart('pmis-budget-chart','bar',{labels:['Approved','Planned','Actual'],datasets:[{label:'Cost',data:[state.project.budget,m.planned,m.actual]}]},{scales:{y:{beginAtZero:true}}});\r\n const pc={Critical:0,High:0,Medium:0,Low:0};state.tasks.forEach(t=>pc[t.priority]=(pc[t.priority]||0)+1);\r\n chart('pmis-priority-chart','pie',{labels:Object.keys(pc),datasets:[{data:Object.values(pc)}]});\r\n const upcoming=[...state.tasks.filter(t=>t.finish>=TODAY).sort((a,b)=>a.finish.localeCompare(b.finish)).slice(0,4),...state.activities.filter(a=>a.targetDate>=TODAY&&a.status!=='Completed').sort((a,b)=>a.targetDate.localeCompare(b.targetDate)).slice(0,4),...state.milestones.filter(m=>m.planned>=TODAY).sort((a,b)=>a.planned.localeCompare(b.planned)).slice(0,3)];\r\n $('pmis-upcoming').innerHTML='<div class=\"pmis-list\">'+(upcoming.length?upcoming.map(x=>`<div class=\"pmis-list-item\"><b>${esc(x.name)}<\/b><small>${x.finish||x.planned} \u2022 ${x.owner||''}<\/small><\/div>`).join(''):'<div class=\"pmis-list-item\">No upcoming items.<\/div>')+'<\/div>';\r\n const attention=[];state.tasks.filter(t=>t.status==='Delayed'||(t.finish<TODAY&&t.progress<100)).slice(0,5).forEach(t=>attention.push(`Delayed: ${t.name}`));state.risks.filter(r=>(+r.probability)*(+r.impact)>=15&&r.status!=='Closed').slice(0,5).forEach(r=>attention.push(`High risk: ${r.description}`));\r\n $('pmis-attention').innerHTML='<div class=\"pmis-list\">'+(attention.length?attention.map(x=>`<div class=\"pmis-list-item\"><b>${esc(x)}<\/b><\/div>`).join(''):'<div class=\"pmis-list-item\">No critical attention items.<\/div>')+'<\/div>';\r\n}\r\nfunction renderGantt(){\r\n const tasks=state.tasks.filter(t=>t.start&&t.finish).sort((a,b)=>a.start.localeCompare(b.start));\r\n if(!tasks.length){$('pmis-gantt').innerHTML='<div style=\"padding:30px\">Add tasks with start and finish dates.<\/div>';return}\r\n const min=new Date(Math.min(...tasks.map(t=>new Date(t.start)))),max=new Date(Math.max(...tasks.map(t=>new Date(t.finish)))),days=daysBetween(min,max),dayW=state.settings.ganttDay||24;\r\n let head='<div class=\"pmis-gantt-head\"><div class=\"pmis-gantt-name\"><b>Task<\/b><\/div><div class=\"pmis-gantt-days\">';\r\n for(let i=0;i<days;i++){const d=new Date(min);d.setDate(d.getDate()+i);head+=`<div class=\"pmis-gantt-day\">${d.getDate()}<br>${d.toLocaleString(undefined,{month:'short'})}<\/div>`}head+='<\/div><\/div>';\r\n let rows=tasks.map(t=>{const left=Math.round((new Date(t.start)-min)\/86400000)*dayW,width=taskDuration(t)*dayW;return `<div class=\"pmis-gantt-row\"><div class=\"pmis-gantt-name\">${esc(t.wbs)} ${esc(t.name)}<\/div><div class=\"pmis-gantt-track\" style=\"--gantt-day:${dayW}px;width:${days*dayW}px\"><div class=\"pmis-gantt-bar\" style=\"left:${left}px;width:${Math.max(width,dayW)}px\">${esc(t.name)}<div class=\"pmis-gantt-progress\" style=\"width:${t.progress}%\"><\/div><\/div><\/div><\/div>`}).join('');\r\n $('pmis-gantt').innerHTML=`<div class=\"pmis-gantt-grid\" style=\"--gantt-day:${dayW}px\">${head}${rows}<\/div>`;\r\n}\r\nfunction renderAll(){renderTasks();renderActivities();renderResources();renderMilestones();renderRisks();renderBudget();renderDashboard();renderGantt()}\r\nfunction openModal(type,index=null){\r\n editing={type,index};$('pmis-modal').hidden=false;\r\n const isEdit=index!==null,obj=isEdit?state[type][index]:{};\r\n $('pmis-modal-title').textContent=(isEdit?'Edit ':'Add ')+({tasks:'Task',activities:'Activity',resources:'Resource',milestones:'Milestone',risks:'Risk \/ Issue',budgetItems:'Cost Item'}[type]);\r\n let h='';\r\n if(type==='tasks')h=field('m-wbs','WBS',obj.wbs||`${state.tasks.length+1}.0`)+field('m-name','Task Name',obj.name||'')+field('m-owner','Owner',obj.owner||'')+field('m-start','Start Date',obj.start||TODAY,'date')+field('m-finish','Finish Date',obj.finish||addDays(TODAY,1),'date')+field('m-pred','Predecessor IDs',obj.pred||'')+selectF('m-priority','Priority',['Critical','High','Medium','Low'],obj.priority||'Medium')+selectF('m-status','Status',['Not Started','In Progress','Completed','On Hold','Delayed'],obj.status||'Not Started')+field('m-progress','% Complete',obj.progress||0,'number')+field('m-planned','Planned Cost',obj.planned||0,'number')+field('m-actual','Actual Cost',obj.actual||0,'number');\r\n\r\n if(type==='activities')h=\r\n   field('m-date','Activity Date',obj.date||TODAY,'date')+\r\n   textareaF('m-activity','Activity Description',obj.activity||'')+\r\n   field('m-task','Related Task \/ WBS',obj.task||'')+\r\n   field('m-owner','Responsible Person',obj.owner||'')+\r\n   field('m-location','Location \/ Department',obj.location||'')+\r\n   selectF('m-status','Status',['Planned','In Progress','Completed','On Hold','Delayed'],obj.status||'Planned')+\r\n   field('m-progress','% Progress',obj.progress||0,'number')+\r\n   textareaF('m-nextAction','Next Action \/ Follow-up',obj.nextAction||'')+\r\n   field('m-targetDate','Target Date',obj.targetDate||addDays(TODAY,1),'date')+\r\n   textareaF('m-remarks','Remarks \/ Update',obj.remarks||'');\r\n if(type==='resources')h=field('m-name','Resource Name',obj.name||'')+field('m-role','Role',obj.role||'')+field('m-department','Department',obj.department||'')+field('m-capacity','Capacity Hours',obj.capacity||0,'number')+field('m-allocated','Allocated Hours',obj.allocated||0,'number')+field('m-rate','Rate per Hour',obj.rate||0,'number');\r\n if(type==='milestones')h=field('m-name','Milestone',obj.name||'')+field('m-plannedDate','Planned Date',obj.planned||TODAY,'date')+field('m-actualDate','Actual Date',obj.actual||'','date')+field('m-owner','Owner',obj.owner||'')+selectF('m-status','Status',['Not Started','In Progress','Completed','Delayed'],obj.status||'Not Started')+textareaF('m-remarks','Remarks',obj.remarks||'');\r\n if(type==='risks')h=field('m-id','Risk ID',obj.id||`R-${state.risks.length+1}`)+selectF('m-type','Type',['Risk','Issue'],obj.type||'Risk')+textareaF('m-description','Description',obj.description||'')+selectF('m-probability','Probability',['1','2','3','4','5'],String(obj.probability||3))+selectF('m-impact','Impact',['1','2','3','4','5'],String(obj.impact||3))+field('m-owner','Owner',obj.owner||'')+textareaF('m-action','Mitigation \/ Action',obj.action||'')+selectF('m-status','Status',['Open','Monitoring','Mitigated','Closed'],obj.status||'Open');\r\n if(type==='budgetItems')h=field('m-category','Category',obj.category||'')+field('m-description','Description',obj.description||'')+field('m-planned','Planned Cost',obj.planned||0,'number')+field('m-committed','Committed Cost',obj.committed||0,'number')+field('m-actual','Actual Cost',obj.actual||0,'number')+field('m-owner','Vendor \/ Owner',obj.owner||'');\r\n $('pmis-modal-form').innerHTML=h;\r\n}\r\nfunction field(id,label,value='',type='text'){return `<label>${label}<input id=\"${id}\" type=\"${type}\" value=\"${esc(value)}\"><\/label>`}\r\nfunction textareaF(id,label,value=''){return `<label class=\"pmis-span-2\">${label}<textarea id=\"${id}\">${esc(value)}<\/textarea><\/label>`}\r\nfunction selectF(id,label,options,value){return `<label>${label}<select id=\"${id}\">${options.map(x=>`<option ${String(x)===String(value)?'selected':''}>${x}<\/option>`).join('')}<\/select><\/label>`}\r\nfunction saveModal(){\r\n const {type,index}=editing;let obj={};\r\n if(type==='tasks')obj={id:index!==null?state.tasks[index].id:Math.max(0,...state.tasks.map(t=>+t.id||0))+1,wbs:$('m-wbs').value,name:$('m-name').value,owner:$('m-owner').value,start:$('m-start').value,finish:$('m-finish').value,pred:$('m-pred').value,priority:$('m-priority').value,status:$('m-status').value,progress:Math.min(100,Math.max(0,+$('m-progress').value||0)),planned:+$('m-planned').value||0,actual:+$('m-actual').value||0};\r\n\r\n if(type==='activities')obj={\r\n   id:index!==null?state.activities[index].id:Math.max(0,...state.activities.map(a=>+a.id||0))+1,\r\n   date:$('m-date').value,\r\n   activity:$('m-activity').value,\r\n   task:$('m-task').value,\r\n   owner:$('m-owner').value,\r\n   location:$('m-location').value,\r\n   status:$('m-status').value,\r\n   progress:Math.min(100,Math.max(0,+$('m-progress').value||0)),\r\n   nextAction:$('m-nextAction').value,\r\n   targetDate:$('m-targetDate').value,\r\n   remarks:$('m-remarks').value\r\n };\r\n if(type==='resources')obj={name:$('m-name').value,role:$('m-role').value,department:$('m-department').value,capacity:+$('m-capacity').value||0,allocated:+$('m-allocated').value||0,rate:+$('m-rate').value||0};\r\n if(type==='milestones')obj={name:$('m-name').value,planned:$('m-plannedDate').value,actual:$('m-actualDate').value,owner:$('m-owner').value,status:$('m-status').value,remarks:$('m-remarks').value};\r\n if(type==='risks')obj={id:$('m-id').value,type:$('m-type').value,description:$('m-description').value,probability:+$('m-probability').value,impact:+$('m-impact').value,owner:$('m-owner').value,action:$('m-action').value,status:$('m-status').value};\r\n if(type==='budgetItems')obj={category:$('m-category').value,description:$('m-description').value,planned:+$('m-planned').value||0,committed:+$('m-committed').value||0,actual:+$('m-actual').value||0,owner:$('m-owner').value};\r\n if(index===null)state[type].push(obj);else state[type][index]=obj;\r\n $('pmis-modal').hidden=true;renderAll();save();\r\n}\r\nfunction deleteItem(type,index){if(confirm('Delete this record?')){state[type].splice(index,1);renderAll();save()}}\r\nfunction exportExcel(){\r\n const wb=XLSX.utils.book_new();\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet(state.tasks),'Tasks');\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet(state.activities),'Activities');\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet(state.resources),'Resources');\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet(state.milestones),'Milestones');\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet(state.risks),'Risks');\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet(state.budgetItems),'Budget');\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet([state.project]),'Project');\r\n downloadBlob(new Blob([XLSX.write(wb,{bookType:'xlsx',type:'array'})]),`${state.project.code||'project'}-MIS.xlsx`);\r\n}\r\nasync function importExcel(file){\r\n try{const wb=XLSX.read(await file.arrayBuffer(),{type:'array',cellDates:true});const sn=wb.SheetNames[0],rows=XLSX.utils.sheet_to_json(wb.Sheets[sn],{defval:''});state.tasks=rows.map((r,i)=>({id:+r.id||i+1,wbs:r.wbs||r.WBS||`${i+1}.0`,name:r.name||r['Task Name']||'',owner:r.owner||r.Owner||'',start:dateVal(r.start||r.Start),finish:dateVal(r.finish||r.Finish),pred:r.pred||r.Predecessor||'',priority:r.priority||r.Priority||'Medium',status:r.status||r.Status||'Not Started',progress:+(r.progress??r['% Complete'])||0,planned:+(r.planned??r['Planned Cost'])||0,actual:+(r.actual??r['Actual Cost'])||0}));renderAll();save()}catch(e){showAlert('Unable to import the selected Excel file.')}\r\n}\r\nfunction dateVal(v){if(!v)return TODAY;if(v instanceof Date)return v.toISOString().slice(0,10);const d=new Date(v);return isNaN(d)?TODAY:d.toISOString().slice(0,10)}\r\nfunction generateReport(type){\r\n readProjectForm();const m=calcMetrics(),p=state.project;\r\n let body=`<h1>${esc(p.name)} \u2014 ${esc(type)} Report<\/h1><p><b>Project Code:<\/b> ${esc(p.code)} &nbsp; <b>Manager:<\/b> ${esc(p.manager)} &nbsp; <b>Status:<\/b> ${esc(p.status)}<\/p><p><b>Reporting Date:<\/b> ${TODAY}<\/p>`;\r\n const table=(heads,rows)=>`<table><thead><tr>${heads.map(h=>`<th>${esc(h)}<\/th>`).join('')}<\/tr><\/thead><tbody>${rows.map(r=>`<tr>${r.map(c=>`<td>${esc(c)}<\/td>`).join('')}<\/tr>`).join('')}<\/tbody><\/table>`;\r\n if(type==='summary'||type==='full')body+=`<h2>Executive Summary<\/h2><div class=\"kpis\"><div><b>${m.total}<\/b><span>Total Tasks<\/span><\/div><div><b>${m.completed}<\/b><span>Completed<\/span><\/div><div><b>${m.avg}%<\/b><span>Progress<\/span><\/div><div><b>${m.delayed}<\/b><span>Delayed<\/span><\/div><div><b>${m.highRisks}<\/b><span>High Risks<\/span><\/div><div><b>${money(state.project.budget-m.actual)}<\/b><span>Budget Balance<\/span><\/div><\/div><h3>Objective<\/h3><p>${esc(p.objective)}<\/p><h3>Management Remarks<\/h3><p>${esc(p.remarks)}<\/p>`;\r\n if(type==='task'||type==='full')body+=`<h2>Task Status<\/h2>${table(['ID','WBS','Task','Owner','Start','Finish','Status','% Complete'],state.tasks.map(t=>[t.id,t.wbs,t.name,t.owner,t.start,t.finish,t.status,t.progress]))}`;\r\n if(type==='activity'||type==='full')body+=`<h2>Activity Register<\/h2>${table(['ID','Date','Activity','Related Task','Owner','Location','Status','Progress %','Next Action','Target Date','Remarks'],state.activities.map(a=>[a.id,a.date,a.activity,a.task,a.owner,a.location,a.status,a.progress,a.nextAction,a.targetDate,a.remarks]))}`;\r\n if(type==='delay'||type==='full')body+=`<h2>Delayed \/ Overdue Tasks<\/h2>${table(['Task','Owner','Finish','Progress','Status'],state.tasks.filter(t=>t.status==='Delayed'||(t.finish<TODAY&&t.progress<100)).map(t=>[t.name,t.owner,t.finish,t.progress,t.status]))}`;\r\n if(type==='resource'||type==='full')body+=`<h2>Resource Utilization<\/h2>${table(['Resource','Role','Capacity','Allocated','Utilization %'],state.resources.map(r=>[r.name,r.role,r.capacity,r.allocated,r.capacity?Math.round(r.allocated\/r.capacity*100):0]))}`;\r\n if(type==='risk'||type==='full')body+=`<h2>Risk Register<\/h2>${table(['ID','Type','Description','Score','Owner','Action','Status'],state.risks.map(r=>[r.id,r.type,r.description,r.probability*r.impact,r.owner,r.action,r.status]))}`;\r\n if(type==='budget'||type==='full')body+=`<h2>Budget Variance<\/h2>${table(['Category','Description','Planned','Committed','Actual','Variance'],state.budgetItems.map(b=>[b.category,b.description,b.planned,b.committed,b.actual,(+b.planned||0)-(+b.actual||0)]))}`;\r\n if(type==='milestone'||type==='full')body+=`<h2>Milestones<\/h2>${table(['Milestone','Planned','Actual','Owner','Status','Remarks'],state.milestones.map(m=>[m.name,m.planned,m.actual,m.owner,m.status,m.remarks]))}`;\r\n currentReportHtml=`<!doctype html><html><head><meta charset=\"utf-8\"><title>${esc(p.name)} MIS<\/title><style>body{font-family:Arial;padding:30px;color:#172033}h1{color:#1d4ed8}.kpis{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.kpis div{border:1px solid #ddd;padding:14px;border-radius:8px}.kpis b{display:block;font-size:24px}.kpis span{color:#666}table{border-collapse:collapse;width:100%;margin:12px 0 24px}th,td{border:1px solid #ccc;padding:7px;text-align:left;font-size:12px}th{background:#eef3f8}@media print{body{padding:0}}<\/style><\/head><body>${body}<\/body><\/html>`;\r\n $('pmis-report-preview').innerHTML=body;$('pmis-download-report-html').disabled=false;$('pmis-print-report').disabled=false;\r\n}\r\ndocument.addEventListener('click',e=>{\r\n const b=e.target.closest('button');\r\n if(!b)return;\r\n if(b.dataset.editTask!==undefined)openModal('tasks',+b.dataset.editTask);\r\n if(b.dataset.delTask!==undefined)deleteItem('tasks',+b.dataset.delTask);\r\n if(b.dataset.editActivity!==undefined)openModal('activities',+b.dataset.editActivity);\r\n if(b.dataset.delActivity!==undefined)deleteItem('activities',+b.dataset.delActivity);\r\n ['resource','milestone','risk','budget'].forEach(x=>{if(b.dataset['edit'+x[0].toUpperCase()+x.slice(1)]!==undefined)openModal(x==='budget'?'budgetItems':x+'s',+b.dataset['edit'+x[0].toUpperCase()+x.slice(1)]);if(b.dataset['del'+x[0].toUpperCase()+x.slice(1)]!==undefined)deleteItem(x==='budget'?'budgetItems':x+'s',+b.dataset['del'+x[0].toUpperCase()+x.slice(1)])});\r\n if(b.dataset.report)generateReport(b.dataset.report);\r\n});\r\n$('pmis-tabs').onclick=e=>{const b=e.target.closest('button');if(b)activateTab(b.dataset.tab)};\r\n$('pmis-add-task').onclick=()=>openModal('tasks');$('pmis-add-activity').onclick=()=>openModal('activities');$('pmis-add-resource').onclick=()=>openModal('resources');$('pmis-add-milestone').onclick=()=>openModal('milestones');$('pmis-add-risk').onclick=()=>openModal('risks');$('pmis-add-budget').onclick=()=>openModal('budgetItems');\r\n$('pmis-modal-close').onclick=$('pmis-modal-cancel').onclick=()=>$('pmis-modal').hidden=true;\r\n$('pmis-modal').addEventListener('click',e=>{if(e.target===$('pmis-modal'))$('pmis-modal').hidden=true});$('pmis-modal-save').onclick=saveModal;\r\n$('pmis-save').onclick=save;$('pmis-refresh-dashboard').onclick=renderDashboard;\r\n$('pmis-task-search').oninput=renderTasks;\r\n$('pmis-activity-search').oninput=renderActivities;$('pmis-activity-status-filter').onchange=renderActivities;$('pmis-activity-date-filter').onchange=renderActivities;$('pmis-task-status-filter').onchange=renderTasks;$('pmis-task-priority-filter').onchange=renderTasks;\r\n$('pmis-gantt-zoom-in').onclick=()=>{state.settings.ganttDay=Math.min(60,(state.settings.ganttDay||24)+6);renderGantt()};$('pmis-gantt-zoom-out').onclick=()=>{state.settings.ganttDay=Math.max(10,(state.settings.ganttDay||24)-6);renderGantt()};\r\n\r\n$('pmis-export-activities').onclick=()=>{\r\n const wb=XLSX.utils.book_new();\r\n XLSX.utils.book_append_sheet(wb,XLSX.utils.json_to_sheet(state.activities),'Activities');\r\n downloadBlob(new Blob([XLSX.write(wb,{bookType:'xlsx',type:'array'})]),`${state.project.code||'project'}-activities.xlsx`);\r\n};\r\n\r\n$('pmis-export-excel').onclick=exportExcel;$('pmis-import-excel').onchange=e=>e.target.files[0]&&importExcel(e.target.files[0]);\r\n$('pmis-export-json').onclick=()=>{save();downloadBlob(new Blob([JSON.stringify(state,null,2)],{type:'application\/json'}),`${state.project.code||'project'}-backup.json`)};\r\n$('pmis-import-json').onchange=async e=>{try{state=JSON.parse(await e.target.files[0].text());populateProjectForm();renderAll();save()}catch(x){showAlert('Invalid backup file.')}};\r\n$('pmis-download-report-html').onclick=()=>downloadBlob(new Blob([currentReportHtml],{type:'text\/html'}),`${state.project.code||'project'}-MIS-report.html`);\r\n$('pmis-print-report').onclick=()=>{const w=window.open('','_blank');w.document.write(currentReportHtml);w.document.close();setTimeout(()=>w.print(),300)};\r\n$('pmis-theme').onclick=()=>{app.classList.toggle('dark');localStorage.setItem('pmis-theme',app.classList.contains('dark')?'dark':'light')};\r\nif(localStorage.getItem('pmis-theme')==='dark'||(!localStorage.getItem('pmis-theme')&&matchMedia('(prefers-color-scheme:dark)').matches))app.classList.add('dark');\r\nload();\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\n<\/div>\n\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>PM Project Management &#038; MIS StudioPlan \u2022 Track \u2022 Control \u2022 Report \u25d0 Save Backup Restore Browser-Based Project Management Complete Project Planning, Tracking &#038; MIS Dashboard Manage tasks, dependencies, milestones, resources, risks, budgets and progress in one professional workspace. Dashboard Project Details Task Planner Activity Register Gantt Chart Resources Milestones Risks &#038; Issues Budget MIS [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"footnotes":""},"class_list":["post-712","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/pages\/712","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/comments?post=712"}],"version-history":[{"count":4,"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/pages\/712\/revisions"}],"predecessor-version":[{"id":716,"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/pages\/712\/revisions\/716"}],"wp:attachment":[{"href":"https:\/\/vikassrivastava.in\/academy\/wp-json\/wp\/v2\/media?parent=712"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}