API dashboard perbandingan jumlah status antrian

This commit is contained in:
renaldybrada
2026-02-11 09:51:38 +07:00
parent 22bfdee8e9
commit dd4377c1fb
10 changed files with 379 additions and 4 deletions
+74 -2
View File
@@ -223,6 +223,47 @@ const docTemplate = `{
}
}
},
"/dashboard/perbandingan-status-antrian/": {
"get": {
"tags": [
"Dashboard"
],
"summary": "Get Perbandingan Status Antrean",
"parameters": [
{
"type": "integer",
"description": "tahun dalam int",
"name": "year",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "bulan dalam int",
"name": "month",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dashboard.PerbandinganStatusAntreanResponse"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/shared.BaseErrorResponse"
}
}
}
}
},
"/reference/diagnosa/": {
"get": {
"tags": [
@@ -591,6 +632,10 @@ const docTemplate = `{
"antrianoperasi.FormDataRequest": {
"type": "object",
"required": [
"jenisKelamin",
"namaPasien",
"noKtp",
"noRekamMedis",
"nomorTelepon"
],
"properties": {
@@ -598,7 +643,11 @@ const docTemplate = `{
"type": "string"
},
"jenisKelamin": {
"type": "string"
"type": "string",
"enum": [
"L",
"P"
]
},
"namaPasien": {
"type": "string"
@@ -715,12 +764,21 @@ const docTemplate = `{
},
"antrianoperasi.StatusPasienRequest": {
"type": "object",
"required": [
"statusOperasi"
],
"properties": {
"keteranganStatus": {
"type": "string"
},
"statusOperasi": {
"type": "string"
"type": "string",
"enum": [
"1",
"2",
"3",
"4"
]
},
"tanggalSelesai": {
"type": "string"
@@ -794,6 +852,20 @@ const docTemplate = `{
}
}
},
"dashboard.PerbandinganStatusAntreanResponse": {
"type": "object",
"properties": {
"idStatus": {
"type": "integer"
},
"jumlah": {
"type": "integer"
},
"status": {
"type": "string"
}
}
},
"diagnosa.DiagnosaResponse": {
"type": "object",
"properties": {
+74 -2
View File
@@ -217,6 +217,47 @@
}
}
},
"/dashboard/perbandingan-status-antrian/": {
"get": {
"tags": [
"Dashboard"
],
"summary": "Get Perbandingan Status Antrean",
"parameters": [
{
"type": "integer",
"description": "tahun dalam int",
"name": "year",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "bulan dalam int",
"name": "month",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dashboard.PerbandinganStatusAntreanResponse"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/shared.BaseErrorResponse"
}
}
}
}
},
"/reference/diagnosa/": {
"get": {
"tags": [
@@ -585,6 +626,10 @@
"antrianoperasi.FormDataRequest": {
"type": "object",
"required": [
"jenisKelamin",
"namaPasien",
"noKtp",
"noRekamMedis",
"nomorTelepon"
],
"properties": {
@@ -592,7 +637,11 @@
"type": "string"
},
"jenisKelamin": {
"type": "string"
"type": "string",
"enum": [
"L",
"P"
]
},
"namaPasien": {
"type": "string"
@@ -709,12 +758,21 @@
},
"antrianoperasi.StatusPasienRequest": {
"type": "object",
"required": [
"statusOperasi"
],
"properties": {
"keteranganStatus": {
"type": "string"
},
"statusOperasi": {
"type": "string"
"type": "string",
"enum": [
"1",
"2",
"3",
"4"
]
},
"tanggalSelesai": {
"type": "string"
@@ -788,6 +846,20 @@
}
}
},
"dashboard.PerbandinganStatusAntreanResponse": {
"type": "object",
"properties": {
"idStatus": {
"type": "integer"
},
"jumlah": {
"type": "integer"
},
"status": {
"type": "string"
}
}
},
"diagnosa.DiagnosaResponse": {
"type": "object",
"properties": {
+50
View File
@@ -81,6 +81,9 @@ definitions:
alamat:
type: string
jenisKelamin:
enum:
- L
- P
type: string
namaPasien:
type: string
@@ -98,6 +101,10 @@ definitions:
umur:
type: string
required:
- jenisKelamin
- namaPasien
- noKtp
- noRekamMedis
- nomorTelepon
type: object
antrianoperasi.PasienOperasi:
@@ -164,9 +171,16 @@ definitions:
keteranganStatus:
type: string
statusOperasi:
enum:
- "1"
- "2"
- "3"
- "4"
type: string
tanggalSelesai:
type: string
required:
- statusOperasi
type: object
antrianoperasi.TindakanItemRequest:
properties:
@@ -212,6 +226,15 @@ definitions:
subSpesialis:
type: string
type: object
dashboard.PerbandinganStatusAntreanResponse:
properties:
idStatus:
type: integer
jumlah:
type: integer
status:
type: string
type: object
diagnosa.DiagnosaResponse:
properties:
keterangan:
@@ -485,6 +508,33 @@ paths:
summary: Get Antrian Per Spesialis
tags:
- Dashboard
/dashboard/perbandingan-status-antrian/:
get:
parameters:
- description: tahun dalam int
in: query
name: year
required: true
type: integer
- description: bulan dalam int
in: query
name: month
required: true
type: integer
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/dashboard.PerbandinganStatusAntreanResponse'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/shared.BaseErrorResponse'
summary: Get Perbandingan Status Antrean
tags:
- Dashboard
/reference/diagnosa/:
get:
parameters:
@@ -0,0 +1,44 @@
package dashboard
import (
"testing"
)
type expectedRangeDate struct {
startDate string
endDate string
}
func TestDashboardDateRange(t *testing.T) {
dataSet := []struct {
testCase string
data PeriodeDashboardRequest
expected expectedRangeDate
}{
{
testCase: "Normal case",
data: PeriodeDashboardRequest{Year: 2025, Month: 1},
expected: expectedRangeDate{startDate: "2025-1-1", endDate: "2025-2-1"},
},
{
testCase: "Cross year case",
data: PeriodeDashboardRequest{Year: 2025, Month: 12},
expected: expectedRangeDate{startDate: "2025-12-1", endDate: "2026-1-1"},
},
{
testCase: "Month > 12",
data: PeriodeDashboardRequest{Year: 2025, Month: 20},
expected: expectedRangeDate{startDate: "2025-12-1", endDate: "2026-1-1"},
},
}
t.Run("test parsing dashboard range date", func(t *testing.T) {
for _, testcase := range dataSet {
resultStartDate, resultEndDate := GenerateStartEndDate(testcase.data)
if resultStartDate != testcase.expected.startDate || resultEndDate != testcase.expected.endDate {
t.Fatalf("expected start date %v got %v \n expected end date %v got %v", testcase.expected.startDate, resultStartDate, testcase.expected.endDate, resultEndDate)
}
}
})
}
+41
View File
@@ -3,6 +3,7 @@ package dashboard
import (
"net/http"
"antrian-operasi/internal/shared"
baseResponse "antrian-operasi/internal/shared"
"github.com/gin-gonic/gin"
@@ -64,3 +65,43 @@ func (h DashboardHandler) GetAntrianPerSpesialis(c *gin.Context) {
c.JSON(http.StatusOK, response)
}
// GetPerbandinganStatusAntrean godoc
// @Summary Get Perbandingan Status Antrean
// @Tags Dashboard
// @Param year query int true "tahun dalam int"
// @Param month query int true "bulan dalam int"
// @Success 200 {object} []PerbandinganStatusAntreanResponse
// @Failure 500 {object} shared.BaseErrorResponse
// @Router /dashboard/perbandingan-status-antrian/ [get]
func (h DashboardHandler) GetPerbandinganstatusAntrean(c *gin.Context) {
var req PeriodeDashboardRequest
if err := c.ShouldBindQuery(&req); err != nil {
c.JSON(400, shared.BaseErrorResponse{
Success: false,
Code: 500,
Message: "error bind json",
Errors: shared.ValidationError(err),
})
return
}
data, err := h.repo.GetPerbandinganStatusAntrean(c, req)
if err != nil {
errorResponse := baseResponse.BaseErrorResponse{
Success: false,
Code: 500,
Message: err.Error(),
}
c.JSON(http.StatusInternalServerError, errorResponse)
return
}
response := baseResponse.ToBaseResponse(
data.MapToResponse(),
true,
200,
"success get perbandingan status antrean")
c.JSON(http.StatusOK, response)
}
+22
View File
@@ -0,0 +1,22 @@
package dashboard
type ListPerbandinganStatusAntrean []PerbandinganStatusAntreanQueryResult
func (list ListPerbandinganStatusAntrean) findJumlahById(id int) int {
for _, item := range list {
if item.IdStatus == id {
return item.Jumlah
}
}
return 0
}
func (list ListPerbandinganStatusAntrean) MapToResponse() []PerbandinganStatusAntreanResponse {
return []PerbandinganStatusAntreanResponse{
{IdStatus: 1, Status: "Belum", Jumlah: list.findJumlahById(1)},
{IdStatus: 2, Status: "Selesai", Jumlah: list.findJumlahById(2)},
{IdStatus: 3, Status: "Tunda", Jumlah: list.findJumlahById(3)},
{IdStatus: 4, Status: "Batal", Jumlah: list.findJumlahById(4)},
}
}
+11
View File
@@ -27,6 +27,17 @@ type AntrianPerSubSpesialisResponse struct {
JmlAntrian int
}
type PerbandinganStatusAntreanQueryResult struct {
IdStatus int `db:"status_operasi"`
Jumlah int `db:"jumlah"`
}
type PerbandinganStatusAntreanResponse struct {
IdStatus int `json:"id"`
Jumlah int `json:"jumlah"`
Status string `json:"statust"`
}
type ListModelAntrianPerSpesialis []AntrianPerSpesialisModel
func (list ListModelAntrianPerSpesialis) ParseToResponse() []AntrianPerSpesialisResponse {
+39
View File
@@ -15,6 +15,7 @@ const TBL_SUBSPESIALIS = "daftar_subspesialis"
type IDashboardRepository interface {
GetAntrianPerKategori(c *gin.Context) ([]AntrianPerKategori, error)
GetAntrianPerSpesialis(c *gin.Context) (ListModelAntrianPerSpesialis, error)
GetPerbandinganStatusAntrean(c *gin.Context, req PeriodeDashboardRequest) (ListPerbandinganStatusAntrean, error)
}
type dashboardRepo struct {
@@ -149,3 +150,41 @@ func (r dashboardRepo) GetAntrianPerSpesialis(c *gin.Context) (ListModelAntrianP
return result, nil
}
func (r dashboardRepo) GetPerbandinganStatusAntrean(c *gin.Context, req PeriodeDashboardRequest) (ListPerbandinganStatusAntrean, error) {
var result ListPerbandinganStatusAntrean
startDate, endDate := GenerateStartEndDate(req)
query := queryUtils.DynamicQuery{
From: TBL_NAME,
Aliases: "dpo",
Fields: []queryUtils.SelectField{
{Expression: "dpo.Status_operasi", Alias: "status_operasi"},
{Expression: "COUNT(dpo.id)", Alias: "jumlah"},
},
Filters: []queryUtils.FilterGroup{
{
Filters: []queryUtils.DynamicFilter{
{Column: "dpo.Tanggal_daftar", Operator: queryUtils.OpBetween, Value: []string{startDate, endDate}},
},
},
},
GroupBy: []string{"dpo.Status_operasi"},
Sort: []queryUtils.SortField{
{Column: "dpo.Status_operasi", Order: "ASC"},
},
}
dbconn, err := r.db.GetSQLXDB(DB_NAME)
if err != nil {
return result, err
}
err = r.queryBuilder.ExecuteQuery(
c, dbconn, query, &result)
if err != nil {
return result, err
}
return result, nil
}
+23
View File
@@ -0,0 +1,23 @@
package dashboard
import "strconv"
type PeriodeDashboardRequest struct {
Year int `form:"year" binding:"required,min=1"`
Month int `form:"month" binding:"required,min=1,max=12"`
}
func GenerateStartEndDate(req PeriodeDashboardRequest) (startDate string, endDate string) {
endYear := req.Year
endMonth := req.Month + 1
if req.Month >= 12 {
req.Month = 12
endYear = req.Year + 1
endMonth = 1
}
startDate = strconv.Itoa(req.Year) + "-" + strconv.Itoa(req.Month) + "-1"
endDate = strconv.Itoa(endYear) + "-" + strconv.Itoa(endMonth) + "-1"
return startDate, endDate
}
+1
View File
@@ -12,4 +12,5 @@ func RegisterRoutes(r *gin.RouterGroup, dbService database.Service) {
r.GET("/antrian-per-kategori", dashboardHandler.GetAntrianPerKategori)
r.GET("/antrian-per-spesialis", dashboardHandler.GetAntrianPerSpesialis)
r.GET("/perbandingan-status-antrian", dashboardHandler.GetPerbandinganstatusAntrean)
}