27 lines
12 KiB
HTML
27 lines
12 KiB
HTML
|
|
{% extends "shared/frontend/base.html" %}
|
||
|
|
{% block title %}Planlægger · BMC Hub{% endblock %}
|
||
|
|
{% block extra_css %}
|
||
|
|
<style>
|
||
|
|
.planner-page{--p-blue:#0f4c75;--p-line:#dce4ea;--p-muted:#667085;max-width:1900px;margin:auto;padding:1rem}.planner-head{display:flex;justify-content:space-between;gap:1rem;align-items:center;margin-bottom:1rem}.planner-head h1{font-size:1.65rem;margin:0}.planner-toolbar,.planner-toggle{display:flex;align-items:center;gap:.45rem;flex-wrap:wrap}.planner-toggle{background:var(--bg-card);border:1px solid var(--p-line);border-radius:10px;padding:.2rem}.planner-toggle button,.planner-toolbar button{border:0;background:transparent;border-radius:8px;padding:.45rem .75rem}.planner-toggle button.active{background:var(--p-blue);color:#fff}.planner-layout{display:grid;grid-template-columns:minmax(285px,340px) minmax(700px,1fr);gap:1rem;min-height:720px}.case-panel,.calendar-panel{background:var(--bg-card);border:1px solid var(--p-line);border-radius:14px;box-shadow:0 3px 14px rgba(15,76,117,.07);overflow:hidden}.case-panel{display:flex;flex-direction:column}.panel-title{padding:1rem;border-bottom:1px solid var(--p-line)}.case-search{position:relative}.case-search input{width:100%;border:1px solid var(--p-line);border-radius:9px;padding:.65rem 2rem .65rem .75rem}.filter-row{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;margin-top:.65rem}.filter-row select{min-width:0;border:1px solid var(--p-line);border-radius:8px;padding:.5rem;background:var(--bg-card);color:var(--text-primary)}.quick-filters{display:flex;gap:.35rem;overflow:auto;margin-top:.6rem}.quick-filters button{white-space:nowrap;border:1px solid var(--p-line);background:transparent;border-radius:999px;padding:.3rem .55rem;font-size:.77rem}.quick-filters button.active{background:#e7f0f5;color:var(--p-blue);border-color:#9db9c9}.case-list{overflow:auto;padding:.7rem;display:flex;flex-direction:column;gap:.55rem}.case-card{border:1px solid var(--p-line);border-left:4px solid #8b98a5;border-radius:10px;padding:.68rem;background:var(--bg-card);cursor:grab}.case-card[data-priority=urgent]{border-left-color:#d92d20}.case-card[data-priority=high]{border-left-color:#f79009}.case-card strong{font-size:.9rem}.case-card .customer{color:var(--p-muted);font-size:.78rem}.case-card .case-meta{display:flex;justify-content:space-between;gap:.4rem;margin-top:.45rem;font-size:.74rem}.progress{height:4px;margin-top:.45rem}.calendar-panel{display:flex;flex-direction:column}.calendar-top{padding:.75rem 1rem;border-bottom:1px solid var(--p-line);display:flex;justify-content:space-between;align-items:center;gap:1rem}.period-label{font-size:1.05rem;font-weight:650}.capacity-legend{font-size:.73rem;color:var(--p-muted);display:flex;gap:.7rem}.dot{width:9px;height:9px;display:inline-block;border-radius:50%;margin-right:.2rem}.green{background:#12b76a}.yellow{background:#fdb022}.red{background:#f04438}.gray{background:#98a2b3}.timeline{overflow:auto;flex:1;position:relative}.week-grid{display:grid;min-width:900px}.grid-cell{border-right:1px solid var(--p-line);border-bottom:1px solid var(--p-line);min-height:108px;position:relative;padding:.35rem}.grid-head{position:sticky;top:0;z-index:5;background:var(--bg-card);min-height:auto;padding:.55rem;text-align:center;font-size:.78rem}.employee-head{position:sticky;left:0;z-index:4;background:var(--bg-card);font-weight:600}.grid-head.employee-head{z-index:7}.capacity-pill{display:inline-flex;align-items:center;border-radius:999px;padding:.15rem .38rem;font-size:.68rem;background:#f2f4f7;margin-top:.2rem}.drop-cell{height:660px;padding:0;background:repeating-linear-gradient(to bottom,transparent 0,transparent 59px,var(--p-line) 59px,var(--p-line) 60px)}.drop-cell .capacity-pill{position:sticky;top:4px;left:4px;z-index:3}.hour-mark{position:absolute;left:2px;color:#98a2b3;font-size:.6rem;transform:translateY(-50%);pointer-events:none}.allocation{border-radius:7px;background:#dbeafe;border-left:3px solid #2563eb;padding:.25rem .35rem;font-size:.72rem;cursor:move;overflow:hidden}.drop-cell .allocation,.drop-cell .external-busy{position:absolute;left:26px;right:3px;z-index:2;margin:0}.allocation.locked{border-left-color:#475467;background:#e4e7ec;cursor
|
||
|
|
.registered-time{position:absolute;left:30px;right:7px;z-index:1;border-radius:7px;background:#dcfae6;border-left:3px solid #079455;padding:.25rem .35rem;font-size:.7rem;overflow:hidden;pointer-events:none}.registered-time .time{font-weight:650;color:#067647}
|
||
|
|
.untimed-registers{position:absolute;left:28px;right:4px;bottom:4px;z-index:4;display:flex;flex-wrap:wrap;gap:4px;pointer-events:none}.untimed-register{max-width:100%;border:1px solid #75e0a7;border-left:3px solid #079455;border-radius:6px;background:#ecfdf3;color:#05603a;padding:3px 7px;font-size:.68rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
|
|
.planner-page{width:100%;max-width:2200px;padding:.75rem}.planner-head{margin-bottom:.75rem}.planner-layout{grid-template-columns:minmax(340px,400px) minmax(0,1fr);gap:.75rem;min-height:calc(100vh - 185px)}.calendar-panel{min-width:0}.panel-title{padding:.8rem}.case-list{padding:.6rem;gap:.5rem}.case-card{padding:.68rem}.case-card strong{display:block;line-height:1.3;overflow-wrap:anywhere}.case-card .customer{margin-top:.18rem}.week-grid{min-width:840px}
|
||
|
|
@media(max-width:1050px){.planner-layout{grid-template-columns:1fr}.case-panel{max-height:390px}.case-panel.collapsed .panel-title>:not(.panel-heading),.case-panel.collapsed .case-list{display:none}.case-panel.collapsed{max-height:58px}.collapse-cases{display:inline-block!important}}.collapse-cases{display:none;border:0;background:transparent}
|
||
|
|
</style>
|
||
|
|
{% endblock %}
|
||
|
|
{% block content %}
|
||
|
|
<main class="planner-page" data-current-user="{{ current_user.id }}">
|
||
|
|
<header class="planner-head"><div><h1><i class="bi bi-calendar2-week me-2"></i>Planlægger</h1><small class="text-muted">Fordel sager og følg teamets kapacitet</small></div>
|
||
|
|
<div class="planner-toolbar"><div class="planner-toggle" id="scopeToggle"><button data-scope="mine" class="active">Min plan</button><button data-scope="team">Team</button></div><div class="planner-toggle" id="viewToggle"><button data-view="day">Dag</button><button data-view="week" class="active">Uge</button><button data-view="month">Måned</button></div></div>
|
||
|
|
</header>
|
||
|
|
<section class="planner-layout">
|
||
|
|
<aside class="case-panel" id="casePanel"><div class="panel-title"><div class="panel-heading d-flex justify-content-between"><strong>Sager til planlægning</strong><button class="collapse-cases" aria-label="Fold sagsliste"><i class="bi bi-chevron-up"></i></button></div><div class="case-search mt-2"><input id="caseSearch" placeholder="Sagsnr., kunde, titel eller ansvarlig…"><i class="bi bi-search position-absolute end-0 me-2 mt-2 text-muted"></i></div><div class="filter-row"><select id="statusFilter"><option value="">Alle statusser</option><option>åben</option><option>i_gang</option><option>on_hold</option></select><select id="priorityFilter"><option value="">Alle prioriteter</option><option value="urgent">Haster</option><option value="high">Høj</option><option value="normal">Normal</option><option value="low">Lav</option></select><select id="typeFilter"><option value="">Alle sagstyper</option></select><select id="responsibleFilter"><option value="">Alle ansvarlige</option></select><select id="departmentFilter"><option value="">Alle afdelinger</option></select><select id="sortFilter"><option value="priority">Prioritet</option><option value="remaining">Resterende tid</option><option value="updated">Senest ændret</option></select></div><div class="quick-filters"><button data-quick="unplanned" class="active">Ikke planlagt</button><button data-quick="partial">Delvist planlagt</button><button data-quick="mine">Mine sager</button><button data-quick="urgent">Haster</button></div></div><div class="case-list" id="caseList"><div class="empty">Henter sager…</div></div></aside>
|
||
|
|
<section class="calendar-panel"><div class="calendar-top"><div class="planner-toolbar"><button id="prevPeriod" aria-label="Forrige"><i class="bi bi-chevron-left"></i></button><button id="todayBtn">I dag</button><button id="nextPeriod" aria-label="Næste"><i class="bi bi-chevron-right"></i></button><span class="period-label" id="periodLabel"></span></div><div class="capacity-legend"><span><i class="dot green"></i>Ledig</span><span><i class="dot yellow"></i>Næsten fuld</span><span><i class="dot red"></i>Fuld/overbooket</span><span><i class="dot gray"></i>Fri/fravær</span></div></div><div class="timeline" id="timeline"></div></section>
|
||
|
|
</section>
|
||
|
|
</main>
|
||
|
|
<dialog class="allocation-dialog" id="allocationDialog"><form method="dialog"><div class="dialog-body"><small id="dialogCustomer" class="text-muted"></small><h5 id="dialogTitle" class="mt-1"></h5><div class="row g-2 mt-2"><div class="col-6"><label class="form-label">Start</label><input id="dialogStart" type="datetime-local" class="form-control"></div><div class="col-6"><label class="form-label">Slut</label><input id="dialogEnd" type="datetime-local" class="form-control"></div><div class="col-12"><label class="form-label">Note</label><textarea id="dialogNote" class="form-control" rows="2"></textarea></div><div class="col-12"><label class="form-check"><input id="dialogLocked" type="checkbox" class="form-check-input"><span class="form-check-label"><i class="bi bi-lock me-1"></i>Fastlås tidspunkt</span></label><div class="form-text">Låste blokke kan ikke flyttes eller slettes, før låsen fjernes.</div></div></div><div id="dialogWarning" class="alert alert-warning mt-2 d-none"></div></div><div class="dialog-actions"><button value="cancel" class="btn btn-light">Luk</button><a id="dialogCaseLink" class="btn btn-outline-primary">Åbn sag</a><button type="button" id="deleteAllocation" class="btn btn-outline-danger">Slet</button><button type="button" id="copyAllocation" class="btn btn-outline-secondary">Kopiér</button><button type="button" id="saveAllocation" class="btn btn-primary">Gem</button></div></form></dialog>
|
||
|
|
<dialog class="allocation-dialog" id="timeDialog"><form method="dialog"><div class="dialog-body"><small class="text-muted">Faktisk registreret tid</small><h5 id="timeDialogTitle"></h5><div id="timeDialogTotal" class="mb-3 fw-semibold"></div><div id="timeEntryList" class="d-flex flex-column gap-2"></div></div><div class="dialog-actions"><button value="cancel" class="btn btn-light">Luk</button><a id="timeDialogCaseLink" class="btn btn-primary">Åbn sag</a></div></form></dialog>
|
||
|
|
<div class="toast-stack" id="toastStack"></div>
|
||
|
|
{% endblock %}
|
||
|
|
{% block extra_js %}<script src="/static/js/planner.js?v=5"></script>{% endblock %}
|