Initial commit
This commit is contained in:
505
cpone-dashboard/menu/dashboard/query.go
Normal file
505
cpone-dashboard/menu/dashboard/query.go
Normal file
@@ -0,0 +1,505 @@
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"cpone-dashboard/db"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const checkinOutTimestampExpr = "TIMESTAMP(Mcu_CheckinoutDate, Mcu_CheckinoutOutTime)"
|
||||
|
||||
type ProjectInfo struct {
|
||||
McuID int
|
||||
CorporateName string
|
||||
Label string
|
||||
Number string
|
||||
StartDate string
|
||||
EndDate string
|
||||
TotalStaff int
|
||||
}
|
||||
|
||||
type KPIData struct {
|
||||
InvitedStaff int // dari mcu_participant_daily, date-filtered — untuk widget kanan atas
|
||||
TotalStaff int // dari mcu_checkinout, seluruh project — untuk KPI card
|
||||
CheckedIn int // dari mcu_checkinout, date-filtered
|
||||
CheckedOut int // dari mcu_checkinout, date-filtered
|
||||
}
|
||||
|
||||
type StationRow struct {
|
||||
Station string
|
||||
Processed int
|
||||
Pending int
|
||||
Total int
|
||||
Pct float64
|
||||
}
|
||||
|
||||
type ArrivalRow struct {
|
||||
Name string
|
||||
InTime string
|
||||
Date string
|
||||
Station string
|
||||
}
|
||||
|
||||
type TATData struct {
|
||||
AvgMinutes int
|
||||
Fastest int
|
||||
Median int
|
||||
CheckedOut int
|
||||
}
|
||||
|
||||
type ChartPoint struct {
|
||||
Label string
|
||||
Value float64
|
||||
}
|
||||
|
||||
type TrendPoint struct {
|
||||
Label string
|
||||
CheckedIn int
|
||||
CheckedOut int
|
||||
}
|
||||
|
||||
// GetProject returns project by mcuID. If mcuID == 0, returns the active project.
|
||||
func GetProject(mcuID int) (ProjectInfo, error) {
|
||||
var p ProjectInfo
|
||||
var err error
|
||||
const cols = `SELECT Mcu_ProjectMcuID, Mcu_ProjectCorporateName, Mcu_ProjectLabel,
|
||||
Mcu_ProjectNumber,
|
||||
DATE_FORMAT(Mcu_ProjectStartDate, '%Y-%m-%d'),
|
||||
DATE_FORMAT(Mcu_ProjectEndDate, '%Y-%m-%d'),
|
||||
Mcu_ProjectTotalParticipant
|
||||
FROM mcu_project`
|
||||
if mcuID > 0 {
|
||||
err = db.DB.QueryRow(cols+` WHERE Mcu_ProjectMcuID = ?`, mcuID).
|
||||
Scan(&p.McuID, &p.CorporateName, &p.Label, &p.Number, &p.StartDate, &p.EndDate, &p.TotalStaff)
|
||||
} else {
|
||||
err = db.DB.QueryRow(cols+` WHERE Mcu_ProjectIsActive = 'Y' ORDER BY Mcu_ProjectStartDate DESC LIMIT 1`).
|
||||
Scan(&p.McuID, &p.CorporateName, &p.Label, &p.Number, &p.StartDate, &p.EndDate, &p.TotalStaff)
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
return p, nil
|
||||
}
|
||||
return p, err
|
||||
}
|
||||
|
||||
func GetKPI(mcuID int, dateFrom, dateTo string) (KPIData, error) {
|
||||
var d KPIData
|
||||
|
||||
// Invited staff: dari mcu_participant_daily, date-filtered — widget kanan atas
|
||||
db.DB.QueryRow(`
|
||||
SELECT COALESCE(SUM(Mcu_ParticipantDailyTotal), 0)
|
||||
FROM mcu_participant_daily
|
||||
WHERE Mcu_ParticipantDailyMcuID = ?
|
||||
AND Mcu_ParticipantDailyDate BETWEEN ? AND ?
|
||||
AND Mcu_ParticipantDailyIsActive = 'Y'
|
||||
`, mcuID, dateFrom, dateTo).Scan(&d.InvitedStaff)
|
||||
|
||||
// Total staff: semua yang datang (checkin) pada tanggal filter
|
||||
db.DB.QueryRow(`
|
||||
SELECT COUNT(DISTINCT Mcu_CheckinoutPreregisterID) FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
`, mcuID, dateFrom, dateTo).Scan(&d.TotalStaff)
|
||||
|
||||
// Checked-in: masih di dalam (belum checkout)
|
||||
db.DB.QueryRow(`
|
||||
SELECT COUNT(DISTINCT Mcu_CheckinoutPreregisterID) FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND Mcu_CheckinoutOutTime IS NULL
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
`, mcuID, dateFrom, dateTo).Scan(&d.CheckedIn)
|
||||
|
||||
// Checked-out: sudah selesai
|
||||
db.DB.QueryRow(`
|
||||
SELECT COUNT(DISTINCT Mcu_CheckinoutPreregisterID) FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND Mcu_CheckinoutOutTime IS NOT NULL
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
`, mcuID, dateFrom, dateTo).Scan(&d.CheckedOut)
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func GetCheckinDates(mcuID int) ([]string, error) {
|
||||
rows, err := db.DB.Query(`
|
||||
SELECT DATE_FORMAT(Mcu_CheckinoutDate, '%Y-%m-%d') AS checkin_date
|
||||
FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
GROUP BY Mcu_CheckinoutDate
|
||||
ORDER BY Mcu_CheckinoutDate DESC
|
||||
`, mcuID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var dates []string
|
||||
for rows.Next() {
|
||||
var d string
|
||||
if rows.Scan(&d) == nil && d != "" {
|
||||
dates = append(dates, d)
|
||||
}
|
||||
}
|
||||
return dates, nil
|
||||
}
|
||||
|
||||
func GetTAT(mcuID int, dateFrom, dateTo string) (TATData, error) {
|
||||
var d TATData
|
||||
rows, err := db.DB.Query(`
|
||||
SELECT TIMESTAMPDIFF(MINUTE,
|
||||
TIMESTAMP(Mcu_CheckinoutDate, Mcu_CheckinoutInTime),
|
||||
`+checkinOutTimestampExpr+`
|
||||
) AS tat
|
||||
FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND Mcu_CheckinoutOutTime IS NOT NULL
|
||||
AND Mcu_CheckinoutInTime IS NOT NULL
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
ORDER BY tat
|
||||
`, mcuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
return d, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var vals []int
|
||||
for rows.Next() {
|
||||
var v int
|
||||
if rows.Scan(&v) == nil && v > 0 {
|
||||
vals = append(vals, v)
|
||||
}
|
||||
}
|
||||
if len(vals) == 0 {
|
||||
return d, nil
|
||||
}
|
||||
sum := 0
|
||||
for _, v := range vals {
|
||||
sum += v
|
||||
}
|
||||
d.CheckedOut = len(vals)
|
||||
d.AvgMinutes = sum / len(vals)
|
||||
d.Fastest = vals[0]
|
||||
d.Median = vals[len(vals)/2]
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func GetStations(mcuID int, dateFrom, dateTo string) ([]StationRow, error) {
|
||||
rows, err := db.DB.Query(`
|
||||
SELECT rs.station_name,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN spd.first_done_date IS NULL OR spd.first_done_date >= mc.Mcu_CheckinoutDate
|
||||
THEN mc.Mcu_CheckinoutPreregisterID
|
||||
END) AS total_required,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN spd.first_done_date = mc.Mcu_CheckinoutDate
|
||||
THEN mc.Mcu_CheckinoutPreregisterID
|
||||
ELSE NULL
|
||||
END) AS processed
|
||||
FROM mcu_checkinout mc
|
||||
JOIN mcu_patient_required_station rs
|
||||
ON rs.preregister_id = mc.Mcu_CheckinoutPreregisterID
|
||||
AND rs.mcu_id = mc.Mcu_CheckinoutMcuID
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
sp.Mcu_StationProgressPreregisterID AS preregister_id,
|
||||
sp.Mcu_StationProgressStationID AS station_id,
|
||||
MIN(CASE
|
||||
WHEN sp.Mcu_StationProgressSource = 'lab'
|
||||
AND sp.Mcu_StationProgressReceiveAt IS NOT NULL
|
||||
THEN DATE(sp.Mcu_StationProgressReceiveAt)
|
||||
WHEN sp.Mcu_StationProgressSource = 'nonlab'
|
||||
AND sp.Mcu_StationProgressDoneAt IS NOT NULL
|
||||
THEN DATE(sp.Mcu_StationProgressDoneAt)
|
||||
ELSE NULL
|
||||
END) AS first_done_date
|
||||
FROM mcu_station_progress sp
|
||||
WHERE sp.Mcu_StationProgressMcuID = ?
|
||||
GROUP BY sp.Mcu_StationProgressPreregisterID, sp.Mcu_StationProgressStationID
|
||||
) spd
|
||||
ON spd.preregister_id = mc.Mcu_CheckinoutPreregisterID
|
||||
AND spd.station_id = rs.sample_station_id
|
||||
WHERE mc.Mcu_CheckinoutMcuID = ?
|
||||
AND mc.Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND mc.Mcu_CheckinoutIsActive = 'Y'
|
||||
GROUP BY rs.station_name
|
||||
HAVING total_required > 0
|
||||
ORDER BY processed DESC, rs.station_name ASC
|
||||
`, mcuID, mcuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []StationRow
|
||||
for rows.Next() {
|
||||
var r StationRow
|
||||
if err := rows.Scan(&r.Station, &r.Total, &r.Processed); err != nil {
|
||||
continue
|
||||
}
|
||||
r.Pending = r.Total - r.Processed
|
||||
if r.Pending < 0 {
|
||||
r.Pending = 0
|
||||
}
|
||||
if r.Total > 0 {
|
||||
r.Pct = float64(r.Processed) / float64(r.Total) * 100
|
||||
}
|
||||
result = append(result, r)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetArrivals(mcuID int, dateFrom, dateTo string, limit int) ([]ArrivalRow, error) {
|
||||
rows, err := db.DB.Query(`
|
||||
SELECT mp.Mcu_PatientName,
|
||||
DATE_FORMAT(mc.Mcu_CheckinoutInTime, '%H:%i:%s') AS in_time,
|
||||
DATE_FORMAT(mc.Mcu_CheckinoutDate, '%Y-%m-%d') AS checkin_date,
|
||||
COALESCE(
|
||||
(SELECT Mcu_StationProgressStationName
|
||||
FROM mcu_station_progress
|
||||
WHERE Mcu_StationProgressPreregisterID = mc.Mcu_CheckinoutPreregisterID
|
||||
AND Mcu_StationProgressCheckinDate = mc.Mcu_CheckinoutDate
|
||||
AND Mcu_StationProgressDoneAt IS NOT NULL
|
||||
ORDER BY Mcu_StationProgressDoneAt DESC LIMIT 1),
|
||||
'Check-in'
|
||||
) AS last_station
|
||||
FROM mcu_checkinout mc
|
||||
JOIN mcu_patient mp ON mp.Mcu_PatientPreregisterID = mc.Mcu_CheckinoutPreregisterID
|
||||
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
|
||||
LIMIT ?
|
||||
`, mcuID, dateFrom, dateTo, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []ArrivalRow
|
||||
for rows.Next() {
|
||||
var r ArrivalRow
|
||||
if rows.Scan(&r.Name, &r.InTime, &r.Date, &r.Station) == nil {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetPeriodTAT — tampilkan agregasi per jam untuk daily maupun range
|
||||
func GetPeriodTAT(mcuID int, dateFrom, dateTo string, isRange bool) ([]ChartPoint, error) {
|
||||
_ = isRange
|
||||
groupExpr := "HOUR(Mcu_CheckinoutInTime)"
|
||||
labelExpr := "CONCAT(LPAD(HOUR(Mcu_CheckinoutInTime), 2, '0'), ':00')"
|
||||
|
||||
q := fmt.Sprintf(`
|
||||
SELECT %s AS label,
|
||||
AVG(TIMESTAMPDIFF(MINUTE,
|
||||
TIMESTAMP(Mcu_CheckinoutDate, Mcu_CheckinoutInTime),
|
||||
%s
|
||||
)) AS avg_tat
|
||||
FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND Mcu_CheckinoutOutTime IS NOT NULL
|
||||
AND Mcu_CheckinoutInTime IS NOT NULL
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
GROUP BY %s
|
||||
ORDER BY %s
|
||||
`, labelExpr, checkinOutTimestampExpr, groupExpr, groupExpr)
|
||||
|
||||
rows, err := db.DB.Query(q, mcuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []ChartPoint
|
||||
for rows.Next() {
|
||||
var p ChartPoint
|
||||
if rows.Scan(&p.Label, &p.Value) == nil {
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetPeriodTrend — tampilkan hitungan per jam untuk daily maupun range
|
||||
func GetPeriodTrend(mcuID int, dateFrom, dateTo string, isRange bool) ([]TrendPoint, error) {
|
||||
_ = isRange
|
||||
q := `
|
||||
SELECT hour_no,
|
||||
CONCAT(LPAD(hour_no, 2, '0'), ':00') AS label,
|
||||
SUM(checked_in) AS checked_in,
|
||||
SUM(checked_out) AS checked_out
|
||||
FROM (
|
||||
SELECT HOUR(Mcu_CheckinoutInTime) AS hour_no,
|
||||
COUNT(*) AS checked_in,
|
||||
0 AS checked_out
|
||||
FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND Mcu_CheckinoutInTime IS NOT NULL
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
GROUP BY HOUR(Mcu_CheckinoutInTime)
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT HOUR(Mcu_CheckinoutOutTime) AS hour_no,
|
||||
0 AS checked_in,
|
||||
COUNT(*) AS checked_out
|
||||
FROM mcu_checkinout
|
||||
WHERE Mcu_CheckinoutMcuID = ?
|
||||
AND Mcu_CheckinoutDate BETWEEN ? AND ?
|
||||
AND Mcu_CheckinoutOutTime IS NOT NULL
|
||||
AND Mcu_CheckinoutIsActive = 'Y'
|
||||
GROUP BY HOUR(Mcu_CheckinoutOutTime)
|
||||
) t
|
||||
GROUP BY hour_no
|
||||
ORDER BY hour_no
|
||||
`
|
||||
|
||||
rows, err := db.DB.Query(q, mcuID, dateFrom, dateTo, mcuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Build cumulative
|
||||
var points []TrendPoint
|
||||
cumCI, cumCO := 0, 0
|
||||
for rows.Next() {
|
||||
var hourNo int
|
||||
var label string
|
||||
var ci, co int
|
||||
if rows.Scan(&hourNo, &label, &ci, &co) == nil {
|
||||
cumCI += ci
|
||||
cumCO += co
|
||||
points = append(points, TrendPoint{
|
||||
Label: label,
|
||||
CheckedIn: cumCI,
|
||||
CheckedOut: cumCO,
|
||||
})
|
||||
}
|
||||
}
|
||||
return points, nil
|
||||
}
|
||||
|
||||
type PatientStationStatus struct {
|
||||
Station string
|
||||
Done bool
|
||||
ProcessAt string
|
||||
DoneAt string
|
||||
}
|
||||
|
||||
type PatientDetail struct {
|
||||
ID int
|
||||
Name string
|
||||
Date string
|
||||
InTime string
|
||||
OutTime string
|
||||
HasOut bool
|
||||
Stations []PatientStationStatus
|
||||
DoneCount int
|
||||
}
|
||||
|
||||
type patientKey struct {
|
||||
ID int
|
||||
Date string
|
||||
}
|
||||
|
||||
func GetAllPatients(mcuID int, dateFrom, dateTo string) ([]PatientDetail, error) {
|
||||
rows, err := db.DB.Query(`
|
||||
SELECT
|
||||
mc.Mcu_CheckinoutPreregisterID,
|
||||
mp.Mcu_PatientName,
|
||||
DATE_FORMAT(mc.Mcu_CheckinoutDate, '%Y-%m-%d'),
|
||||
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,
|
||||
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),
|
||||
1, 0),
|
||||
COALESCE(DATE_FORMAT(
|
||||
CASE
|
||||
WHEN sp.Mcu_StationProgressSource = 'lab'
|
||||
THEN COALESCE(sp.Mcu_StationProgressSamplingAt, sp.Mcu_StationProgressProcessAt, sp.Mcu_StationProgressReceiveAt)
|
||||
WHEN sp.Mcu_StationProgressSource = 'nonlab'
|
||||
THEN COALESCE(sp.Mcu_StationProgressProcessAt, sp.Mcu_StationProgressDoneAt)
|
||||
ELSE NULL
|
||||
END,
|
||||
'%d/%m/%Y %H:%i'), ''),
|
||||
COALESCE(DATE_FORMAT(
|
||||
IF(sp.Mcu_StationProgressSource = 'lab', sp.Mcu_StationProgressReceiveAt, sp.Mcu_StationProgressDoneAt),
|
||||
'%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
|
||||
AND rs.mcu_id = ?
|
||||
LEFT JOIN mcu_station_progress sp ON
|
||||
sp.Mcu_StationProgressPreregisterID = mc.Mcu_CheckinoutPreregisterID
|
||||
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
|
||||
)
|
||||
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
|
||||
`, mcuID, mcuID, mcuID, mcuID, dateFrom, dateTo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var patients []PatientDetail
|
||||
keyIndex := map[patientKey]int{}
|
||||
|
||||
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 {
|
||||
continue
|
||||
}
|
||||
k := patientKey{ID: pid, Date: date}
|
||||
idx, ok := keyIndex[k]
|
||||
if !ok {
|
||||
p := PatientDetail{
|
||||
ID: pid,
|
||||
Name: name,
|
||||
Date: date,
|
||||
InTime: inTime,
|
||||
OutTime: outTime,
|
||||
HasOut: hasOutInt == 1,
|
||||
}
|
||||
keyIndex[k] = len(patients)
|
||||
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++
|
||||
}
|
||||
}
|
||||
|
||||
return patients, nil
|
||||
}
|
||||
Reference in New Issue
Block a user