Initial commit
This commit is contained in:
287
cpone-dashboard/menu/dashboard/handler.go
Normal file
287
cpone-dashboard/menu/dashboard/handler.go
Normal file
@@ -0,0 +1,287 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"cpone-dashboard/menu/auth"
|
||||
"cpone-dashboard/menu/projects"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var templateFS *embed.FS
|
||||
var funcMap template.FuncMap
|
||||
|
||||
type StationsPartial struct {
|
||||
Rows []StationRow
|
||||
IsLive bool
|
||||
}
|
||||
|
||||
type ArrivalsPartial struct {
|
||||
Rows []ArrivalRow
|
||||
IsLive bool
|
||||
}
|
||||
|
||||
type PatientsPartial struct {
|
||||
Patients []PatientDetail
|
||||
IsRange bool
|
||||
}
|
||||
|
||||
type PageData struct {
|
||||
Username string
|
||||
McuID int
|
||||
Project ProjectInfo
|
||||
CurrentProject projects.ProjectItem
|
||||
AvailableDates []string
|
||||
Mode string
|
||||
DateFrom string
|
||||
DateTo string
|
||||
IsRange bool
|
||||
IsLive bool
|
||||
KPI KPIData
|
||||
TAT TATData
|
||||
Stations []StationRow
|
||||
Arrivals []ArrivalRow
|
||||
TATChart template.JS
|
||||
TrendChart template.JS
|
||||
}
|
||||
|
||||
var basePath string
|
||||
|
||||
func SetTemplateFS(fs *embed.FS) { templateFS = fs }
|
||||
func SetTemplateFuncs(fm template.FuncMap) { funcMap = fm }
|
||||
func SetBasePath(p string) { basePath = p }
|
||||
|
||||
func parse(files ...string) *template.Template {
|
||||
return template.Must(template.New("").Funcs(funcMap).ParseFS(templateFS, files...))
|
||||
}
|
||||
|
||||
func defaultDailyDate(project ProjectInfo) string {
|
||||
today := time.Now().Format("2006-01-02")
|
||||
if project.StartDate == "" {
|
||||
return today
|
||||
}
|
||||
if project.EndDate != "" && today > project.EndDate {
|
||||
return project.StartDate
|
||||
}
|
||||
if today < project.StartDate {
|
||||
return project.StartDate
|
||||
}
|
||||
return today
|
||||
}
|
||||
|
||||
func containsDate(dates []string, target string) bool {
|
||||
for _, d := range dates {
|
||||
if d == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func activeDateRange(r *http.Request, project ProjectInfo, availableDates []string) (mode, from, to string) {
|
||||
mode = "daily"
|
||||
reqDate := r.URL.Query().Get("date")
|
||||
|
||||
switch {
|
||||
case reqDate != "" && containsDate(availableDates, reqDate):
|
||||
from = reqDate
|
||||
case containsDate(availableDates, time.Now().Format("2006-01-02")):
|
||||
from = time.Now().Format("2006-01-02")
|
||||
case len(availableDates) > 0:
|
||||
from = availableDates[0]
|
||||
default:
|
||||
from = defaultDailyDate(project)
|
||||
}
|
||||
to = from
|
||||
return
|
||||
}
|
||||
|
||||
func activeMcuID(r *http.Request) int {
|
||||
if id, _ := strconv.Atoi(r.URL.Query().Get("mcu_id")); id > 0 {
|
||||
return id
|
||||
}
|
||||
return auth.SelectedProjectID(r)
|
||||
}
|
||||
|
||||
func toJS(v interface{}) template.JS {
|
||||
b, _ := json.Marshal(v)
|
||||
return template.JS(b)
|
||||
}
|
||||
|
||||
func Index(w http.ResponseWriter, r *http.Request) {
|
||||
mcuID := activeMcuID(r)
|
||||
username := auth.Username(r)
|
||||
|
||||
if mcuID == 0 {
|
||||
http.Redirect(w, r, basePath+"/projects", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
ok, err := projects.HasAccess(username, mcuID)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] HasAccess error: %v", err)
|
||||
http.Error(w, "query error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
http.Redirect(w, r, basePath+"/projects", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
project, err := GetProject(mcuID)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetActiveProject error: %v", err)
|
||||
http.Error(w, "query error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
currentProject := projects.ProjectItem{}
|
||||
if item, ok, err := projects.GetUserProject(username, mcuID); err != nil {
|
||||
log.Printf("[dashboard] GetUserProject error: %v", err)
|
||||
} else if ok {
|
||||
currentProject = item
|
||||
auth.SetSelectedProject(w, mcuID)
|
||||
}
|
||||
availableDates, err := GetCheckinDates(project.McuID)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetCheckinDates error: %v", err)
|
||||
}
|
||||
mode, dateFrom, dateTo := activeDateRange(r, project, availableDates)
|
||||
isRange := dateFrom != dateTo
|
||||
|
||||
kpi, err := GetKPI(project.McuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetKPI error: %v", err)
|
||||
}
|
||||
tat, err := GetTAT(project.McuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetTAT error: %v", err)
|
||||
}
|
||||
stations, err := GetStations(project.McuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetStations error: %v", err)
|
||||
}
|
||||
arrivals, err := GetArrivals(project.McuID, dateFrom, dateTo, 8)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetArrivals error: %v", err)
|
||||
}
|
||||
hourlyTAT, err := GetPeriodTAT(project.McuID, dateFrom, dateTo, isRange)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetPeriodTAT error: %v", err)
|
||||
}
|
||||
trend, err := GetPeriodTrend(project.McuID, dateFrom, dateTo, isRange)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetPeriodTrend error: %v", err)
|
||||
}
|
||||
|
||||
// Build chart JSON payloads
|
||||
tatLabels, tatValues := []string{}, []float64{}
|
||||
for _, p := range hourlyTAT {
|
||||
tatLabels = append(tatLabels, p.Label)
|
||||
tatValues = append(tatValues, p.Value)
|
||||
}
|
||||
trendLabels, trendCI, trendCO := []string{}, []int{}, []int{}
|
||||
for _, p := range trend {
|
||||
trendLabels = append(trendLabels, p.Label)
|
||||
trendCI = append(trendCI, p.CheckedIn)
|
||||
trendCO = append(trendCO, p.CheckedOut)
|
||||
}
|
||||
|
||||
today := time.Now().Format("2006-01-02")
|
||||
data := PageData{
|
||||
Username: username,
|
||||
McuID: project.McuID,
|
||||
Project: project,
|
||||
CurrentProject: currentProject,
|
||||
AvailableDates: availableDates,
|
||||
Mode: mode,
|
||||
DateFrom: dateFrom,
|
||||
DateTo: dateTo,
|
||||
IsRange: isRange,
|
||||
IsLive: mode == "daily" && dateFrom == today,
|
||||
KPI: kpi,
|
||||
TAT: tat,
|
||||
Stations: stations,
|
||||
Arrivals: arrivals,
|
||||
TATChart: toJS(map[string]interface{}{
|
||||
"labels": tatLabels,
|
||||
"values": tatValues,
|
||||
}),
|
||||
TrendChart: toJS(map[string]interface{}{
|
||||
"labels": trendLabels,
|
||||
"checkedIn": trendCI,
|
||||
"checkedOut": trendCO,
|
||||
}),
|
||||
}
|
||||
|
||||
t := parse("templates/layout/base.html", "templates/dashboard/index.html")
|
||||
if err := t.ExecuteTemplate(w, "base", data); err != nil {
|
||||
log.Printf("[dashboard] template error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Patients(w http.ResponseWriter, r *http.Request) {
|
||||
project, err := GetProject(activeMcuID(r))
|
||||
if err != nil {
|
||||
http.Error(w, "query error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
availableDates, _ := GetCheckinDates(project.McuID)
|
||||
mode, dateFrom, dateTo := activeDateRange(r, project, availableDates)
|
||||
patients, err := GetAllPatients(project.McuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
log.Printf("[dashboard] GetAllPatients error: %v", err)
|
||||
http.Error(w, "query error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data := PatientsPartial{
|
||||
Patients: patients,
|
||||
IsRange: mode != "daily" || dateFrom != dateTo,
|
||||
}
|
||||
t := parse("templates/dashboard/partials/patients.html")
|
||||
if err := t.ExecuteTemplate(w, "patients", data); err != nil {
|
||||
log.Printf("[dashboard] patients template error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func KPI(w http.ResponseWriter, r *http.Request) {
|
||||
project, _ := GetProject(activeMcuID(r))
|
||||
availableDates, _ := GetCheckinDates(project.McuID)
|
||||
_, from, to := activeDateRange(r, project, availableDates)
|
||||
data, err := GetKPI(project.McuID, from, to)
|
||||
if err != nil {
|
||||
http.Error(w, "query error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
t := parse("templates/dashboard/partials/kpi.html")
|
||||
t.ExecuteTemplate(w, "kpi", data)
|
||||
}
|
||||
|
||||
func Stations(w http.ResponseWriter, r *http.Request) {
|
||||
project, _ := GetProject(activeMcuID(r))
|
||||
availableDates, _ := GetCheckinDates(project.McuID)
|
||||
_, from, to := activeDateRange(r, project, availableDates)
|
||||
rows, err := GetStations(project.McuID, from, to)
|
||||
if err != nil {
|
||||
http.Error(w, "query error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
t := parse("templates/dashboard/partials/stations.html")
|
||||
t.ExecuteTemplate(w, "stations", StationsPartial{Rows: rows, IsLive: from == time.Now().Format("2006-01-02")})
|
||||
}
|
||||
|
||||
func Arrivals(w http.ResponseWriter, r *http.Request) {
|
||||
project, _ := GetProject(activeMcuID(r))
|
||||
availableDates, _ := GetCheckinDates(project.McuID)
|
||||
_, from, to := activeDateRange(r, project, availableDates)
|
||||
rows, err := GetArrivals(project.McuID, from, to, 8)
|
||||
if err != nil {
|
||||
http.Error(w, "query error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
t := parse("templates/dashboard/partials/arrivals.html")
|
||||
t.ExecuteTemplate(w, "arrivals", rows)
|
||||
}
|
||||
Reference in New Issue
Block a user