From c6bb55862c62acede49953e6665c45cf9b2bd331 Mon Sep 17 00:00:00 2001 From: Dr Masroor Ehsan Date: Sun, 12 Jan 2025 13:17:35 +0600 Subject: [PATCH] wip --- .../Controllers/Staff/ReportController.php | 13 +- app/Models/StudyReport.php | 5 + app/Services/Export/Exporters.php | 2 +- app/Services/Report/ReportManager.php | 2 +- app/Services/Report/StampService.php | 5 + .../reports/viewer/html-report.blade.php | 80 +++++++--- .../staff/reports/viewer/layout.blade.php | 48 +++++- src/phpdocx/src/Transform/TransformDoc.php | 4 +- src/phpdocx/src/Transform/TransformDocAdv.php | 2 +- .../src/Transform/TransformDocAdvDOMPDF.php | 68 ++++----- .../src/Transform/TransformDocAdvHTML.php | 78 +++++----- .../TransformDocAdvHTMLDOMPDFPlugin.php | 6 +- .../TransformDocAdvHTMLDefaultPlugin.php | 6 +- .../TransformDocAdvHTMLTCPDFPlugin.php | 6 +- .../Transform/TransformDocAdvLibreOffice.php | 6 +- .../src/Transform/TransformDocAdvMSWord.php | 2 +- .../Transform/TransformDocAdvOpenOffice.php | 144 +++++++++--------- .../src/Transform/TransformDocAdvPDF.php | 66 ++++---- 18 files changed, 313 insertions(+), 230 deletions(-) diff --git a/app/Http/Controllers/Staff/ReportController.php b/app/Http/Controllers/Staff/ReportController.php index 5875fa3..5ac12a2 100644 --- a/app/Http/Controllers/Staff/ReportController.php +++ b/app/Http/Controllers/Staff/ReportController.php @@ -7,6 +7,7 @@ use App\Http\Requests\StoreReportRequest; use App\Models\Study; use App\Services\Report\ReportManager; +use App\Services\Report\StampService; class ReportController extends HashidControllerBase { @@ -80,9 +81,17 @@ public function view(string $uuid) { ReportManager::ensureDownloadAccess(); $manager = ReportManager::fromReport($uuid); - $title = 'View Report'; + $title = 'Report Quick View ' . $manager->getStudy()->getPatientDemographic(); $report = $manager->getReport(); + if ($report->isFinalized()) { + $stamper = new StampService($report->read_by_id); + $signature = $stamper->hasSignatureImage() ? $stamper->signatureImageUrl() : null; + $notice = null; + } else { + $signature = null; + $notice = 'This is a preliminary radiology interpretation that has not been finalized or approved by a radiologist. It is not intended for diagnostic purposes.'; + } - return view('staff.reports.viewer.html-report', compact('report', 'title')); + return view('staff.reports.viewer.html-report', compact('report', 'title', 'signature', 'notice')); } } diff --git a/app/Models/StudyReport.php b/app/Models/StudyReport.php index 5ba450e..f32e5d0 100644 --- a/app/Models/StudyReport.php +++ b/app/Models/StudyReport.php @@ -126,6 +126,11 @@ public function canEdit(User|int|null $user = null): bool return false; } + public function isFinalized(): bool + { + return $this->report_status->value >= ReportStatus::Finalized->value; + } + /** * @return array */ diff --git a/app/Services/Export/Exporters.php b/app/Services/Export/Exporters.php index 91edc28..e55d12c 100644 --- a/app/Services/Export/Exporters.php +++ b/app/Services/Export/Exporters.php @@ -7,8 +7,8 @@ use App\Models\StudyReport; use app\Services\Export\Formats\HtmlExport; use app\Services\Export\Formats\PdfExport; -use app\Services\Export\Formats\Word2007Export; use app\Services\Export\Formats\Word2003Export; +use app\Services\Export\Formats\Word2007Export; final readonly class Exporters { diff --git a/app/Services/Report/ReportManager.php b/app/Services/Report/ReportManager.php index ab89cd6..fabadd6 100644 --- a/app/Services/Report/ReportManager.php +++ b/app/Services/Report/ReportManager.php @@ -21,7 +21,7 @@ public static function make(int $study_id, ?StudyReport $report = null): static public static function fromReport(string $uuid): static { - $report = StudyReport::accession($uuid)->select(['id', 'study_id', 'file_path', 'created_at'])->firstOrFail(); + $report = StudyReport::accession($uuid)->firstOrFail(); return static::make($report->study_id, $report); } diff --git a/app/Services/Report/StampService.php b/app/Services/Report/StampService.php index fac7e47..f574ef8 100644 --- a/app/Services/Report/StampService.php +++ b/app/Services/Report/StampService.php @@ -25,4 +25,9 @@ public function signatureImagePath(): string { return Storage::disk('public')->path($this->user->radiologistProfile?->signature_image_path); } + + public function signatureImageUrl(): string + { + return Storage::disk('public')->url($this->user->radiologistProfile?->signature_image_path); + } } diff --git a/resources/views/staff/reports/viewer/html-report.blade.php b/resources/views/staff/reports/viewer/html-report.blade.php index 11b75b2..89f1da2 100644 --- a/resources/views/staff/reports/viewer/html-report.blade.php +++ b/resources/views/staff/reports/viewer/html-report.blade.php @@ -1,23 +1,24 @@ @extends('staff.reports.viewer.layout') @section('content') -
-
-
-
-
- {{ $report->study->modality }} Report -
-

- {{ $report->study->study_description }} -

-
-
-
-
+
-
-
+ @isset($notice) +
+
+ +
+
+ @endisset + +
@@ -42,14 +43,45 @@
-
-
+ -
-
-
- {!! $report->getContent() !!} +
+
+
+
+ {{ $report->study->modality }} Report +
+

+ {{ $report->study->study_description }} +

+
-
-
+ + +
+
+
+ {!! $report->getContent() !!} +
+
+
+ + @isset($signature) +
+
+ +
+
+ @endisset +
@endsection + +@push('footer') +
+
+ + {{ config('app.name') }} © {{ now()->year }} Dr. Masroor Ehsan + +
+
+@endpush diff --git a/resources/views/staff/reports/viewer/layout.blade.php b/resources/views/staff/reports/viewer/layout.blade.php index 67b40ba..cca3ea9 100644 --- a/resources/views/staff/reports/viewer/layout.blade.php +++ b/resources/views/staff/reports/viewer/layout.blade.php @@ -4,10 +4,14 @@ - + + {{ $title }} @stack('header') - + - @yield('content') +@yield('content') - @stack('footer') +@stack('footer') diff --git a/src/phpdocx/src/Transform/TransformDoc.php b/src/phpdocx/src/Transform/TransformDoc.php index 5a16f77..d6e1d26 100644 --- a/src/phpdocx/src/Transform/TransformDoc.php +++ b/src/phpdocx/src/Transform/TransformDoc.php @@ -46,7 +46,7 @@ class TransformDoc */ public function __construct() { - + } /** @@ -56,7 +56,7 @@ public function __construct() */ public function __destruct() { - + } /** diff --git a/src/phpdocx/src/Transform/TransformDocAdv.php b/src/phpdocx/src/Transform/TransformDocAdv.php index e44a08a..2907a34 100644 --- a/src/phpdocx/src/Transform/TransformDocAdv.php +++ b/src/phpdocx/src/Transform/TransformDocAdv.php @@ -50,7 +50,7 @@ abstract public function transformDocument($source, $target, $options = array()) /** * Check if the extension if supproted - * + * * @param string $fileExtension * @param array $supportedExtensions * @return array files extensions diff --git a/src/phpdocx/src/Transform/TransformDocAdvDOMPDF.php b/src/phpdocx/src/Transform/TransformDocAdvDOMPDF.php index d3d0e57..fd5b0c2 100644 --- a/src/phpdocx/src/Transform/TransformDocAdvDOMPDF.php +++ b/src/phpdocx/src/Transform/TransformDocAdvDOMPDF.php @@ -777,12 +777,12 @@ protected function addDefaultStyles() if ($docDefaultsStylesPpr) { $css .= 'p, h1, h2, h3, h4, h5, h6, ul, ol {' . $this->addPprStyles($docDefaultsStylesPpr, true) . '}'; } - + // addRprStyles if ($docDefaultsStylesRpr) { $css .= 'span {' . $this->addRprStyles($docDefaultsStylesRpr) . '}'; } - + // default styles query by w:default="1" $docDefaultsStyles = $xpathStyles->query('//w:style[@w:default="1"]'); foreach ($docDefaultsStyles as $docDefaultsStyle) { @@ -1110,7 +1110,7 @@ protected function getCellStyles($styles) $cellStyles.= 'border-bottom: ' . $elementWTcBordersBottom->item(0)->getAttribute('w:sz') . ' ' . $borderStyle . ' #' . $elementWTcBordersBottom->item(0)->getAttribute('w:color') . ';'; $borderStylesCell .= 'border-bottom: ' . $elementWTcBordersBottom->item(0)->getAttribute('w:sz') . ' ' . $borderStyle . ' #' . $elementWTcBordersBottom->item(0)->getAttribute('w:color') . ';'; } - + // left $elementWTcBordersLeft = $elementWTcBorders->item(0)->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'left'); if ($elementWTcBordersLeft->length > 0) { @@ -1187,7 +1187,7 @@ protected function getNumberingLvlText($id, $level) if ($elementNum != '') { // get w:abstractNumId used to set the numbering styles $abstractNumId = $elementNum->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'abstractNumId')->item(0)->getAttribute('w:val'); - + // get the style of the w:abstractNum related to w:abstractNumId $elementAbstractNumStart = $xpathNumbering->query( '//w:abstractNum[@w:abstractNumId="' . $abstractNumId . '"]' . @@ -1197,7 +1197,7 @@ protected function getNumberingLvlText($id, $level) return $elementAbstractNumStart->getAttribute('w:val'); } - + // style not found, return 1 as default value return '1'; } @@ -1226,7 +1226,7 @@ protected function getNumberingStart($id, $level) if ($elementNum != '') { // get w:abstractNumId used to set the numbering styles $abstractNumId = $elementNum->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'abstractNumId')->item(0)->getAttribute('w:val'); - + // get the style of the w:abstractNum related to w:abstractNumId $elementAbstractNumStart = $xpathNumbering->query( '//w:abstractNum[@w:abstractNumId="' . $abstractNumId . '"]' . @@ -1240,7 +1240,7 @@ protected function getNumberingStart($id, $level) return '1'; } } - + // style not found, return 1 as default value return '1'; } @@ -1277,7 +1277,7 @@ protected function getNumberingStyles($id, $level) return $elementAbstractNumLvl; } - + // style not found return null; } @@ -1304,7 +1304,7 @@ protected function getNumberingType($id, $level) if ($elementNum != '') { // get w:abstractNumId used to set the numbering styles $abstractNumId = $elementNum->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'abstractNumId')->item(0)->getAttribute('w:val'); - + // get the style of the w:abstractNum related to w:abstractNumId $elementAbstractNumFmt = $xpathNumbering->query( '//w:abstractNum[@w:abstractNumId="' . $abstractNumId . '"]' . @@ -1314,7 +1314,7 @@ protected function getNumberingType($id, $level) return $elementAbstractNumFmt->getAttribute('w:val'); } - + // style not found return null; } @@ -1430,7 +1430,7 @@ protected function getTableStyles($styles) $tableStyles.= 'border-bottom: ' . $this->htmlPlugin->transformSizes($elementWTblBordersBottom->item(0)->getAttribute('w:sz'), 'eights') . ' ' . $borderStyle . ' #' . $this->htmlPlugin->transformColors($elementWTblBordersBottom->item(0)->getAttribute('w:color')) . ';'; $borderStylesTable .= 'border-bottom: ' . $this->htmlPlugin->transformSizes($elementWTblBordersBottom->item(0)->getAttribute('w:sz'), 'eights') . ' ' . $borderStyle . ' #' . $this->htmlPlugin->transformColors($elementWTblBordersBottom->item(0)->getAttribute('w:color')) . ';'; } - + // left $elementWTblBordersLeft = $elementWTblBorders->item(0)->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'left'); if ($elementWTblBordersLeft->length > 0) { @@ -1668,7 +1668,7 @@ protected function getRelationshipContent($id) } else { $relsContent = $this->docxStructure->getContent('word/_rels/document.xml.rels'); } - + $xmlDocumentRels = new \DOMDocument(); $xmlDocumentRels->loadXML($relsContent); @@ -1681,7 +1681,7 @@ protected function getRelationshipContent($id) if (!$elementId || !$elementId->hasAttribute('Target')) { return null; } - + return $elementId->getAttribute('Target'); } @@ -1919,7 +1919,7 @@ protected function transformW_DRAWING($childNode, $nodeClass) $this->css[$nodeClass] .= 'display: inline;'; } else { // anchor tag - + // wrapSquare $elementWrapSquare = $childNode->getElementsByTagNameNS('http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing', 'wrapSquare'); if ($elementWrapSquare->length > 0) { @@ -1993,12 +1993,12 @@ protected function transformW_ENDNOTEREFERENCE($childNode, $nodeClass) $return = ''; $endnotesIndex = count($this->endnotesIndex) + 1; - while ($endnotesIndex > 0) { + while ($endnotesIndex > 0) { foreach ($table as $rom => $arb) { - if ($endnotesIndex >= $arb) { - $endnotesIndex -= $arb; - $return .= $rom; - break; + if ($endnotesIndex >= $arb) { + $endnotesIndex -= $arb; + $return .= $rom; + break; } } } @@ -2240,7 +2240,7 @@ protected function transformW_P($childNode, $nodeClass) } // handle tag - + // default element $elementTag = $this->htmlPlugin->getTag('paragraph'); @@ -2253,7 +2253,7 @@ protected function transformW_P($childNode, $nodeClass) // numbering tag if (is_array($this->numberingParagraph)) { // handle as p tags - + // handle numbering in paragraph $numPrTag = $childNode->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'numPr'); // handle numbering in pStyle @@ -2295,7 +2295,7 @@ protected function transformW_P($childNode, $nodeClass) $this->numberingParagraph['level'] = $numberingLevel; $this->numberingParagraph['numId'] = $numIdTag->item(0)->getAttribute('w:val'); - + switch ($numberingStyle) { case 'bullet': // default value @@ -2303,7 +2303,7 @@ protected function transformW_P($childNode, $nodeClass) if ($listLvlText == 'o') { $this->prependTValue = '◦' . ' '; } - break; + break; case 'decimal': // iterate numberLevel to handle level list when displaying sublevels such as 1.1. 1.2 for ($i = $numberingLevel; $i >= 0; $i--) { @@ -2517,7 +2517,7 @@ protected function transformW_P($childNode, $nodeClass) } } } - + // remove extra , and . before adding it to the HTML $nodeClassHTML = str_replace(array(',', '.'), '', $nodeClass); @@ -2593,7 +2593,7 @@ protected function transformW_P($childNode, $nodeClass) } if ($closeNewList === true) { unset($this->listStartValues[$numIdTag->item(0)->getAttribute('w:val')]); - for ($iClose = 0; $iClose < $iterationListClose; $iClose++) { + for ($iClose = 0; $iClose < $iterationListClose; $iClose++) { $this->html .= ''; } } @@ -2659,7 +2659,7 @@ protected function transformW_R($childNode, $nodeClass) $this->html = str_replace('{{ CLASS_COMPLEX_FIELD }}', $nodeClass, $this->html); } } - + // remove extra , and . before adding it to the HTML $nodeClassHTML = str_replace(array(',', '.'), '', $nodeClass); @@ -2841,7 +2841,7 @@ protected function transformW_TBL($childNode, $nodeClass) } } - // cells + // cells $xpathDOMXPathWTblTrTc = new \DOMXPath($elementWTblTr->ownerDocument); $xpathDOMXPathWTblTrTc->registerNamespace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); $elementsWTblTrTc = $xpathDOMXPathWTblTrTc->query('w:tc|w:sdt', $elementWTblTr); @@ -2927,7 +2927,7 @@ protected function transformW_TBL($childNode, $nodeClass) if (!empty($cellPadding)) { $this->css[$nodeTdClass] .= $cellPadding; } - + // cell properties $elementWTblTrTcTcpr = $elementWTblTrTc->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'tcPr'); if ($elementWTblTrTcTcpr->length > 0) { @@ -3060,16 +3060,16 @@ protected function transformIntegerToRoman($value) { $table = array('m' => 1000, 'cm' => 900, 'd' => 500, 'cd' => 400, 'c' => 100, 'xc' => 90, 'l' => 50, 'xl' => 40, 'x' => 10, 'ix' => 9, 'v' => 5, 'iv' => 4, 'i' => 1); $return = ''; - while ($value > 0) { + while ($value > 0) { foreach ($table as $rom => $arb) { - if ($value >= $arb) { - $value -= $arb; - $return .= $rom; - break; + if ($value >= $arb) { + $value -= $arb; + $return .= $rom; + break; } } } - + return $return; } diff --git a/src/phpdocx/src/Transform/TransformDocAdvHTML.php b/src/phpdocx/src/Transform/TransformDocAdvHTML.php index 22331c0..d095771 100644 --- a/src/phpdocx/src/Transform/TransformDocAdvHTML.php +++ b/src/phpdocx/src/Transform/TransformDocAdvHTML.php @@ -235,7 +235,7 @@ public function transform(TransformDocAdvHTMLPlugin $htmlPlugin, $options = arra $this->html = ''; } $this->html = ''; - + $footersContents = $this->docxStructure->getContentByType('footers'); $this->target = 'footers'; foreach ($footersContents as $footerContent) { @@ -389,7 +389,7 @@ public function transform(TransformDocAdvHTMLPlugin $htmlPlugin, $options = arra /** * Iterate the contents and transform them * - * @param + * @param * @param array $options * Values: * 'javaScriptAtTop' => default as false. If true add JS in the head tag. @@ -738,7 +738,7 @@ protected function addRprStyles($node) } else if ($rprStyle->hasAttribute('w:cs')) { $fontFamily = $rprStyle->getAttribute('w:cs'); } - + $styles .= 'font-family: "' . $fontFamily. '";'; break; case 'w:shd': @@ -860,7 +860,7 @@ protected function addDefaultStyles() if ($docDefaultsStylesPpr) { $css .= 'p, h1, h2, h3, h4, h5, h6, ul, ol {' . $this->addPprStyles($docDefaultsStylesPpr) . '}'; } - + // addRprStyles if ($docDefaultsStylesRpr) { $css .= 'span {' . $this->addRprStyles($docDefaultsStylesRpr) . '}'; @@ -1033,7 +1033,7 @@ protected function getCellStyles($styles) $cellStyles .= 'border-bottom: none;'; $borderStylesCell .= 'border-bottom: none;'; } - + // left $elementWTcBordersLeft = $elementWTcBorders->item(0)->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'left'); if ($elementWTcBordersLeft->length > 0) { @@ -1120,7 +1120,7 @@ protected function getNumberingLvlText($id, $level) if ($elementNum != '') { // get w:abstractNumId used to set the numbering styles $abstractNumId = $elementNum->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'abstractNumId')->item(0)->getAttribute('w:val'); - + // get the style of the w:abstractNum related to w:abstractNumId $elementAbstractNumStart = $xpathNumbering->query( '//w:abstractNum[@w:abstractNumId="' . $abstractNumId . '"]' . @@ -1130,7 +1130,7 @@ protected function getNumberingLvlText($id, $level) return $elementAbstractNumStart->getAttribute('w:val'); } - + // style not found, return 1 as default value return '1'; } @@ -1159,7 +1159,7 @@ protected function getNumberingStart($id, $level) if ($elementNum != '') { // get w:abstractNumId used to set the numbering styles $abstractNumId = $elementNum->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'abstractNumId')->item(0)->getAttribute('w:val'); - + // get the style of the w:abstractNum related to w:abstractNumId $elementAbstractNumStart = $xpathNumbering->query( '//w:abstractNum[@w:abstractNumId="' . $abstractNumId . '"]' . @@ -1173,7 +1173,7 @@ protected function getNumberingStart($id, $level) return '1'; } } - + // style not found, return 1 as default value return '1'; } @@ -1212,7 +1212,7 @@ protected function getNumberingStyles($id, $level) return $elementAbstractNumLvl; } - + // style not found return null; } @@ -1241,19 +1241,19 @@ protected function getNumberingType($id, $level) if ($elementNum != '') { // get w:abstractNumId used to set the numbering styles $abstractNumId = $elementNum->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'abstractNumId')->item(0)->getAttribute('w:val'); - + // get the style of the w:abstractNum related to w:abstractNumId $elementAbstractNumFmt = $xpathNumbering->query( '//w:abstractNum[@w:abstractNumId="' . $abstractNumId . '"]' . '/w:lvl[@w:ilvl="' . $level . '"]' . '/w:numFmt' )->item(0); - + if ($elementAbstractNumFmt != null) { return $elementAbstractNumFmt->getAttribute('w:val'); } } - + // style not found return null; } @@ -1367,7 +1367,7 @@ protected function getTableStyles($styles) $tableStyles.= 'border-bottom: ' . $this->htmlPlugin->transformSizes($elementWTblBordersBottom->item(0)->getAttribute('w:sz'), 'eights') . ' ' . $borderStyle . ' #' . $this->htmlPlugin->transformColors($elementWTblBordersBottom->item(0)->getAttribute('w:color')) . ';'; $borderStylesTable .= 'border-bottom: ' . $this->htmlPlugin->transformSizes($elementWTblBordersBottom->item(0)->getAttribute('w:sz'), 'eights') . ' ' . $borderStyle . ' #' . $this->htmlPlugin->transformColors($elementWTblBordersBottom->item(0)->getAttribute('w:color')) . ';'; } - + // left $elementWTblBordersLeft = $elementWTblBorders->item(0)->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'left'); if ($elementWTblBordersLeft->length > 0) { @@ -1606,7 +1606,7 @@ protected function getRelationshipContent($id) } else { $relsContent = $this->docxStructure->getContent('word/_rels/document.xml.rels'); } - + $xmlDocumentRels = new \DOMDocument(); $optionEntityLoader = libxml_disable_entity_loader(true); @@ -1621,7 +1621,7 @@ protected function getRelationshipContent($id) if (!$elementId || !$elementId->hasAttribute('Target')) { return null; } - + return $elementId->getAttribute('Target'); } @@ -1931,7 +1931,7 @@ protected function transformW_DRAWING($childNode, $nodeClass) $this->css[$nodeClass] .= 'display: inline;'; } else { // anchor tag - + // wrapSquare $elementWrapSquare = $childNode->getElementsByTagNameNS('http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing', 'wrapSquare'); if ($elementWrapSquare->length > 0) { @@ -2014,7 +2014,7 @@ protected function transformW_DRAWING($childNode, $nodeClass)