304 lines
9.4 KiB
Vue
304 lines
9.4 KiB
Vue
<script setup>
|
|
import FileUpload from '@/components/media/FileUpload.vue';
|
|
|
|
const { dealer } = useStore();
|
|
const { $buildFileUrl, $formatFileSize, $getdata, $insertapi, $patchapi, $snackbar } = useNuxtApp();
|
|
|
|
const project = await $getdata('project', undefined, undefined, true);
|
|
const projectDocuments = ref([]);
|
|
|
|
async function loadProjectDocuments() {
|
|
projectDocuments.value = await $getdata("projectfile", undefined, {
|
|
filter: { project: project.id, file__type: 1 } ,
|
|
values: "id,project,file,file__id,file__code,file__type,file__name,file__file,file__size,file__caption,file__user,file__user__fullname,create_time",
|
|
})
|
|
}
|
|
|
|
loadProjectDocuments();
|
|
|
|
async function attachFilesToProject(files) {
|
|
const payload = files
|
|
.filter((file) => file && file.id)
|
|
.map((file) => ({ project: project.id, file: file.id }));
|
|
if (payload.length === 0) return 0;
|
|
const result = await $insertapi("projectfile", payload, undefined, false);
|
|
if (result === "error") {
|
|
throw new Error("Không thể liên kết tệp với dự án");
|
|
}
|
|
return payload.length;
|
|
}
|
|
|
|
async function onUploadedProjectDocs(payload) {
|
|
const uploadedFiles = Array.isArray(payload) ? payload : null;
|
|
if (uploadedFiles && uploadedFiles.length > 0) {
|
|
try {
|
|
const linked = await attachFilesToProject(uploadedFiles);
|
|
if (linked > 0) {
|
|
await loadProjectDocuments();
|
|
const message =
|
|
linked === 1
|
|
? "Đã thêm tài liệu dự án thành công"
|
|
: `Đã thêm ${linked} tài liệu dự án thành công`;
|
|
$snackbar(message, "Thành công", "Success");
|
|
}
|
|
} catch (error) {
|
|
console.error("Error attaching project documents:", error);
|
|
$snackbar(
|
|
"Không thể thêm tài liệu dự án, vui lòng thử lại",
|
|
"Lỗi",
|
|
"Error"
|
|
);
|
|
}
|
|
return;
|
|
}
|
|
|
|
const event = payload?.target ? payload : null;
|
|
if (!event) return;
|
|
const files = event.target.files;
|
|
if (!files || files.length === 0) return;
|
|
|
|
const totalFiles = files.length;
|
|
Array.from(files).forEach((file) => {
|
|
projectDocuments.value.push({
|
|
id: Date.now() + Math.random(),
|
|
name: file.name,
|
|
size: $formatFileSize(file.size),
|
|
uploaded_by: store.login?.fullname || "Admin",
|
|
});
|
|
});
|
|
const message =
|
|
totalFiles === 1
|
|
? "Đã thêm tài liệu dự án thành công"
|
|
: `Đã thêm ${totalFiles} tài liệu dự án thành công`;
|
|
$snackbar(message, "Thành công", "Success");
|
|
event.target.value = "";
|
|
}
|
|
|
|
const editingDocument = ref(null);
|
|
const editingDocumentName = ref("");
|
|
const editingDocumentCaption = ref("");
|
|
|
|
// Sửa tài liệu
|
|
function editDocument(doc) {
|
|
editingDocument.value = doc;
|
|
editingDocumentName.value = doc.file__name;
|
|
editingDocumentCaption.value = doc.file__caption || "";
|
|
}
|
|
|
|
async function saveEditDocument() {
|
|
if (!editingDocument.value) return;
|
|
const index = projectDocuments.value.findIndex(
|
|
(doc) => doc.id === editingDocument.value.id
|
|
);
|
|
if (index !== -1) {
|
|
projectDocuments.value[index] = {
|
|
...projectDocuments.value[index],
|
|
name: editingDocumentName.value,
|
|
caption: editingDocumentCaption.value,
|
|
};
|
|
const fileId = editingDocument.value.fileId || editingDocument.value.file;
|
|
if (fileId) {
|
|
try {
|
|
await $patchapi(
|
|
"file",
|
|
{
|
|
id: fileId,
|
|
name: editingDocumentName.value,
|
|
caption: editingDocumentCaption.value?.trim() || null,
|
|
},
|
|
{},
|
|
false
|
|
);
|
|
$snackbar("Đã cập nhật tài liệu thành công", "Thành công", "Success");
|
|
} catch (error) {
|
|
console.error("Error updating document metadata:", error);
|
|
$snackbar("Cập nhật tài liệu thất bại", "Lỗi", "Error");
|
|
}
|
|
}
|
|
}
|
|
cancelEditDocument();
|
|
}
|
|
|
|
function cancelEditDocument() {
|
|
editingDocument.value = null;
|
|
editingDocumentName.value = "";
|
|
editingDocumentCaption.value = "";
|
|
}
|
|
</script>
|
|
<template>
|
|
<div class="mb-3">
|
|
<FileUpload
|
|
v-if="!dealer && $getEditRights()"
|
|
position="right"
|
|
:type="['pdf', 'file']"
|
|
@files="onUploadedProjectDocs"
|
|
/>
|
|
</div>
|
|
<div class="table-container">
|
|
<table class="table is-bordered is-fullwidth">
|
|
<thead>
|
|
<tr>
|
|
<th>File</th>
|
|
<th>Mô tả</th>
|
|
<th>Người tải lên</th>
|
|
<th>Chức năng</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<template v-for="doc in projectDocuments" :key="doc.id">
|
|
<tr v-if="editingDocument?.id === doc.id">
|
|
<td colspan="4">
|
|
<div class="columns is-multiline">
|
|
<div class="column is-4">
|
|
<div class="field">
|
|
<label class="label">Tên tài liệu</label>
|
|
<div class="control">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="editingDocumentName"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-4">
|
|
<div class="field">
|
|
<label class="label">Mô tả</label>
|
|
<div class="control">
|
|
<input
|
|
class="input"
|
|
type="text"
|
|
v-model="editingDocumentCaption"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="column is-4">
|
|
<div class="field">
|
|
<label class="label"> </label>
|
|
<div class="control">
|
|
<div class="buttons">
|
|
<button
|
|
class="button has-text-white is-primary"
|
|
@click="saveEditDocument"
|
|
>
|
|
Lưu
|
|
</button>
|
|
<button
|
|
class="button is-danger has-text-white"
|
|
@click="cancelEditDocument"
|
|
>
|
|
Hủy
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr v-else>
|
|
<td>
|
|
<div class="is-flex is-align-items-center">
|
|
<div>
|
|
<a
|
|
:href="$buildFileUrl(doc.file__file)"
|
|
target="_blank"
|
|
class="has-text-weight-semibold"
|
|
>
|
|
{{ doc.file__name }}
|
|
</a>
|
|
<p class="is-size-7 has-text-grey">
|
|
{{ $formatFileSize(doc.file__size) }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="is-size-7">{{
|
|
doc.file__caption || "-"
|
|
}}</span>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<p class="is-size-7 has-text-weight-semibold">
|
|
{{ doc.file__user__fullname }}
|
|
</p>
|
|
<p class="is-size-7 has-text-grey">
|
|
{{
|
|
doc.create_time
|
|
? new Date(doc.create_time).toLocaleString(
|
|
"vi-VN"
|
|
)
|
|
: "-"
|
|
}}
|
|
</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="buttons">
|
|
<a
|
|
v-if="!dealer && $getEditRights()"
|
|
@click="editDocument(doc)"
|
|
title="Sửa"
|
|
>
|
|
<span class="icon"
|
|
><SvgIcon
|
|
v-bind="{
|
|
name: 'edit.svg',
|
|
type: 'primary',
|
|
size: 18,
|
|
}"
|
|
></SvgIcon
|
|
></span>
|
|
</a>
|
|
<a
|
|
:href="$buildFileUrl(doc.file__file)"
|
|
target="_blank"
|
|
title="Tải xuống"
|
|
>
|
|
<span class="icon"
|
|
><SvgIcon
|
|
v-bind="{
|
|
name: 'download.svg',
|
|
type: 'success',
|
|
size: 18,
|
|
}"
|
|
></SvgIcon
|
|
></span>
|
|
</a>
|
|
<a
|
|
v-if="!dealer && $getEditRights()"
|
|
@click="deleteDocument(doc)"
|
|
title="Xóa"
|
|
>
|
|
<span class="icon"
|
|
><SvgIcon
|
|
v-bind="{
|
|
name: 'bin1.svg',
|
|
type: 'primary',
|
|
size: 18,
|
|
}"
|
|
></SvgIcon
|
|
></span>
|
|
</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
<tr v-if="projectDocuments.length === 0">
|
|
<td colspan="4" class="has-text-centered py-4">
|
|
<p class="has-text-grey">
|
|
Chưa có tài liệu nào được đính kèm.
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</template>
|
|
<style>
|
|
.table th {
|
|
background-color: #f5f5f5;
|
|
}
|
|
</style> |