Update dashboard filters and packet views
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user