feat (generate-file): resume table is done

This commit is contained in:
dpurbosakti
2025-11-26 17:23:48 +07:00
parent d88d376112
commit 04add70ac5
5 changed files with 452 additions and 153 deletions
+385 -146
View File
@@ -7,26 +7,40 @@
body {
padding: 2rem 3rem;
}
table {
width: 100%;
border-collapse: collapse
}
td {
vertical-align: top;
}
.border-table, .border-table td, .border-table th {
.border-table,
.border-table td,
.border-table th {
border: 1px solid black;
}
.section-title {
.section-title {
margin-top: 1rem;
margin-bottom: 0rem;
}
.data-label {
.data-label {
width: 9rem;
}
.data-colon {
width: 0.1234rem;
.data-colon {
width: 15px; padding-left: 10px;
}
.description-label {
font-size: 0.7rem;
margin: 0;
}
</style>
</head>
@@ -60,7 +74,7 @@
</table>
<hr style="margin: 20px 0" />
<div style="
text-align: center;
font-weight: bold;
@@ -80,39 +94,39 @@
No. RM
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .MedicalRecord }}</td>
<td style="width: 7rem;">
Ruang/Klinik
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .Unit }}</td>
</tr>
<tr>
<td>
NIK
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .NIK }}</td>
<td>
Kelas
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .Class }}</td>
</tr>
<tr>
<td>
Nama
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .Name }}</td>
<td>
DPJP
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .Doctor_Name }}</td>
</tr>
<tr>
</tr>
<td style="padding: 5px 0"></td>
</tr>
@@ -121,21 +135,21 @@
Tempat/Tanggal Lahir
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .BirthPlaceDate }}</td>
</tr>
<tr>
<td>
Jenis Kelamin
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .Gender }}</td>
</tr>
<tr>
<td>
No. Telepon
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .Phone }}</td>
</tr>
</table>
@@ -165,32 +179,33 @@
Tanggal Masuk
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .StartedAt }}</td>
</tr>
<tr>
<td class="data-label">
Tanggal Keluar
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .FinishedAt }}</td>
</tr>
<tr>
<td class="data-label">
Diagnosis Masuk
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .DiagnosisIn }}</td>
</tr>
<tr>
<td class="data-label">
Diagnosis Keluar
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .DiagnosisOut }}</td>
</tr>
</table>
<table class="border-table" style="margin-top: 0.7rem;">
<table class="border-table" style="margin-top: 0.7rem; page-break-inside: avoid !important;">
<thead>
<tr>
<th style="width: 1rem;">
No
@@ -205,31 +220,46 @@
Kode ICD-10
</th>
</tr>
<tr>
<td>
1
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>
2
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>
3
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
</table>
</thead>
<tbody>
{{ $dataLen := len .Diagnosis }}
{{ if gt $dataLen 0 }}
<!-- If we have data, show all of it -->
{{ range $index, $diagnosis := .Diagnosis }}
<tr>
<td>{{ if eq $index 0 }}1{{ else if eq $index 1 }}2{{ else if eq $index 2 }}3{{ else if eq $index 3 }}4{{ else if eq $index 4 }}5{{ else }}{{ $index }}{{ end }}</td>
<td>{{ $diagnosis.DiagnosisName }}</td>
<td>{{ $diagnosis.Basis }}</td>
<td>{{ $diagnosis.ICD10 }}</td>
</tr>
{{ end }}
<!-- If data is less than 2, fill remaining rows -->
{{ if eq $dataLen 1 }}
<tr>
<td>2</td>
<td></td>
<td></td>
<td></td>
</tr>
{{ end }}
{{ else }}
<!-- If no data, show 2 empty rows -->
<tr>
<td>1</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2</td>
<td></td>
<td></td>
<td></td>
</tr>
{{ end }}
</tbody>
</table>
@@ -237,50 +267,54 @@
<h4 class="section-title">Kajian Awal Medis</i></h4>
<h4 class="section-title">Kajian Awal Medis</i></h4>
<p style="
font-size: 0.7rem;
margin-top: 0rem;
margin-bottom: 0.4rem;
"><i>(Diisi oleh Dokter Penanggung Jawab Pelayanan)</i></p>
"><i>(Diisi oleh Dokter Penanggung Jawab Pelayanan)</i></p>
<table>
<tr>
<td class="data-label">
Keluhan Utama
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .MainComplaint }}</td>
</tr>
<tr>
<td class="data-label">
Riwayat Penyakit
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .MedicalHistory }}</td>
</tr>
<tr>
<td class="data-label">
Pemeriksaan Fisik & Keadaan Umum
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .PhysicalExamination }}</td>
</tr>
</table>
<h4 class="section-title">Pemeriksaan Penunjang</i></h4>
<h4 class="section-title">Pemeriksaan Penunjang</i></h4>
<table>
<tr>
<td class="data-label">
Pemeriksaan
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .SupportingExamination }}</td>
</tr>
</table>
<h4 class="section-title">Tindakan Medis</i></h4>
<table class="border-table" style="margin-top: 0.4rem;">
<table style="page-break-inside: avoid !important;"></table>
<tr>
<td>
<h4 class="section-title">Tindakan Medis</i></h4>
<table class="border-table" style="margin-top: 0.4rem;">
<thead>
<tr>
<th style="width: 1rem;">
No
@@ -295,31 +329,47 @@
Kode ICD 9-CM
</th>
</tr>
<tr>
<td>
1
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>
2
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>
3
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
</table>
</thead>
<tbody>
{{ $dataLen := len .MedicalActions }}
{{ if gt $dataLen 0 }}
<!-- If we have data, show all of it -->
{{ range $index, $action := .MedicalActions }}
<tr>
<td>{{ if eq $index 0 }}1{{ else if eq $index 1 }}2{{ else if eq $index 2 }}3{{ else if eq $index 3 }}4{{ else if eq $index 4 }}5{{ else }}{{ $index }}{{ end }}</td>
<td>{{ $action.Action }}</td>
<td>{{ $action.Basis }}</td>
<td>{{ $action.ICD9 }}</td>
</tr>
{{ end }}
<!-- If data is less than 2, fill remaining rows -->
{{ if eq $dataLen 1 }}
<tr>
<td>2</td>
<td></td>
<td></td>
<td></td>
</tr>
{{ end }}
{{ else }}
<!-- If no data, show 2 empty rows -->
<tr>
<td>1</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>2</td>
<td></td>
<td></td>
<td></td>
</tr>
{{ end }}
</tbody>
</table>
<table style="margin: 0.7rem 0;">
<tr>
@@ -327,51 +377,53 @@
Tindakan Medis
</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .MedicalAction }}</td>
</tr>
</table>
<table style="page-break-inside: avoid !important;">
<tr>
<td>
<h4 class="section-title">Konsultasi</i></h4>
</table>
<table class="border-table" style="margin-top: 0.4rem;">
<thead>
<tr>
<th style="width: 1rem;">No</th>
<th>Konsultasi</th>
<th>Jawaban Konsultasi</th>
</tr>
</thead>
<tbody>
{{ $dataLen := len .Consultations }}
{{ if gt $dataLen 0 }}
<!-- If we have data, show all of it -->
{{ range $index, $consultation := .Consultations }}
<tr>
<td>{{ if eq $index 0 }}1{{ else if eq $index 1 }}2{{ else if eq $index 2 }}3{{ else if eq $index 3 }}4{{ else if eq $index 4 }}5{{ else }}{{ $index }}{{ end }}</td>
<td>{{ $consultation.Consultation }}</td>
<td>{{ $consultation.ConsultationAnswer }}</td>
</tr>
{{ end }}
<!-- If data is less than 2, fill remaining rows -->
{{ if eq $dataLen 1 }}
<tr><td>2</td><td></td><td></td></tr>
{{ end }}
{{ else }}
<!-- If no data, show 2 empty rows -->
<tr><td>1</td><td></td><td></td></tr>
<tr><td>2</td><td></td><td></td></tr>
{{ end }}
</tbody>
</table>
</td>
</tr>
<h4 class="section-title">Konsultasi</i></h4>
<table class="border-table" style="margin-top: 0.4rem;">
<tr>
<th style="width: 1rem;">
No
</th>
<th>
Konsultasi
</th>
<th>
Jawaban Konsultasi
</th>
</tr>
<tr>
<td>
1
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>
2
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>
3
</td>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
</table>
<h4 class="section-title">Terapi</i></h4>
<h4 class="section-title">Terapi</i></h4>
<table>
<tr>
<td class="data-label">
@@ -379,54 +431,241 @@
</td>
<td class="data-colon">: </td>
<td>
Replace
{{ .Allergy}}
</td>
</tr>
</table>
<h4 class="section-title" style="margin-top: 3rem;">Obat yang diberikan</i></h4>
<table class="border-table" style="margin-top: 0.4rem;">
<table style="page-break-inside: avoid !important;">
<tr>
<th>
Terapi (Farmakologi & Non Farmakologi) Selawa Perawatan
</th>
<th>
Terapi (Farmakologi & Non Farmakologi) Selawa Pulang
</th>
</tr>
<tr>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
</tr>
<tr>
<td>{{ .Repalcable }}</td>
<td>{{ .Repalcable }}</td>
<td>
<h4 class="section-title" style="margin-top: 3rem;">Obat yang diberikan</i></h4>
<table class="border-table" style="margin-top: 0.4rem;">
<tr>
<th>
Terapi (Farmakologi & Non Farmakologi) Selawa Perawatan
</th>
<th>
Terapi (Farmakologi & Non Farmakologi) Selawa Pulang
</th>
</tr>
<tr>
<td>{{ .NIK }}</td>
<td>{{ .NIK }}</td>
</tr>
<tr>
<td>{{ .NIK }}</td>
<td>{{ .NIK }}</td>
</tr>
<tr>
<td>{{ .NIK }}</td>
<td>{{ .NIK }}</td>
</tr>
</table>
</td>
</tr>
</table>
<h4 class="section-title">Kondisi saat Pulang</i></h4>
<h4 class="section-title">Kondisi saat Pulang</i></h4>
<table>
<tr>
<td class="data-label">
Keluhan Utama
</td>
<td class="data-label">Kesadaran</td>
<td class="data-colon">: </td>
<td>{{ .Repalcable }}</td>
<td>{{ .ConsciousnessLevel }}</td>
</tr>
<tr>
<td class="data-label">
Tanda Vital
<p class="description-label"><i>Vital sign</i></p>
</td>
<td class="data-colon">:</td>
</tr>
<tr>
<td colspan="3">
<table>
<tr>
<td style="width: 50%;">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<td class="data-label" style="text-align: right;"> Tekanan Darah
<p class="description-label"><i>Blood Pressure</i></p>
</td>
<td class="data-colon">: </td>
<td>{{ .BloodPressure }} mmHg</td>
<td>
</tr>
<tr>
<td>
<td class="data-label" style="text-align: right;">Suhu
<p class="description-label"><i>Temperatur</i></p>
</td>
</td>
<td class="data-colon">: </td>
<td>{{ .BodyTemperature }} C</td>
<td>
</tr>
<tr>
<td>
<td class="data-label" style="text-align: right;">Nadi
<p class="description-label"><i>Pulse</i></p>
</td>
<td class="data-colon">: </td>
<td>{{ .HeartRate }} x/Menit</td>
</td>
</tr>
</table>
</td>
<td>
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<td class="data-label" style="text-align: right;">Frekuensi Nafas
<p class="description-label"><i>Respiratory rate</i></p>
</td>
</td>
<td class="data-colon">: </td>
<td>{{ .RespirationRate }}</td>
</td>
</tr>
<tr>
<td>
<td class="data-label" style="text-align: right;">Skala Nyeri
<p class="description-label"><i>Pain Scale</i></p>
</td>
</td>
<td class="data-colon">: </td>
<td>{{ .PainScale }}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="data-label">Keadaan Keluar</td>
<td class="data-colon">: </td>
<td>{{ .ConditionOnDischarge }}</td>
</tr>
<tr>
<td class="data-label">Cara Keluar
<p class="description-label"><i>Patient discharge of hospital</i></p>
</td>
<td class="data-colon">:</td>
<td>{{ .DischargeMethod }}</td>
</tr>
</table>
<table style="
margin-top: 1rem;
">
<tr>
<td>
<h4 class="description-label">INSTRUKSI UNTUK TINDAK LANJUT</h4>
<p class="description-label"><i>Follow up Consultation to</i></p>
</td>
<td class="">
<h4 class="description-label">Kontrol Ke</h4>
<p class="description-label"><i>Follow up Consultation to</i></p>
</td>
<td class="">
<table>
<tr>
<td style="width: 4rem;">Fasyankes</td>
<td class="data-colon">: </td>
<td>{{ .NIK }}</td>
</tr>
<tr>
<td>Tanggal</td>
<td>: </td>
<td>{{ .NIK }}</td>
</tr>
<tr>
<td>Klinik</td>
<td>: </td>
<td>{{ .NIK }}</td>
</tr>
</table>
</td>
</tr>
<tr><td style="height: 1rem;"></td></tr>
<tr>
<td class="">
<h4 class="description-label">Dalam keadaan darurat dapat menghubungi</h4>
<p class="description-label"><i>In case of emergencycontact</i></p>
</td>
<td class="">
<h4 class="description-label">IGD</h4>
<p class="description-label"><i>(Accident & Emergency Instalation)</i></p>
</td>
<td class="">
<table>
<tr>
<td style="width: 4rem;">Telepon
<p class="description-label"><i>Phone</i></p>
</td>
<td class="data-colon">: </td>
<td>(0341) 362101</td>
</tr>
</table>
</td>
</tr>
<tr><td style="height: 1rem;"></td></tr>
<tr>
<td class="">
<h4 class="description-label">EDUKASI & RENCANA TINDAK LANJUT</h4>
<p class="description-label"><i>Follow up plan (if necessary)</i></p>
</td>
<td class="">
<h4 class="description-label"></h4>
<p class="description-label"><i>(bila diperlukan)</i></p>
</td>
</tr>
</table>
<table style="margin-top: 3rem;">
<tr>
<td></td>
<td style="width: 15rem;">
Malang, {{ .Date }}<br>
Dokter Penanggung Jawab Pelayanan
</td>
</tr>
<tr><td style="height: 7rem;"></td></tr>
<tr>
<td></td>
<td style="width: 15rem;">
({{ .Doctor_Name }})
</td>
</tr>
</table>
<div style="height: 3rem;"></div>
<hr style="margin: 20px 0" />
<p>*) Data dapat berubah setelah pasien pulang sesuai prosedur</p>
</body>
</html>
+5 -5
View File
@@ -96,7 +96,7 @@ type Assessment struct {
StartedAt *time.Time `json:"startedAt`
FinishedAt *time.Time `json:"finishedAt`
Doctor_Code string `json:"doctor_code`
DiagnosisIn string `json:"diagnosesIn`
DiagnosisIn string `json:"diagnosisIn`
AmbulatoryIndication string `json:"ambulatoryIndication"`
MainComplaint string `json:"mainComplaint"`
PhysicalExamination string `json:"physicalExamination"`
@@ -106,13 +106,13 @@ type Assessment struct {
type Diagnosis struct {
PrimaryDiagnosis DiagnosisEntry `json:"primaryDiagnosis"`
SecondaryDiagnoses []DiagnosisEntry `json:"secondaryDiagnoses"`
SecondaryDiagnosis []DiagnosisEntry `json:"secondaryDiagnosis"`
}
type DiagnosisEntry struct {
Diagnosis string `json:"diagnosis"`
ICD10 string `json:"icd_10"`
Basis string `json:"basis"` // Clinical basis of diagnosis / dasar diagnosa
DiagnosisName string `json:"diagnosis"`
ICD10 string `json:"icd_10"`
Basis string `json:"basis"` // Clinical basis of diagnosis / dasar diagnosa
}
type Action struct {
@@ -52,6 +52,10 @@ func GetDetail(w http.ResponseWriter, r *http.Request) {
}
func Update(w http.ResponseWriter, r *http.Request) {
authInfo, err := pa.GetAuthInfo(r)
if err != nil {
rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil)
}
id := rw.ValidateInt(w, "id", r.PathValue("id"))
if id <= 0 {
return
@@ -62,11 +66,16 @@ func Update(w http.ResponseWriter, r *http.Request) {
return
}
dto.Id = uint(id)
dto.AuthInfo = *authInfo
res, err := u.Update(dto)
rw.DataResponse(w, res, err)
}
func Delete(w http.ResponseWriter, r *http.Request) {
authInfo, err := pa.GetAuthInfo(r)
if err != nil {
rw.WriteJSON(w, http.StatusUnauthorized, d.IS{"message": err.Error()}, nil)
}
id := rw.ValidateInt(w, "id", r.PathValue("id"))
if id <= 0 {
return
@@ -74,6 +83,7 @@ func Delete(w http.ResponseWriter, r *http.Request) {
dto := e.DeleteDto{}
dto.Id = uint(id)
dto.AuthInfo = *authInfo
res, err := u.Delete(dto)
rw.DataResponse(w, res, err)
}
@@ -250,8 +250,28 @@ func generateResume(input GenerateDto, event pl.Event, tx *gorm.DB) (*ResponseDt
}
}
templateData, err := generateResumeTemplateData(*r, event, tx)
if err != nil {
return nil, err
}
input.FormatType = erc.DFTCPDF
input.TemplateName = TDNR
input.Encounter_Id = r.Encounter_Id
// generate file
urlPub, err := generateFile(input, templateData)
if err != nil {
return nil, err
}
r.FileUrl = &urlPub
if err := tx.Save(&r).Error; err != nil {
return nil, err
}
response := ResponseDto{
FileUrl: "",
FileUrl: urlPub,
}
return &response, nil
@@ -264,7 +284,6 @@ func generateResumeTemplateData(resume er.Resume, event pl.Event, tx *gorm.DB) (
if err != nil {
return nil, err
}
fmt.Println(encounter)
// map template data
rData := er.ValueDto{}
@@ -293,6 +312,24 @@ func generateResumeTemplateData(resume er.Resume, event pl.Event, tx *gorm.DB) (
templateData.Doctor_Name = resume.Doctor.Employee.Person.FullName()
templateData.StartedAt = *pc.TimeToStringWithFormat(encounter.StartedAt, "")
templateData.FinishedAt = *pc.TimeToStringWithFormat(encounter.FinishedAt, "")
templateData.DiagnosisIn = rData.Assessment.DiagnosisIn
templateData.Diagnosis = rData.Diagnosis.SecondaryDiagnosis
templateData.MainComplaint = rData.Assessment.MainComplaint
templateData.MedicalHistory = rData.Assessment.MedicalHistory
templateData.PhysicalExamination = rData.Assessment.PhysicalExamination
templateData.SupportingExamination = rData.Supporting.Notes
templateData.MedicalActions = rData.Action.AdditionalActions
templateData.MedicalAction = rData.Action.MedicalActions
templateData.Consultations = rData.Consultation.Consultations
templateData.Allergy = rData.Pharmacy.AllergySpecialConditions
templateData.ConsciousnessLevel = rData.Discharge.ConsciousnessLevel
templateData.BloodPressure = fmt.Sprintf("%.0f/%.0f", rData.Discharge.BloodPressureSystolic, rData.Discharge.BloodPressureDiastolic)
templateData.BodyTemperature = rData.Discharge.BodyTemperature
templateData.RespirationRate = rData.Discharge.RespirationRate
templateData.HeartRate = rData.Discharge.HeartRate
templateData.PainScale = rData.Discharge.PainScale
templateData.ConditionOnDischarge = rData.Management.ConditionOnDischarge
templateData.DischargeMethod = rData.Management.DischargeMethod
return &templateData, nil
}
@@ -57,6 +57,18 @@ type ResumePDF struct {
MedicalAction string
Consultations []er.ConsultationEntry
Allergy string
ConsciousnessLevel string
BloodPressure string
BodyTemperature float64
RespirationRate float64
HeartRate float64
PainScale int
ConditionOnDischarge string
DischargeMethod string
// fasyankes
// date
// klinik
Date string
}
type GenerateDto struct {
@@ -110,6 +122,7 @@ type TemplateDocsName string
const (
TDNGC TemplateDocsName = "general-consent.html"
TDNCL TemplateDocsName = "control-letter.html"
TDNR TemplateDocsName = "resume.html"
)
func (v VclaimControlLetter) generateTemplateData() ControlLetterPDF {