API dashboard antrian per spesialis

This commit is contained in:
renaldybrada
2026-02-06 07:56:21 +07:00
parent 53242ae2ff
commit f230f0a6cc
7 changed files with 308 additions and 0 deletions
+59
View File
@@ -136,6 +136,31 @@ const docTemplate = `{
}
}
},
"/dashboard/antrian-per-spesialis/": {
"get": {
"tags": [
"Dashboard"
],
"summary": "Get Antrian Per Spesialis",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dashboard.AntrianPerSpesialisResponse"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/shared.BaseErrorResponse"
}
}
}
}
},
"/reference/diagnosa/": {
"get": {
"tags": [
@@ -626,6 +651,40 @@ const docTemplate = `{
}
}
},
"dashboard.AntrianPerSpesialisResponse": {
"type": "object",
"properties": {
"idSpesialis": {
"type": "integer"
},
"jmlAntrian": {
"type": "integer"
},
"spesialis": {
"type": "string"
},
"subSpesialis": {
"type": "array",
"items": {
"$ref": "#/definitions/dashboard.AntrianPerSubSpesialisResponse"
}
}
}
},
"dashboard.AntrianPerSubSpesialisResponse": {
"type": "object",
"properties": {
"idSubSpesialis": {
"type": "integer"
},
"jmlAntrian": {
"type": "integer"
},
"subSpesialis": {
"type": "string"
}
}
},
"diagnosa.DiagnosaResponse": {
"type": "object",
"properties": {
+59
View File
@@ -130,6 +130,31 @@
}
}
},
"/dashboard/antrian-per-spesialis/": {
"get": {
"tags": [
"Dashboard"
],
"summary": "Get Antrian Per Spesialis",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/dashboard.AntrianPerSpesialisResponse"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/shared.BaseErrorResponse"
}
}
}
}
},
"/reference/diagnosa/": {
"get": {
"tags": [
@@ -620,6 +645,40 @@
}
}
},
"dashboard.AntrianPerSpesialisResponse": {
"type": "object",
"properties": {
"idSpesialis": {
"type": "integer"
},
"jmlAntrian": {
"type": "integer"
},
"spesialis": {
"type": "string"
},
"subSpesialis": {
"type": "array",
"items": {
"$ref": "#/definitions/dashboard.AntrianPerSubSpesialisResponse"
}
}
}
},
"dashboard.AntrianPerSubSpesialisResponse": {
"type": "object",
"properties": {
"idSubSpesialis": {
"type": "integer"
},
"jmlAntrian": {
"type": "integer"
},
"subSpesialis": {
"type": "string"
}
}
},
"diagnosa.DiagnosaResponse": {
"type": "object",
"properties": {
+38
View File
@@ -158,6 +158,28 @@ definitions:
kategori:
type: string
type: object
dashboard.AntrianPerSpesialisResponse:
properties:
idSpesialis:
type: integer
jmlAntrian:
type: integer
spesialis:
type: string
subSpesialis:
items:
$ref: '#/definitions/dashboard.AntrianPerSubSpesialisResponse'
type: array
type: object
dashboard.AntrianPerSubSpesialisResponse:
properties:
idSubSpesialis:
type: integer
jmlAntrian:
type: integer
subSpesialis:
type: string
type: object
diagnosa.DiagnosaResponse:
properties:
keterangan:
@@ -375,6 +397,22 @@ paths:
summary: Get Antrian Per Kategori
tags:
- Dashboard
/dashboard/antrian-per-spesialis/:
get:
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/dashboard.AntrianPerSpesialisResponse'
type: array
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/shared.BaseErrorResponse'
summary: Get Antrian Per Spesialis
tags:
- Dashboard
/reference/diagnosa/:
get:
parameters:
+26
View File
@@ -38,3 +38,29 @@ func (h DashboardHandler) GetAntrianPerKategori(c *gin.Context) {
c.JSON(http.StatusOK, response)
}
// GetAntrianPerSpesialis godoc
// @Summary Get Antrian Per Spesialis
// @Tags Dashboard
// @Success 200 {object} []AntrianPerSpesialisResponse
// @Failure 500 {object} shared.BaseErrorResponse
// @Router /dashboard/antrian-per-spesialis/ [get]
func (h DashboardHandler) GetAntrianPerSpesialis(c *gin.Context) {
data, err := h.repo.GetAntrianPerSpesialis(c)
if err != nil {
errorResponse := baseResponse.BaseErrorResponse{
Success: false,
Code: 500,
Message: err.Error(),
}
c.JSON(http.StatusInternalServerError, errorResponse)
}
response := baseResponse.ToBaseResponse(
data.ParseToResponse(),
true,
200,
"success get jumlah antrian per spesialis")
c.JSON(http.StatusOK, response)
}
+61
View File
@@ -5,3 +5,64 @@ type AntrianPerKategori struct {
Kategori string `db:"Kategori" json:"kategori"`
JmlAntrian int `db:"jumlah_antrean" json:"jumlah_antrean"`
}
type AntrianPerSpesialisModel struct {
IdSpesialis int `db:"id_spesialis"`
Spesialis string `db:"Spesialis"`
IdSubSpesialis int `db:"id_subspesialis"`
SubSpesialis string `db:"Subspesialis"`
JmlAntrian int `db:"jml_antrian"`
}
type AntrianPerSpesialisResponse struct {
IdSpesialis int
Spesialis string
JmlAntrian int
SubSpesialis []AntrianPerSubSpesialisResponse
}
type AntrianPerSubSpesialisResponse struct {
IdSubSpesialis int
SubSpesialis string
JmlAntrian int
}
type ListModelAntrianPerSpesialis []AntrianPerSpesialisModel
func (list ListModelAntrianPerSpesialis) ParseToResponse() []AntrianPerSpesialisResponse {
resultMap := make(map[int]*AntrianPerSpesialisResponse)
for _, item := range list {
// check if spesialis already on resultMap
// if not exist, create antrian spesialis response
if _, ok := resultMap[item.IdSpesialis]; !ok {
resultMap[item.IdSpesialis] = &AntrianPerSpesialisResponse{
IdSpesialis: item.IdSpesialis,
Spesialis: item.Spesialis,
JmlAntrian: 0,
SubSpesialis: []AntrianPerSubSpesialisResponse{},
}
}
// add subspesialis item
resultMap[item.IdSpesialis].SubSpesialis = append(
resultMap[item.IdSpesialis].SubSpesialis,
AntrianPerSubSpesialisResponse{
IdSubSpesialis: item.IdSubSpesialis,
SubSpesialis: item.SubSpesialis,
JmlAntrian: item.JmlAntrian,
},
)
// accumulate jmlAntrian subspesialis -> total antrian spesialis
resultMap[item.IdSpesialis].JmlAntrian += item.JmlAntrian
}
// convert map -> slice
result := make([]AntrianPerSpesialisResponse, 0, len(resultMap))
for _, v := range resultMap {
result = append(result, *v)
}
return result
}
+64
View File
@@ -10,9 +10,11 @@ import (
const DB_NAME = "db_antrian"
const TBL_NAME = "data_pasien_operasi"
const TBL_SUBSPESIALIS = "daftar_subspesialis"
type IDashboardRepository interface {
GetAntrianPerKategori(c *gin.Context) ([]AntrianPerKategori, error)
GetAntrianPerSpesialis(c *gin.Context) (ListModelAntrianPerSpesialis, error)
}
type dashboardRepo struct {
@@ -85,3 +87,65 @@ func (r dashboardRepo) GetAntrianPerKategori(c *gin.Context) ([]AntrianPerKatego
return result, nil
}
func (r dashboardRepo) GetAntrianPerSpesialis(c *gin.Context) (ListModelAntrianPerSpesialis, error) {
var result ListModelAntrianPerSpesialis
query := queryUtils.DynamicQuery{
From: TBL_SUBSPESIALIS,
Aliases: "dss",
Fields: []queryUtils.SelectField{
{Expression: "ds.id", Alias: "id_spesialis"},
{Expression: "dss.id", Alias: "id_subspesialis"},
{Expression: "ds.Spesialis"},
{Expression: "dss.Subspesialis"},
{Expression: "COUNT(dpo.id)", Alias: "jml_antrian"},
},
Joins: []queryUtils.Join{
{
Type: "LEFT",
Table: "daftar_spesialis",
Alias: "ds",
OnConditions: queryUtils.FilterGroup{
Filters: []queryUtils.DynamicFilter{
{
Column: "dss.FK_daftar_spesialis_ID", Operator: queryUtils.OpEqual, Value: "ds.id",
},
},
},
},
{
Type: "LEFT",
Table: "data_pasien_operasi",
Alias: "dpo",
OnConditions: queryUtils.FilterGroup{
Filters: []queryUtils.DynamicFilter{
{
Column: "dpo.Sub_spesialis", Operator: queryUtils.OpEqual, Value: "dss.id",
},
{
Column: "dpo.Status_operasi", Operator: queryUtils.OpEqual, Value: "1",
},
}, LogicOp: "AND",
},
},
},
GroupBy: []string{"dss.id", "dss.Subspesialis", "ds.id", "ds.Spesialis"},
Sort: []queryUtils.SortField{
{Column: "ds.id"},
},
}
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
}
+1
View File
@@ -11,4 +11,5 @@ func RegisterRoutes(r *gin.RouterGroup, dbService database.Service) {
dashboardHandler := NewDashboardHandler(dashboardRepo)
r.GET("/antrian-per-kategori", dashboardHandler.GetAntrianPerKategori)
r.GET("/antrian-per-spesialis", dashboardHandler.GetAntrianPerSpesialis)
}