pridane tlacitko na zmazanie prilohy,

implementovany upload a zobrazenie suboru obrazku
This commit is contained in:
Igor Miňo 2025-05-17 13:46:26 +02:00
parent 16fa3d1ed1
commit 4a050b0ff7
4 changed files with 130 additions and 14 deletions

12
api.php
View File

@ -57,6 +57,11 @@ switch ($action) {
case 'attachmentGetAll':
$result = attachmentGetAll($_REQUEST['report_id']);
break;
case 'attachmentDelete':
$suc = attachmentDelete($_REQUEST['attachment_id']);
if ($suc === false) $error = 'Attachment delete failed';
$result = array('processed' => $suc);
break;
}
header('Content-Type: application/json');
@ -172,6 +177,13 @@ function help()
'params' => [
'report_id' => 'Report id',
]
],
'attachmentGet' => [
'name' => 'attachmentGet',
'description' => 'Get attachment',
'params' => [
'attachment_id' => 'Attachment id',
]
]
]
];

View File

@ -473,6 +473,7 @@ button:focus-visible,
flex-direction: row;
justify-content: space-between;
background-color: var(--color-bg0);
align-items: center;
}
#report .attachments .attachment .attachment-header .created,
#report .attachments .attachment .attachment-header .author {

View File

@ -97,4 +97,8 @@ export const backend = {
return this.callPromise('attachmentGetAll', {report_id: report_id});
},
attachmentDelete(attachment_id) {
return this.callPromise('attachmentDelete', {attachment_id: attachment_id});
},
};

View File

@ -47,12 +47,12 @@
:key="attachment.attachment_id"
>
<div class="attachment-header">
<span class="created"
title="Vytvorene"
<span class="created" title="Vytvorene"
><font-awesome-icon :icon="['fas', 'calendar-days']" />
{{ attachment.created_dt }}</span
>
<span class="updated"
<span
class="updated"
v-if="attachment.updated_dt"
title="Posledná zmena"
><font-awesome-icon :icon="['fas', 'pen']" />
@ -62,8 +62,14 @@
><font-awesome-icon :icon="['fas', 'user']" />
{{ attachment.attachment_author }}</span
>
<span class="actions">
<button @click="attachmentDelete(attachment)">
<font-awesome-icon :icon="['fas', 'circle-xmark']" /> Odstranit
</button>
</span>
</div>
<div
v-if="attachment.attachment_type == 'comment'"
class="attachment-content"
:contenteditable="attachment.editable ?? false"
@dblclick="attachment.editable = true"
@ -74,6 +80,15 @@
>
{{ attachment.attachment_content }}
</div>
<div
v-else-if="attachment.attachment_type == 'file'"
class="attachment-file"
>
<img :src="attachment.attachment_content" />
</div>
<div v-else class="attachment-content">
Neznamy typ prilohy: <strong>{{ attachment.attachment_type }}</strong>
</div>
</div>
</div>
<div class="attachment-new">
@ -87,6 +102,32 @@
required
></textarea>
</div>
<div class="form-group">
<label for="files">Prílohy:</label>
<input
type="file"
id="files"
ref="attachmentNewFiles"
@change="handleFileUpload"
multiple
class="form-control file-input"
/>
<div class="selected-files" v-if="selectedFiles.length > 0">
<p>Vybrané súbory:</p>
<p v-for="(file, index) in selectedFiles" :key="index">
<button
type="button"
class="remove-file"
@click="removeFile(index)"
>
<font-awesome-icon :icon="['fas', 'circle-xmark']" /> Odober súbor
</button>
&nbsp;&nbsp;
{{ file.name }} ({{ formatFileSize(file.size) }})
</p>
</div>
</div>
<div class="form-actions">
<button @click="attachmentAdd">
<font-awesome-icon :icon="['fas', 'circle-plus']" /> Pridať
@ -125,6 +166,9 @@ export default {
created_dt: "--",
},
],
attachmentNewFiles: null,
selectedFiles: [],
selectedFilesContent: [],
};
},
mounted() {
@ -158,6 +202,8 @@ export default {
});
},
attachmentAdd() {
let comment = this.$refs.attachmentNewContent.value;
if (comment.trim().length > 0) {
this.loading = true;
backend
.attachmentAdd(
@ -170,6 +216,33 @@ export default {
this.loadReportData();
this.loading = false;
});
}
if (this.selectedFiles.length > 0) {
let for_upload = this.selectedFiles.length;
this.loading = true;
for (let i = 0; i < this.selectedFiles.length; i++) {
backend
.attachmentAdd(this.report_id, "file", this.selectedFilesContent[i])
.then(() => {
for_upload--;
if (for_upload == 0) {
this.selectedFiles = [];
this.selectedFilesContent = [];
this.$refs.attachmentNewFiles.value = null;
this.loadReportData();
this.loading = false;
}
});
}
}
},
attachmentDelete(attachment) {
if (!confirm("Naozaj chcete zmazať prilohu?")) return;
this.loading = true;
backend.attachmentDelete(attachment.attachment_id).then(() => {
this.loadReportData();
this.loading = false;
});
},
updateAttachmentContent(event, attachment) {
this.loading = true;
@ -180,6 +253,32 @@ export default {
this.loading = false;
});
},
handleFileUpload(event) {
const files = event.target.files;
if (files) {
for (let i = 0; i < files.length; i++) {
this.selectedFiles.push(files[i]);
const reader = new FileReader();
reader.onload = () => {
this.selectedFilesContent[i] = reader.result;
};
reader.readAsDataURL(files[i]);
}
}
},
removeFile(index) {
this.selectedFiles.splice(index, 1);
this.selectedFilesContent.splice(index, 1);
},
formatFileSize(size) {
if (size < 1024) {
return size + " B";
} else if (size < 1024 * 1024) {
return (size / 1024).toFixed(2) + " KB";
} else {
return (size / (1024 * 1024)).toFixed(2) + " MB";
}
},
},
};
</script>