Update dashboard filters and packet views

This commit is contained in:
sas.fajri
2026-05-07 12:04:09 +07:00
parent da419950ce
commit 11f0d0436e
17 changed files with 1008 additions and 342 deletions

View File

@@ -9,6 +9,7 @@ import (
"log"
"net/http"
"strconv"
"strings"
"time"
)
@@ -26,8 +27,15 @@ type ArrivalsPartial struct {
}
type PatientsPartial struct {
Patients []PatientDetail
IsRange bool
Patients []PatientDetail
IsRange bool
Search string
ProgressStatus string
KpiFilter string
Page int
PageSize int
HasMore bool
NextPage int
}
type PageData struct {
@@ -237,12 +245,84 @@ func Patients(w http.ResponseWriter, r *http.Request) {
http.Error(w, "query error", http.StatusInternalServerError)
return
}
search := strings.TrimSpace(r.URL.Query().Get("search"))
progressStatus := strings.TrimSpace(r.URL.Query().Get("progress_status"))
kpiFilter := strings.TrimSpace(r.URL.Query().Get("kpi_filter"))
if kpiFilter != "" {
filteredByKPI := make([]PatientDetail, 0, len(patients))
for _, p := range patients {
switch kpiFilter {
case "invited":
filteredByKPI = append(filteredByKPI, p)
case "total_staff":
if p.InTime != "" {
filteredByKPI = append(filteredByKPI, p)
}
case "inprogress":
if p.InTime != "" && !p.HasOut {
filteredByKPI = append(filteredByKPI, p)
}
case "checkedout":
if p.HasOut {
filteredByKPI = append(filteredByKPI, p)
}
default:
filteredByKPI = append(filteredByKPI, p)
}
}
patients = filteredByKPI
}
if search != "" || progressStatus != "" {
lowerSearch := strings.ToLower(search)
filtered := make([]PatientDetail, 0, len(patients))
for _, p := range patients {
if progressStatus != "" && p.ProgressStatus != progressStatus {
continue
}
if lowerSearch != "" && !strings.Contains(strings.ToLower(p.Name), lowerSearch) && !strings.Contains(strconv.Itoa(p.ID), lowerSearch) {
continue
}
filtered = append(filtered, p)
}
patients = filtered
}
page := 1
if p, err := strconv.Atoi(strings.TrimSpace(r.URL.Query().Get("page"))); err == nil && p > 0 {
page = p
}
pageSize := 30
start := (page - 1) * pageSize
if start > len(patients) {
start = len(patients)
}
end := start + pageSize
if end > len(patients) {
end = len(patients)
}
pagedPatients := patients[start:end]
hasMore := end < len(patients)
data := PatientsPartial{
Patients: patients,
IsRange: mode != "daily" || dateFrom != dateTo,
Patients: pagedPatients,
IsRange: mode != "daily" || dateFrom != dateTo,
Search: search,
ProgressStatus: progressStatus,
KpiFilter: kpiFilter,
Page: page,
PageSize: pageSize,
HasMore: hasMore,
NextPage: page + 1,
}
t := parse("templates/dashboard/partials/patients.html")
if err := t.ExecuteTemplate(w, "patients", data); err != nil {
templateName := "patients"
if r.URL.Query().Get("chunk") == "1" {
templateName = "patients-rows"
}
if err := t.ExecuteTemplate(w, templateName, data); err != nil {
log.Printf("[dashboard] patients template error: %v", err)
}
}

View File

@@ -391,6 +391,7 @@ func GetPeriodTrend(mcuID int, dateFrom, dateTo string, isRange bool) ([]TrendPo
type PatientStationStatus struct {
Station string
Done bool
Progress bool
ProcessAt string
DoneAt string
}
@@ -404,6 +405,8 @@ type PatientDetail struct {
HasOut bool
Stations []PatientStationStatus
DoneCount int
ProgressCount int
ProgressStatus string
}
type patientKey struct {
@@ -414,16 +417,22 @@ type patientKey struct {
func GetAllPatients(mcuID int, dateFrom, dateTo string) ([]PatientDetail, error) {
rows, err := db.DB.Query(`
SELECT
mc.Mcu_CheckinoutPreregisterID,
s.Mcu_PatientSchedulePreregisterID,
mp.Mcu_PatientName,
DATE_FORMAT(mc.Mcu_CheckinoutDate, '%Y-%m-%d'),
DATE_FORMAT(mc.Mcu_CheckinoutInTime, '%H:%i'),
DATE_FORMAT(s.Mcu_PatientScheduleDate, '%Y-%m-%d'),
COALESCE(DATE_FORMAT(mc.Mcu_CheckinoutInTime, '%H:%i'), ''),
COALESCE(DATE_FORMAT(mc.Mcu_CheckinoutOutTime, '%H:%i'), ''),
IF(mc.Mcu_CheckinoutOutTime IS NOT NULL, 1, 0),
rs.station_name,
COALESCE(rs.station_name, ''),
IF(
(sp.Mcu_StationProgressSource = 'lab' AND sp.Mcu_StationProgressReceiveAt IS NOT NULL AND DATE(sp.Mcu_StationProgressReceiveAt) <= mc.Mcu_CheckinoutDate)
OR (sp.Mcu_StationProgressSource = 'nonlab' AND sp.Mcu_StationProgressDoneAt IS NOT NULL AND DATE(sp.Mcu_StationProgressDoneAt) <= mc.Mcu_CheckinoutDate),
(sp.Mcu_StationProgressSource = 'lab' AND sp.Mcu_StationProgressReceiveAt IS NOT NULL AND DATE(sp.Mcu_StationProgressReceiveAt) <= s.Mcu_PatientScheduleDate)
OR (sp.Mcu_StationProgressSource = 'nonlab' AND sp.Mcu_StationProgressProcessAt IS NOT NULL AND DATE(sp.Mcu_StationProgressProcessAt) <= s.Mcu_PatientScheduleDate)
OR (sp.Mcu_StationProgressSource = 'nonlab' AND sp.Mcu_StationProgressDoneAt IS NOT NULL AND DATE(sp.Mcu_StationProgressDoneAt) <= s.Mcu_PatientScheduleDate),
1, 0),
IF(
(sp.Mcu_StationProgressProcessAt IS NOT NULL AND DATE(sp.Mcu_StationProgressProcessAt) <= s.Mcu_PatientScheduleDate)
OR (sp.Mcu_StationProgressReceiveAt IS NOT NULL AND DATE(sp.Mcu_StationProgressReceiveAt) <= s.Mcu_PatientScheduleDate)
OR (sp.Mcu_StationProgressSamplingAt IS NOT NULL AND DATE(sp.Mcu_StationProgressSamplingAt) <= s.Mcu_PatientScheduleDate),
1, 0),
COALESCE(DATE_FORMAT(
CASE
@@ -435,29 +444,41 @@ func GetAllPatients(mcuID int, dateFrom, dateTo string) ([]PatientDetail, error)
END,
'%d/%m/%Y %H:%i'), ''),
COALESCE(DATE_FORMAT(
IF(sp.Mcu_StationProgressSource = 'lab', sp.Mcu_StationProgressReceiveAt, sp.Mcu_StationProgressDoneAt),
CASE
WHEN sp.Mcu_StationProgressSource = 'lab' THEN sp.Mcu_StationProgressReceiveAt
WHEN sp.Mcu_StationProgressSource = 'nonlab' THEN COALESCE(sp.Mcu_StationProgressDoneAt, sp.Mcu_StationProgressProcessAt)
ELSE NULL
END,
'%d/%m/%Y %H:%i'), '')
FROM mcu_checkinout mc
JOIN mcu_patient mp ON mp.Mcu_PatientPreregisterID = mc.Mcu_CheckinoutPreregisterID
JOIN mcu_patient_required_station rs ON
rs.preregister_id = mc.Mcu_CheckinoutPreregisterID
FROM mcu_patient_schedule s
JOIN mcu_patient mp ON mp.Mcu_PatientPreregisterID = s.Mcu_PatientSchedulePreregisterID
AND mp.Mcu_PatientMcuID = ?
AND mp.Mcu_PatientIsActive = 'Y'
LEFT JOIN mcu_checkinout mc ON
mc.Mcu_CheckinoutPreregisterID = s.Mcu_PatientSchedulePreregisterID
AND mc.Mcu_CheckinoutMcuID = ?
AND mc.Mcu_CheckinoutDate = s.Mcu_PatientScheduleDate
AND mc.Mcu_CheckinoutIsActive = 'Y'
LEFT JOIN mcu_patient_required_station rs ON
rs.preregister_id = s.Mcu_PatientSchedulePreregisterID
AND rs.mcu_id = ?
LEFT JOIN mcu_station_progress sp ON
sp.Mcu_StationProgressPreregisterID = mc.Mcu_CheckinoutPreregisterID
sp.Mcu_StationProgressPreregisterID = s.Mcu_PatientSchedulePreregisterID
AND sp.Mcu_StationProgressStationID = rs.sample_station_id
AND sp.Mcu_StationProgressMcuID = ?
AND sp.Mcu_StationProgressCheckinDate = (
SELECT MAX(sp2.Mcu_StationProgressCheckinDate)
FROM mcu_station_progress sp2
WHERE sp2.Mcu_StationProgressPreregisterID = mc.Mcu_CheckinoutPreregisterID
AND sp2.Mcu_StationProgressStationID = rs.sample_station_id
AND sp2.Mcu_StationProgressMcuID = ?
AND sp2.Mcu_StationProgressCheckinDate <= mc.Mcu_CheckinoutDate
AND (
(sp.Mcu_StationProgressCheckinDate IS NOT NULL AND sp.Mcu_StationProgressCheckinDate <= s.Mcu_PatientScheduleDate)
OR
(sp.Mcu_StationProgressCheckinDate IS NULL AND (
(sp.Mcu_StationProgressDoneAt IS NOT NULL AND DATE(sp.Mcu_StationProgressDoneAt) <= s.Mcu_PatientScheduleDate)
OR (sp.Mcu_StationProgressProcessAt IS NOT NULL AND DATE(sp.Mcu_StationProgressProcessAt) <= s.Mcu_PatientScheduleDate)
OR (sp.Mcu_StationProgressReceiveAt IS NOT NULL AND DATE(sp.Mcu_StationProgressReceiveAt) <= s.Mcu_PatientScheduleDate)
OR (sp.Mcu_StationProgressSamplingAt IS NOT NULL AND DATE(sp.Mcu_StationProgressSamplingAt) <= s.Mcu_PatientScheduleDate)
))
)
WHERE mc.Mcu_CheckinoutMcuID = ?
AND mc.Mcu_CheckinoutDate BETWEEN ? AND ?
AND mc.Mcu_CheckinoutIsActive = 'Y'
ORDER BY mc.Mcu_CheckinoutDate DESC, mc.Mcu_CheckinoutInTime DESC, rs.station_name
WHERE s.Mcu_PatientScheduleDate BETWEEN ? AND ?
AND s.Mcu_PatientScheduleIsActive = 'Y'
ORDER BY s.Mcu_PatientScheduleDate DESC, mc.Mcu_CheckinoutInTime DESC, mp.Mcu_PatientName ASC, rs.station_name
`, mcuID, mcuID, mcuID, mcuID, dateFrom, dateTo)
if err != nil {
return nil, err
@@ -470,8 +491,8 @@ func GetAllPatients(mcuID int, dateFrom, dateTo string) ([]PatientDetail, error)
for rows.Next() {
var pid int
var name, date, inTime, outTime, stationName, processAt, doneAt string
var hasOutInt, doneInt int
if err := rows.Scan(&pid, &name, &date, &inTime, &outTime, &hasOutInt, &stationName, &doneInt, &processAt, &doneAt); err != nil {
var hasOutInt, doneInt, progressInt int
if err := rows.Scan(&pid, &name, &date, &inTime, &outTime, &hasOutInt, &stationName, &doneInt, &progressInt, &processAt, &doneAt); err != nil {
continue
}
k := patientKey{ID: pid, Date: date}
@@ -489,15 +510,33 @@ func GetAllPatients(mcuID int, dateFrom, dateTo string) ([]PatientDetail, error)
patients = append(patients, p)
idx = len(patients) - 1
}
done := doneInt == 1
patients[idx].Stations = append(patients[idx].Stations, PatientStationStatus{
Station: stationName,
Done: done,
ProcessAt: processAt,
DoneAt: doneAt,
})
if done {
patients[idx].DoneCount++
if stationName != "" {
done := doneInt == 1
patients[idx].Stations = append(patients[idx].Stations, PatientStationStatus{
Station: stationName,
Done: done,
Progress: progressInt == 1,
ProcessAt: processAt,
DoneAt: doneAt,
})
if done {
patients[idx].DoneCount++
}
if progressInt == 1 {
patients[idx].ProgressCount++
}
}
}
for i := range patients {
totalStations := len(patients[i].Stations)
switch {
case totalStations > 0 && patients[i].DoneCount == totalStations:
patients[i].ProgressStatus = "done"
case patients[i].DoneCount > 0 || patients[i].ProgressCount > 0:
patients[i].ProgressStatus = "partial"
default:
patients[i].ProgressStatus = "not_yet"
}
}