Dashboards done

This commit is contained in:
nugroho 2025-07-04 03:34:05 +07:00
parent 6b605f8883
commit 95d23a3239
5 changed files with 245 additions and 27 deletions

View File

@ -42,7 +42,7 @@
</div> </div>
<div style="display: grid; gap: 2ch; grid-template-columns: 1fr auto 1fr; padding: 1ch"> <div style="display: grid; gap: 2ch; grid-template-columns: 1fr auto 1fr; padding: 1ch">
<div class="card"> <div class="card">
<div class="numbers"> <div class="numbers" id="pacts">
0 0
</div> </div>
<div class="texts"> <div class="texts">
@ -51,17 +51,16 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="numbers" id="oacts">
<div class="numbers">
0 0
</div> </div>
<div class="texts"> <div class="texts">
Aksi<br> Sedang<br>
Berlangsung Berlangsung
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="numbers warn"> <div class="numbers warn" id="dacts">
0 0
</div> </div>
<div class="texts"> <div class="texts">
@ -80,7 +79,7 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="numbers good"> <div class="numbers good" id="eacts">
0 0
</div> </div>
<div class="texts"> <div class="texts">
@ -106,6 +105,110 @@
</div> </div>
</div> </div>
<script type="module"> <script type="module">
const Now = new Date();
let prokers = [];
async function getProkers()
{
const loadid = moly.loadScreen.show("Menyusun dasbor...","dots","#content");
const years = [];
const pro = await getJson("/api/getprokers");
if(pro.status != 200)
{
moly.loadScreen.close(loadid);
return;
}
prokers = pro.data.reduce((a,v)=>{
const aindex = a.findIndex(e=>e.prokerID == v.prokerID);
if(!years.includes(v.year))
{
years.push(v.year);
const opt = moly.newElement("option");
opt.value = v.year;
opt.append(v.year);
$('#pkYear').append(opt);
}
if(aindex >=0)
{
a[aindex].journal.push({
journalID: v.journalID,
submitterID: v.submitterID,
notes: v.notes,
status: v.status,
document: v.document,
timeStamp: v.timeStamp.replace("T"," ")
})
a[aindex].journal.sort((ja,jb)=>ja.journalID.localeCompare(jb.journalID));
}
else
{
const nv = JSON.parse(JSON.stringify(v));
nv.journal= [{
journalID: v.journalID,
submitterID: v.submitterID,
notes: v.notes,
status: v.status,
document: v.document,
timeStamp: v.timeStamp.replace("T"," ")
}]
const owner = agents.find(e=> e.agentID == v.ownerID)
if (owner)
{
nv.owner = owner
delete nv.ownerID
}
delete nv.journalID;
delete nv.submitterID;
delete nv.notes;
delete nv.status;
delete nv.document;
delete nv.timeStamp;
a.push(nv);
}
return a;
},[]);
prokers = prokers.filter(p=>p.owner);
const currProkers = prokers.filter(p=>p.year == Now.getFullYear());
const ongoingProkers = currProkers.filter(p=>p.journal.at(-1).status == 3);
const doneProkers = currProkers.filter(p=>p.journal.at(-1).status == 4);
const evaledProkers = currProkers.filter(p=>p.journal.at(-1).status == 8);
µ('#pacts').text(currProkers.length);
µ('#oacts').text(ongoingProkers.length);
µ('#dacts').text(doneProkers.length);
µ('#eacts').text(evaledProkers.length);
$.each(currProkers,(_,v)=>{
const donetime = new Date(v.journal.at(-1).timeStamp);
const lifeline = (v.isInMonth ? new Date(v.year, v.startMonth -1, 1) : new Date(v.year, v.startMonth -1, v.startDay)).setHours(0,0,0,0);
const deadline = new Date((v.isInMonth ? new Date(v.year, v.startMonth + v.timeTarget, 0) : new Date(v.year, v.startMonth -1, v.startDay + v.timeTarget)).setHours(23,59,59));
v.donetime = donetime;
});
const sortedProkers = [...currProkers].filter(r=>r.journal.at(-1).status == 4 || r.journal.at(-1).status == 8).sort((a,b)=>a.donetime - b.donetime);
const closest = sortedProkers.find(p=>p.journal.at(-1).status == 4);
µ('#udate').text(closest ? `${closest.donetime.getFullYear()}/${(closest.donetime.getMonth()+1).toString().padStart(2,"0")}/${closest.donetime.getDate().toString().padStart(2,"0")}` : "");
µ('#utext').text(closest ? (closest.owner.name +": "+closest.sasaran) : "");
const todayActs = sortedProkers.filter(p=>
{
const today = new Date();
today.setHours(0,0,0,0);
const ts = new Date(p.journal.at(-1).timeStamp)
ts.setHours(0,0,0,0);
return ts.getTime() == today.getTime();
}
)
if(todayActs.length>0) µ('#htoday').empty();
$.each(todayActs,(_,v)=>{
const d = moly.newElement("div");
const s = moly.newElement("span");
const t = moly.newElement("span");
d.append(s);
d.append(t);
s.append(v.journal.at(-1).status == 8 ? "Dievaluasi: " : "Belum Dievaluasi: ");
s.style.fontWeight = "600"
s.style.color = v.journal.at(-1).status == 8 ? "var(--positive-accent)" : "var(--neutral-n-accent)"
t.append((v.owner.name +": "+v.sasaran))
µ('#htoday').append(d);
});
moly.loadScreen.close(loadid);
}
function µ(selector) function µ(selector)
{ {
if (selector) return $('body>#main>#content').find(selector); if (selector) return $('body>#main>#content').find(selector);
@ -166,4 +269,5 @@
} }
} }
buildCalendar(); buildCalendar();
await getProkers()
</script> </script>

View File

@ -42,7 +42,7 @@
</div> </div>
<div style="display: grid; gap: 2ch; grid-template-columns: 1fr auto 1fr; padding: 1ch"> <div style="display: grid; gap: 2ch; grid-template-columns: 1fr auto 1fr; padding: 1ch">
<div class="card"> <div class="card">
<div class="numbers"> <div class="numbers" id="pacts">
0 0
</div> </div>
<div class="texts"> <div class="texts">
@ -51,22 +51,21 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="numbers" id="dacts">
<div class="numbers">
0 0
</div> </div>
<div class="texts"> <div class="texts">
Aksi<br> Aksi<br>
Berlangsung dalam Draf
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="numbers warn"> <div class="numbers warn" id="oacts">
0 0
</div> </div>
<div class="texts"> <div class="texts">
Menunggu<br> Pengajuan<br>
Respons Menunggu Respons
</div> </div>
</div> </div>
<div style="grid-column: span 2;" class="ecard"> <div style="grid-column: span 2;" class="ecard">
@ -80,11 +79,11 @@
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<div class="numbers good"> <div class="numbers good" id="racts">
0 0
</div> </div>
<div class="texts"> <div class="texts">
Telah<br> Pengajuan<br>
Direspons Direspons
</div> </div>
</div> </div>
@ -106,6 +105,110 @@
</div> </div>
</div> </div>
<script type="module"> <script type="module">
const Now = new Date();
let prokers = [];
async function getProkers()
{
const loadid = moly.loadScreen.show("Menyusun dasbor...","dots","#content");
const years = [];
const pro = await getJson("/api/getprokers");
if(pro.status != 200)
{
moly.loadScreen.close(loadid);
return;
}
prokers = pro.data.reduce((a,v)=>{
const aindex = a.findIndex(e=>e.prokerID == v.prokerID);
if(!years.includes(v.year))
{
years.push(v.year);
const opt = moly.newElement("option");
opt.value = v.year;
opt.append(v.year);
$('#pkYear').append(opt);
}
if(aindex >=0)
{
a[aindex].journal.push({
journalID: v.journalID,
submitterID: v.submitterID,
notes: v.notes,
status: v.status,
document: v.document,
timeStamp: v.timeStamp.replace("T"," ")
})
a[aindex].journal.sort((ja,jb)=>ja.journalID.localeCompare(jb.journalID));
}
else
{
const nv = JSON.parse(JSON.stringify(v));
nv.journal= [{
journalID: v.journalID,
submitterID: v.submitterID,
notes: v.notes,
status: v.status,
document: v.document,
timeStamp: v.timeStamp.replace("T"," ")
}]
const owner = agents.find(e=> e.agentID == v.ownerID)
if (owner)
{
nv.owner = owner
delete nv.ownerID
}
delete nv.journalID;
delete nv.submitterID;
delete nv.notes;
delete nv.status;
delete nv.document;
delete nv.timeStamp;
a.push(nv);
}
return a;
},[]);
prokers = prokers.filter(p=>p.owner);
const currProkers = prokers.filter(p=>p.year == Now.getFullYear());
const draftProkers = currProkers.filter(p=>p.journal.at(-1).status == 0);
const propProkers = currProkers.filter(p=>p.journal.at(-1).status == 2);
const respProkers = currProkers.filter(p=>p.journal.at(-1).status == 1 || p.journal.at(-1).status >= 3);
µ('#pacts').text(currProkers.length);
µ('#dacts').text(draftProkers.length);
µ('#oacts').text(propProkers.length);
µ('#racts').text(respProkers.length);
$.each(currProkers,(_,v)=>{
const doneline = new Date(v.journal.at(-1).timeStamp);
const lifeline = (v.isInMonth ? new Date(v.year, v.startMonth -1, 1) : new Date(v.year, v.startMonth -1, v.startDay)).setHours(0,0,0,0);
const deadline = new Date((v.isInMonth ? new Date(v.year, v.startMonth + v.timeTarget, 0) : new Date(v.year, v.startMonth -1, v.startDay + v.timeTarget)).setHours(23,59,59));
v.deadline = deadline;
});
const sortedProkers = [...currProkers].filter(r=>r.journal.at(-1).status >= 1 && r.journal.at(-1).status <=3 ).sort((a,b)=>a.deadline - b.deadline);
const closest = sortedProkers.find(p=>p.journal.at(-1).status == 2);
µ('#udate').text(closest ? `${closest.deadline.getFullYear()}/${(closest.deadline.getMonth()+1).toString().padStart(2,"0")}/${closest.deadline.getDate().toString().padStart(2,"0")}` : "");
µ('#utext').text(closest ? closest.sasaran : "");
const todayActs = sortedProkers.filter(p=>
{
const today = new Date();
today.setHours(0,0,0,0);
const ts = new Date(p.journal.at(-1).timeStamp)
ts.setHours(0,0,0,0);
return ts.getTime() == today.getTime();
}
)
if(todayActs.length>0) µ('#htoday').empty();
$.each(todayActs,(_,v)=>{
const d = moly.newElement("div");
const s = moly.newElement("span");
const t = moly.newElement("span");
d.append(s);
d.append(t);
s.append(v.journal.at(-1).status == 1 ? `Ditolak: `: v.journal.at(-1).status == 2 ? `Diajukan: ` : `Disetujui: `);
s.style.fontWeight = "600"
s.style.color = v.journal.at(-1).status == 1 ? "var(--neutral-p-accent)": v.journal.at(-1).status == 2 ? "var(--neutral-n-accent)" : "var(--positive-accent)"
t.append(v.sasaran)
µ('#htoday').append(d);
});
moly.loadScreen.close(loadid);
}
function µ(selector) function µ(selector)
{ {
if (selector) return $('body>#main>#content').find(selector); if (selector) return $('body>#main>#content').find(selector);
@ -166,4 +269,5 @@
} }
} }
buildCalendar(); buildCalendar();
await getProkers()
</script> </script>

View File

@ -64,7 +64,7 @@
0 0
</div> </div>
<div class="texts"> <div class="texts">
Aksi<br> Sedang<br>
Berlangsung Berlangsung
</div> </div>
</div> </div>
@ -177,7 +177,7 @@
} }
return a; return a;
},[]); },[]);
window.currProkers = prokers.filter(p=>p.year == Now.getFullYear()); const currProkers = prokers.filter(p=>p.year == Now.getFullYear());
const ongoingProkers = currProkers.filter(p=>p.journal.at(-1).status == 3); const ongoingProkers = currProkers.filter(p=>p.journal.at(-1).status == 3);
const doneProkers = currProkers.filter(p=>p.journal.at(-1).status >= 4); const doneProkers = currProkers.filter(p=>p.journal.at(-1).status >= 4);
const evaledProkers = currProkers.filter(p=>p.journal.at(-1).status == 8); const evaledProkers = currProkers.filter(p=>p.journal.at(-1).status == 8);
@ -197,7 +197,7 @@
const closest = sortedProkers[0]; const closest = sortedProkers[0];
µ('#udate').text(closest ? `${closest.deadline.getFullYear()}/${(closest.deadline.getMonth()+1).toString().padStart(2,"0")}/${closest.deadline.getDate().toString().padStart(2,"0")}` : ""); µ('#udate').text(closest ? `${closest.deadline.getFullYear()}/${(closest.deadline.getMonth()+1).toString().padStart(2,"0")}/${closest.deadline.getDate().toString().padStart(2,"0")}` : "");
µ('#utext').text(closest ? closest.sasaran : ""); µ('#utext').text(closest ? closest.sasaran : "");
µ('#htoday').empty(); if(sortedProkers.length>0) µ('#htoday').empty();
$.each(sortedProkers,(_,v)=>{ $.each(sortedProkers,(_,v)=>{
const d = moly.newElement("div"); const d = moly.newElement("div");
const s = moly.newElement("span"); const s = moly.newElement("span");

View File

@ -96,7 +96,7 @@
] ]
async function populateProker(agentID) async function populateProker(agentID)
{ {
if(!agentID) return; if(!agentID) return false;
const loadid = moly.loadScreen.show("Memuat Daftar Program Kerja...","bar","#pkWrapper"); const loadid = moly.loadScreen.show("Memuat Daftar Program Kerja...","bar","#pkWrapper");
prokers = await getJson('/api/getprokers'); prokers = await getJson('/api/getprokers');
if (prokers.status != 200 || prokers.length < 1) if (prokers.status != 200 || prokers.length < 1)
@ -164,6 +164,7 @@
}) })
fillProker(); fillProker();
moly.loadScreen.close(loadid); moly.loadScreen.close(loadid);
return prokers.length > 0;
} }
function fillProker() function fillProker()
{ {
@ -239,7 +240,7 @@
{ {
const loadid = moly.loadScreen.show("Memuat data agen...","bar","#agWrapper"); const loadid = moly.loadScreen.show("Memuat data agen...","bar","#agWrapper");
$('#agContent').empty(); $('#agContent').empty();
$.each(agents,(i,v)=>{ $.each(agents.filter(a=>a.agentID != userDetails.info.agentID),(i,v)=>{
const ro = moly.newElement("tr"); const ro = moly.newElement("tr");
const no = moly.newElement("td"); const no = moly.newElement("td");
const ni = moly.newElement("td"); const ni = moly.newElement("td");
@ -252,11 +253,15 @@
ni.append(v.agentID); ni.append(v.agentID);
ni.style.textAlign = "center"; ni.style.textAlign = "center";
na.append(v.name); na.append(v.name);
$(ro).click(()=>{ $(ro).click(async()=>{
if (!await populateProker(v.agentID))
{
moly.alert.show("Program Kerja Kosong",`Agen ${v.name} tidak memiliki Program Kerja.`)
return;
}
$('#agGroup').prop("collapsed",true); $('#agGroup').prop("collapsed",true);
$('#pkGroup').prop("collapsed",false); $('#pkGroup').prop("collapsed",false);
$('#pkGroup').prop("disabled",false); $('#pkGroup').prop("disabled",false);
populateProker(v.agentID);
}); });
$('#agContent').append(ro); $('#agContent').append(ro);
}) })

View File

@ -94,7 +94,7 @@
] ]
async function populateProker(agentID) async function populateProker(agentID)
{ {
if(!agentID) return; if(!agentID) return false;
const loadid = moly.loadScreen.show("Memuat Daftar Program Kerja...","bar","#pkWrapper"); const loadid = moly.loadScreen.show("Memuat Daftar Program Kerja...","bar","#pkWrapper");
prokers = await getJson('/api/getprokers'); prokers = await getJson('/api/getprokers');
if (prokers.status != 200 || prokers.length < 1) if (prokers.status != 200 || prokers.length < 1)
@ -162,6 +162,7 @@
}) })
fillProker(); fillProker();
moly.loadScreen.close(loadid); moly.loadScreen.close(loadid);
return prokers.length > 0;
} }
function fillProker() function fillProker()
{ {
@ -230,7 +231,7 @@
{ {
const loadid = moly.loadScreen.show("Memuat data agen...","bar","#agWrapper"); const loadid = moly.loadScreen.show("Memuat data agen...","bar","#agWrapper");
$('#agContent').empty(); $('#agContent').empty();
$.each(agents,(i,v)=>{ $.each(agents.filter(a=>a.agentID != userDetails.info.agentID),(i,v)=>{
const ro = moly.newElement("tr"); const ro = moly.newElement("tr");
const no = moly.newElement("td"); const no = moly.newElement("td");
const ni = moly.newElement("td"); const ni = moly.newElement("td");
@ -243,11 +244,15 @@
ni.append(v.agentID); ni.append(v.agentID);
ni.style.textAlign = "center"; ni.style.textAlign = "center";
na.append(v.name); na.append(v.name);
$(ro).click(()=>{ $(ro).click(async ()=>{
if (!await populateProker(v.agentID))
{
moly.alert.show("Program Kerja Kosong",`Agen ${v.name} tidak memiliki Program Kerja.`)
return;
}
$('#agGroup').prop("collapsed",true); $('#agGroup').prop("collapsed",true);
$('#pkGroup').prop("collapsed",false); $('#pkGroup').prop("collapsed",false);
$('#pkGroup').prop("disabled",false); $('#pkGroup').prop("disabled",false);
populateProker(v.agentID);
}); });
$('#agContent').append(ro); $('#agContent').append(ro);
}) })