wip - attachments
This commit is contained in:
parent
e6376c7d92
commit
b7efd18571
@ -15,6 +15,7 @@
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
|
||||
class Study extends BaseModel implements HasMedia
|
||||
{
|
||||
@ -22,6 +23,7 @@ class Study extends BaseModel implements HasMedia
|
||||
use InteractsWithMedia;
|
||||
|
||||
public const string MEDIA_COLLECTION = 'attachments';
|
||||
public const string FALLBACK_IMAGE = 'imgs/pdf.png';
|
||||
|
||||
public function details(): HasOne
|
||||
{
|
||||
@ -265,6 +267,26 @@ public function getPriorityIcon(): string
|
||||
};
|
||||
}
|
||||
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
// $media->extension
|
||||
$this->addMediaConversion('tn')
|
||||
->width(48)
|
||||
->height(48)
|
||||
->sharpen(10)
|
||||
->performOnCollections(Study::MEDIA_COLLECTION)
|
||||
->nonQueued();
|
||||
}
|
||||
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection(self::MEDIA_COLLECTION)
|
||||
->useFallbackUrl(asset(self::FALLBACK_IMAGE))
|
||||
->useFallbackUrl(asset(self::FALLBACK_IMAGE), 'tn')
|
||||
->useFallbackPath(public_path(self::FALLBACK_IMAGE))
|
||||
->useFallbackPath(public_path(self::FALLBACK_IMAGE), 'tn');
|
||||
}
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\AuditTrail\ActivityLogger;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
|
||||
if (! function_exists('_h')) {
|
||||
function _h(int $key): string
|
||||
@ -72,10 +73,11 @@ function may(BackedEnum|iterable|string $perm): bool
|
||||
return auth()->user()->can($perm);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('human_filesize')) {
|
||||
function human_filesize(int $bytes, $dec = 0): string
|
||||
{
|
||||
$size = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
$size = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
$factor = floor((strlen($bytes) - 1) / 3);
|
||||
if ($factor == 0) {
|
||||
$dec = 0;
|
||||
@ -84,3 +86,28 @@ function human_filesize(int $bytes, $dec = 0): string
|
||||
return sprintf("%.{$dec}f %s", $bytes / (1024 ** $factor), $size[$factor]);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('chomp')) {
|
||||
function chomp(string $s, int $len, int $right = 6): string
|
||||
{
|
||||
$length = strlen($s);
|
||||
if ($length <= ($len + $right)) {
|
||||
return $s;
|
||||
}
|
||||
$start = substr($s, 0, $len);
|
||||
$end = substr($s, -$right);
|
||||
|
||||
return $start . '...' . $end;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('thumb_url')) {
|
||||
function thumb_url(Media $media): string
|
||||
{
|
||||
if ($media->mime_type === 'application/pdf') {
|
||||
return asset('imgs/pdf.png');
|
||||
}
|
||||
|
||||
return $media->getUrl('tn') ?? asset('imgs/pdf.png');
|
||||
}
|
||||
}
|
||||
|
BIN
resources/imgs/pdf.png
Normal file
BIN
resources/imgs/pdf.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
@ -12,12 +12,13 @@
|
||||
|
||||
@extends('layouts.layoutMaster')
|
||||
|
||||
@section('title', 'Worklist')
|
||||
@section('title', 'Info')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'resources/fontawesome/scss/fontawesome.scss',
|
||||
'resources/fontawesome/scss/light.scss',
|
||||
'resources/assets/vendor/libs/dropzone/dropzone.scss'
|
||||
])
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Trumbowyg/2.27.3/ui/trumbowyg.min.css"
|
||||
integrity="sha512-Fm8kRNVGCBZn0sPmwJbVXlqfJmPC13zRsMElZenX6v721g/H7OukJd8XzDEBRQ2FSATK8xNF9UYvzsCtUpfeJg=="
|
||||
@ -33,43 +34,69 @@
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Trumbowyg/2.27.3/plugins/cleanpaste/trumbowyg.cleanpaste.min.js"
|
||||
integrity="sha512-UInqT8f+K1tkck6llPo0HDxlT/Zxv8t4OGeCuVfsIlXLrnP1ZKDGb+tBsBPMqDW15OcmV8NDfQe9+EaAG4aXeg=="
|
||||
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
|
||||
@endsection
|
||||
|
||||
@section('page-script')
|
||||
<script>
|
||||
|
||||
$('textarea').trumbowyg({
|
||||
$('.tw_ed').trumbowyg({
|
||||
btns: [
|
||||
['strong', 'em'],
|
||||
['removeformat'],
|
||||
['viewHTML'],
|
||||
['fullscreen']
|
||||
],
|
||||
removeformatPasted: true,
|
||||
autogrow: true,
|
||||
resetCss: true
|
||||
removeformatPasted: true
|
||||
});
|
||||
|
||||
Dropzone.options.fileDropzone = {
|
||||
|
||||
(function () {
|
||||
// previewTemplate: Updated Dropzone default previewTemplate
|
||||
// ! Don't change it unless you really know what you are doing
|
||||
const previewTemplate = `<div class="dz-preview dz-file-preview">
|
||||
<div class="dz-details">
|
||||
<div class="dz-thumbnail">
|
||||
<img data-dz-thumbnail>
|
||||
<span class="dz-nopreview">No preview</span>
|
||||
<div class="dz-success-mark"></div>
|
||||
<div class="dz-error-mark"></div>
|
||||
<div class="dz-error-message"><span data-dz-errormessage></span></div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-primary" role="progressbar" aria-valuemin="0" aria-valuemax="100" data-dz-uploadprogress></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dz-filename" data-dz-name></div>
|
||||
<div class="dz-size" data-dz-size></div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const dropzoneMulti = document.querySelector('#dropzone-multi');
|
||||
if (dropzoneMulti) {
|
||||
const myDropzoneMulti = new Dropzone(dropzoneMulti, {
|
||||
paramName: 'file',
|
||||
maxFilesize: 5, // MB
|
||||
acceptedFiles: '.pdf,.jpg,.jpeg,.png',
|
||||
uploadMultiple: true,
|
||||
parallelUploads: 3,
|
||||
parallelUploads: 2,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': "{{ csrf_token() }}"
|
||||
},
|
||||
success: function (file, response) {
|
||||
console.log(response.success);
|
||||
previewTemplate: previewTemplate,
|
||||
addRemoveLinks: true
|
||||
});
|
||||
}
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row g-6">
|
||||
<div class="col-8">
|
||||
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('History') }}
|
||||
</h2>
|
||||
@ -81,63 +108,61 @@
|
||||
<input type="hidden" name="study_id" value="{{ $details->hash }}">
|
||||
<h5>Clinical History</h5>
|
||||
<div class="p-4 border-gray-100">
|
||||
<textarea name="clinical_history" id="clinical_history" cols="90"
|
||||
rows="10">{!! $details->clinical_history !!}</textarea>
|
||||
<div class="tw_ed" name="clinical_history" id="clinical_history"
|
||||
>{!! $details->clinical_history !!}</div class="tw_ed">
|
||||
</div>
|
||||
<x-section-border/>
|
||||
|
||||
<h5>surgical history</h5>
|
||||
<div class="p-4 border-gray-100">
|
||||
<textarea name="surgical_history" id="surgical_history" cols="90"
|
||||
rows="10">{!! $details->surgical_history !!}</textarea>
|
||||
<div class="tw_ed" name="surgical_history" id="surgical_history"
|
||||
>{!! $details->surgical_history !!}</div class="tw_ed">
|
||||
</div>
|
||||
<x-section-border/>
|
||||
|
||||
<h5>lab results</h5>
|
||||
<div class="p-4 border-gray-100">
|
||||
<textarea name="lab_results" id="lab_results" cols="90"
|
||||
rows="10">{!! $details->lab_results !!}</textarea>
|
||||
<div class="tw_ed" name="lab_results" id="lab_results"
|
||||
>{!! $details->lab_results !!}</div class="tw_ed">
|
||||
</div>
|
||||
<x-section-border/>
|
||||
|
||||
<h5>clinical diagnosis</h5>
|
||||
<div class="p-4 border-gray-100">
|
||||
<textarea name="clinical_diagnosis" id="clinical_diagnosis" cols="90"
|
||||
rows="10">{!! $details->clinical_diagnosis !!}</textarea>
|
||||
<div class="tw_ed" name="clinical_diagnosis" id="clinical_diagnosis"
|
||||
>{!! $details->clinical_diagnosis !!}</div class="tw_ed">
|
||||
</div>
|
||||
|
||||
<button type="submit">Save</button>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h1>Upload Files</h1>
|
||||
|
||||
<!-- List of already uploaded files -->
|
||||
<div class="uploaded-files">
|
||||
<h2>Uploaded Files</h2>
|
||||
<ul>
|
||||
@foreach ($study->getMedia(\App\Models\Study::MEDIA_COLLECTION) as $media)
|
||||
<li>
|
||||
<i class="fa {{ $media->mime_type == 'application/pdf' ? 'fa-file-pdf' : 'fa-file-image' }}"></i>
|
||||
<a href="{{ $media->getUrl() }}" target="_blank">{{ $media->file_name }}</a>
|
||||
({{ $media->human_readable_size }}) - Uploaded on {{ $media->created_at->format('Y-m-d H:i') }}
|
||||
|
||||
<form action="{{ route('staff.attachment.delete', [$study->hash, $media->id]) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-danger btn-sm">Delete</button>
|
||||
</form>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="col-4">
|
||||
<h4>Attachments</h4>
|
||||
|
||||
<!-- Dropzone area -->
|
||||
<form action="{{ route('staff.attachment.upload', $study->hash) }}" class="dropzone" id="file-dropzone">
|
||||
<form action="{{ route('staff.attachment.upload', $study->hash) }}" class="dropzone needsclick"
|
||||
id="dropzone-multi">
|
||||
@csrf
|
||||
<div class="dz-message needsclick">
|
||||
Drop attachments here or click to upload
|
||||
<span class="note needsclick">Allowed files: <span class="fw-medium">JPG, PNG, PDF</span></span>
|
||||
</div>
|
||||
<div class="fallback">
|
||||
<input name="file" type="file"/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<!-- List of already uploaded files -->
|
||||
@include('staff.history.partials._uploaded-studies-list', ['study' => $study])
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table dataTable no-footer table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>File</th>
|
||||
<th>Size</th>
|
||||
<th>Uploaded</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@foreach ($study->getMedia(\App\Models\Study::MEDIA_COLLECTION) as $media)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar-wrapper">
|
||||
<div class="avatar me-2">
|
||||
<img class="rounded" src="{{ thumb_url($media) }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<a class="text-heading fw-medium" target="_blank" href="{{ $media->getUrl() }}">
|
||||
{{ chomp($media->file_name, 20) }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ $media->human_readable_size }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ $media->created_at->format('d.m.Y h:iA') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="d-flex align-items-end">
|
||||
<form action="{{ route('staff.attachment.delete', [$study->hash, $media->id]) }}"
|
||||
method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-google-plus btn-xs btn-icon">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user