package admin import ( "api-service/internal/config" "api-service/internal/database" "context" "database/sql" "encoding/json" "fmt" "net/http" "strconv" "time" "github.com/gin-gonic/gin" ) type Ruangan struct { No int Nama string JumlahTT int KodeKelas sql.NullString KodeAplicare sql.NullString NamaRuang sql.NullString StAktif int } type AdminHandler struct { db database.Service } type AdminHandlerConfig struct { Config *config.Config } func NewAdminHandler(cfg AdminHandlerConfig) *AdminHandler { return &AdminHandler{db: database.New(cfg.Config)} } func (h *AdminHandler) getRuangan(ctx context.Context) ([]Ruangan, error) { db, err := h.db.GetDB("simrs") if err != nil { return nil, fmt.Errorf("koneksi simrs gagal: %w", err) } rows, err := db.QueryContext(ctx, ` SELECT no, nama, jumlah_tt, kode_kelas, kode_aplicare, nama_ruang, st_aktif FROM m_ruang WHERE subsistem LIKE '%RAWAT INAP%' ORDER BY no `) if err != nil { return nil, err } defer rows.Close() var result []Ruangan for rows.Next() { var r Ruangan if err := rows.Scan(&r.No, &r.Nama, &r.JumlahTT, &r.KodeKelas, &r.KodeAplicare, &r.NamaRuang, &r.StAktif); err != nil { return nil, err } result = append(result, r) } return result, rows.Err() } // GetPage — GET /admin/aplicares func (h *AdminHandler) GetPage(c *gin.Context) { ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second) defer cancel() ruangans, err := h.getRuangan(ctx) if err != nil { c.String(http.StatusInternalServerError, "Error: "+err.Error()) return } type RuanganJSON struct { No int `json:"no"` Nama string `json:"nama"` JumlahTT int `json:"jumlah_tt"` KodeKelas string `json:"kode_kelas"` KodeAplicare string `json:"kode_aplicare"` NamaRuang string `json:"nama_ruang"` SudahMapping bool `json:"sudah_mapping"` StAktif int `json:"st_aktif"` } var data []RuanganJSON belumMapping := 0 for _, r := range ruangans { sudah := r.KodeKelas.Valid && r.KodeKelas.String != "" && r.KodeAplicare.Valid && r.KodeAplicare.String != "" if !sudah { belumMapping++ } data = append(data, RuanganJSON{ No: r.No, Nama: r.Nama, JumlahTT: r.JumlahTT, KodeKelas: r.KodeKelas.String, KodeAplicare: r.KodeAplicare.String, NamaRuang: r.NamaRuang.String, SudahMapping: sudah, StAktif: r.StAktif, }) } jsonData, _ := json.Marshal(data) html := ` Admin Aplicares

🏥 Admin Aplicares — Mapping Ruangan BPJS

-
Total Ruangan
-
Sudah Mapping
-
Belum Mapping
No Nama Ruangan (SIMRS) Kapasitas Status Kode Kelas Kode BPJS Status Aksi
` c.Header("Content-Type", "text/html; charset=utf-8") c.String(http.StatusOK, html) } func kelasOptions() string { opts := ` ` return opts } // GetRuangan — GET /api/v1/admin/aplicares/ruangan (JSON) func (h *AdminHandler) GetRuangan(c *gin.Context) { ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second) defer cancel() ruangans, err := h.getRuangan(ctx) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } type Resp struct { No int `json:"no"` Nama string `json:"nama"` JumlahTT int `json:"jumlah_tt"` KodeKelas string `json:"kode_kelas"` KodeAplicare string `json:"kode_aplicare"` NamaRuang string `json:"nama_ruang"` SudahMapping bool `json:"sudah_mapping"` } var data []Resp belum := 0 for _, r := range ruangans { sudah := r.KodeKelas.Valid && r.KodeKelas.String != "" && r.KodeAplicare.Valid && r.KodeAplicare.String != "" if !sudah { belum++ } data = append(data, Resp{ No: r.No, Nama: r.Nama, JumlahTT: r.JumlahTT, KodeKelas: r.KodeKelas.String, KodeAplicare: r.KodeAplicare.String, NamaRuang: r.NamaRuang.String, SudahMapping: sudah, }) } c.JSON(http.StatusOK, gin.H{ "total": len(data), "belum_mapping": belum, "sudah_mapping": len(data) - belum, "data": data, }) } // UpdateRuangan — PUT /api/v1/admin/aplicares/ruangan/:no func (h *AdminHandler) UpdateRuangan(c *gin.Context) { no, err := strconv.Atoi(c.Param("no")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "no tidak valid"}) return } var body struct { KodeKelas string `json:"kode_kelas"` KodeAplicare string `json:"kode_aplicare"` NamaRuang string `json:"nama_ruang"` JumlahTT int `json:"jumlah_tt"` StAktif int `json:"st_aktif"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if body.KodeKelas == "" || body.KodeAplicare == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "kode_kelas dan kode_aplicare wajib diisi"}) return } db, err := h.db.GetDB("simrs") if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "koneksi DB gagal"}) return } ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second) defer cancel() result, err := db.ExecContext(ctx, ` UPDATE m_ruang SET kode_kelas=$1, kode_aplicare=$2, nama_ruang=$3, jumlah_tt=$4, st_aktif=$5 WHERE no=$6 `, body.KodeKelas, body.KodeAplicare, body.NamaRuang, body.JumlahTT, body.StAktif, no) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "update gagal: " + err.Error()}) return } rowsAffected, _ := result.RowsAffected() if rowsAffected == 0 { c.JSON(http.StatusOK, gin.H{"error": "tidak ada row yang terupdate, no=" + fmt.Sprintf("%d", no)}) return } c.JSON(http.StatusOK, gin.H{"message": "berhasil diupdate", "no": no, "rows_affected": rowsAffected}) } // CreateRuangan — POST /api/v1/admin/aplicares/ruangan func (h *AdminHandler) CreateRuangan(c *gin.Context) { var body struct { Nama string `json:"nama"` JumlahTT int `json:"jumlah_tt"` KodeKelas string `json:"kode_kelas"` KodeAplicare string `json:"kode_aplicare"` NamaRuang string `json:"nama_ruang"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if body.Nama == "" || body.KodeKelas == "" || body.KodeAplicare == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "nama, kode_kelas, kode_aplicare wajib diisi"}) return } db, err := h.db.GetDB("simrs") if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "koneksi DB gagal"}) return } ctx, cancel := context.WithTimeout(c.Request.Context(), 10*time.Second) defer cancel() // Auto generate no = MAX(no) + 1 var maxNo int err = db.QueryRowContext(ctx, `SELECT COALESCE(MAX(no), 0) FROM m_ruang`).Scan(&maxNo) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "gagal generate no: " + err.Error()}) return } newNo := maxNo + 1 _, err = db.ExecContext(ctx, ` INSERT INTO m_ruang (no, nama, jumlah_tt, subsistem, st_aktif, kode_kelas, kode_aplicare, nama_ruang) VALUES ($1, $2, $3, 'RAWAT INAP', 1, $4, $5, $6) `, newNo, body.Nama, body.JumlahTT, body.KodeKelas, body.KodeAplicare, body.NamaRuang) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "insert gagal: " + err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "ruangan berhasil ditambahkan", "no": newNo}) }