129 lines
3.5 KiB
Go
129 lines
3.5 KiB
Go
package arrival
|
|
|
|
import (
|
|
"cpone-dashboard/menu/auth"
|
|
"cpone-dashboard/menu/projects"
|
|
"encoding/json"
|
|
"html/template"
|
|
"net/http"
|
|
)
|
|
|
|
var tmpl *template.Template
|
|
var basePath string
|
|
|
|
func SetTemplates(t *template.Template) { tmpl = t }
|
|
func SetBasePath(p string) { basePath = p }
|
|
|
|
type pageData struct {
|
|
Username string
|
|
CurrentProject projects.ProjectItem
|
|
Date string
|
|
AvailableDates []string
|
|
Search string
|
|
Department string
|
|
Rows []ArrivalRow
|
|
FilteredRows []ArrivalRow
|
|
Summary ArrivalSummary
|
|
Departments []DepartmentStat
|
|
DepartmentOptions []string
|
|
OverviewJSON template.JS
|
|
DepartmentJSON template.JS
|
|
}
|
|
|
|
func toJS(v interface{}) template.JS {
|
|
b, _ := json.Marshal(v)
|
|
return template.JS(b)
|
|
}
|
|
|
|
func Index(w http.ResponseWriter, r *http.Request) {
|
|
username := auth.Username(r)
|
|
mcuID := auth.SelectedProjectID(r)
|
|
if mcuID == 0 {
|
|
http.Redirect(w, r, basePath+"/projects", http.StatusSeeOther)
|
|
return
|
|
}
|
|
project, ok, err := projects.GetUserProject(username, mcuID)
|
|
if err != nil {
|
|
http.Error(w, "query error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !ok {
|
|
http.Redirect(w, r, basePath+"/projects", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
dates, err := GetArrivalDates(mcuID)
|
|
if err != nil {
|
|
http.Error(w, "query error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
selectedDate := activeDateOrLatest(dates, r.URL.Query().Get("date"), project.StartDate)
|
|
rows, err := GetArrivalRows(mcuID, selectedDate)
|
|
if err != nil {
|
|
http.Error(w, "query error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
summary, deptStats := BuildArrivalStats(rows)
|
|
filteredRows := FilterArrivalRows(rows, r.URL.Query().Get("search"), r.URL.Query().Get("dept"))
|
|
deptOptions := UniqueDepartments(rows)
|
|
|
|
stationMap, err := GetStationProgress(mcuID, selectedDate)
|
|
if err != nil {
|
|
http.Error(w, "query error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
for i := range filteredRows {
|
|
filteredRows[i].Stations = stationMap[filteredRows[i].PreregisterID]
|
|
}
|
|
|
|
// Chart 1: double donut — inner: checked-in vs pending, outer: total per posisi/dept
|
|
outerDepts := []map[string]any{}
|
|
for _, d := range deptStats {
|
|
if d.Total > 0 {
|
|
outerDepts = append(outerDepts, map[string]any{"name": d.Name, "value": d.Total})
|
|
}
|
|
}
|
|
overview := map[string]any{
|
|
"checkedIn": summary.CheckedIn,
|
|
"pending": summary.Pending,
|
|
"depts": outerDepts,
|
|
}
|
|
|
|
// Chart 2: per-station patient count bar chart
|
|
stationStats := BuildStationChart(stationMap)
|
|
stationLabels := make([]string, len(stationStats))
|
|
stationCounts := make([]int, len(stationStats))
|
|
for i, s := range stationStats {
|
|
stationLabels[i] = s.Name
|
|
stationCounts[i] = s.Count
|
|
}
|
|
stationChart := map[string]any{
|
|
"labels": stationLabels,
|
|
"counts": stationCounts,
|
|
}
|
|
|
|
t := tmpl
|
|
if t == nil {
|
|
http.Error(w, "template not ready", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
data := pageData{
|
|
Username: username,
|
|
CurrentProject: project,
|
|
Date: selectedDate,
|
|
AvailableDates: dates,
|
|
Search: r.URL.Query().Get("search"),
|
|
Department: r.URL.Query().Get("dept"),
|
|
Rows: rows,
|
|
FilteredRows: filteredRows,
|
|
Summary: summary,
|
|
Departments: deptStats,
|
|
DepartmentOptions: deptOptions,
|
|
OverviewJSON: toJS(overview),
|
|
DepartmentJSON: toJS(stationChart),
|
|
}
|
|
if err := t.ExecuteTemplate(w, "base", data); err != nil {
|
|
http.Error(w, "template error", http.StatusInternalServerError)
|
|
}
|
|
}
|