396 lines
12 KiB
Vue
396 lines
12 KiB
Vue
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useRoute } from 'vue-router';
|
|
import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar';
|
|
import axios from 'axios';
|
|
|
|
import VnPaginate from 'components/ui/VnPaginate.vue';
|
|
import VnDms from 'src/components/common/VnDms.vue';
|
|
import VnConfirm from 'components/ui/VnConfirm.vue';
|
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
|
import VnUserLink from '../ui/VnUserLink.vue';
|
|
import { downloadFile } from 'src/composables/downloadFile';
|
|
|
|
const route = useRoute();
|
|
const quasar = useQuasar();
|
|
const { t } = useI18n();
|
|
const rows = ref();
|
|
const dmsRef = ref();
|
|
const formDialog = ref({});
|
|
|
|
const $props = defineProps({
|
|
model: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
updateModel: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
deleteModel: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
downloadModel: {
|
|
type: String,
|
|
required: false,
|
|
default: undefined,
|
|
},
|
|
defaultDmsCode: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
filter: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
const dmsFilter = {
|
|
include: {
|
|
relation: 'dms',
|
|
scope: {
|
|
fields: [
|
|
'dmsTypeFk',
|
|
'reference',
|
|
'hardCopyNumber',
|
|
'workerFk',
|
|
'description',
|
|
'hasFile',
|
|
'file',
|
|
'created',
|
|
'companyFk',
|
|
'warehouseFk',
|
|
],
|
|
include: [
|
|
{
|
|
relation: 'dmsType',
|
|
scope: {
|
|
fields: ['name'],
|
|
},
|
|
},
|
|
{
|
|
relation: 'worker',
|
|
scope: {
|
|
fields: ['id'],
|
|
include: {
|
|
relation: 'user',
|
|
scope: {
|
|
fields: ['name'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
where: { [$props.filter]: route.params.id },
|
|
};
|
|
|
|
const columns = computed(() => [
|
|
{
|
|
align: 'left',
|
|
field: 'id',
|
|
label: t('globals.id'),
|
|
name: 'id',
|
|
component: 'span',
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'type',
|
|
label: t('globals.type'),
|
|
name: 'type',
|
|
component: QInput,
|
|
props: (prop) => ({
|
|
readonly: true,
|
|
borderless: true,
|
|
'model-value': prop.row.dmsType?.name,
|
|
}),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'hardCopyNumber',
|
|
label: t('globals.order'),
|
|
name: 'order',
|
|
component: 'span',
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'reference',
|
|
label: t('globals.reference'),
|
|
name: 'reference',
|
|
component: 'span',
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'description',
|
|
label: t('globals.description'),
|
|
name: 'description',
|
|
component: 'span',
|
|
props: (prop) => ({ value: prop.value?.toUpperCase() }),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'hasFile',
|
|
label: t('globals.original'),
|
|
name: 'hasFile',
|
|
component: QCheckbox,
|
|
props: (prop) => ({
|
|
disable: true,
|
|
'model-value': Boolean(prop.value),
|
|
}),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'file',
|
|
label: t('globals.file'),
|
|
name: 'file',
|
|
component: 'span',
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'worker',
|
|
label: t('globals.worker'),
|
|
name: 'worker',
|
|
component: VnUserLink,
|
|
props: (prop) => ({
|
|
name: prop.row.worker?.user?.name.toLowerCase(),
|
|
workerId: prop.row.worker?.id,
|
|
}),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'created',
|
|
label: t('globals.created'),
|
|
name: 'created',
|
|
component: VnInputDate,
|
|
props: (prop) => ({
|
|
disable: true,
|
|
'model-value': prop.row.created,
|
|
}),
|
|
},
|
|
{
|
|
field: 'options',
|
|
name: 'options',
|
|
components: [
|
|
{
|
|
component: QBtn,
|
|
name: 'download',
|
|
isDocuware: true,
|
|
props: () => ({
|
|
icon: 'cloud_download',
|
|
flat: true,
|
|
color: 'primary',
|
|
}),
|
|
click: (prop) =>
|
|
downloadFile(
|
|
prop.row.id,
|
|
$props.downloadModel,
|
|
undefined,
|
|
prop.row.download
|
|
),
|
|
},
|
|
{
|
|
component: QBtn,
|
|
name: 'edit',
|
|
external: false,
|
|
props: () => ({
|
|
icon: 'edit',
|
|
flat: true,
|
|
color: 'primary',
|
|
}),
|
|
click: (prop) => showFormDialog(prop.row),
|
|
},
|
|
{
|
|
component: QBtn,
|
|
name: 'delete',
|
|
external: false,
|
|
props: () => ({
|
|
icon: 'delete',
|
|
flat: true,
|
|
color: 'primary',
|
|
}),
|
|
click: (prop) => deleteDms(prop.row.id),
|
|
},
|
|
{
|
|
component: QBtn,
|
|
name: 'open',
|
|
external: true,
|
|
props: () => ({
|
|
icon: 'open_in_new',
|
|
flat: true,
|
|
color: 'primary',
|
|
}),
|
|
click: (prop) => open(prop.row.url),
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
function setData(data) {
|
|
const newData = data.map((value) => value.dms || value);
|
|
newData.sort((a, b) => new Date(b.created) - new Date(a.created));
|
|
rows.value = newData;
|
|
}
|
|
|
|
function deleteDms(dmsFk) {
|
|
quasar
|
|
.dialog({
|
|
component: VnConfirm,
|
|
componentProps: {
|
|
title: t('globals.confirmDeletion'),
|
|
message: t('globals.confirmDeletionMessage'),
|
|
},
|
|
})
|
|
.onOk(async () => {
|
|
await axios.post(`${$props.deleteModel ?? $props.model}/${dmsFk}/removeFile`);
|
|
const index = rows.value.findIndex((row) => row.id == dmsFk);
|
|
rows.value.splice(index, 1);
|
|
});
|
|
}
|
|
|
|
function showFormDialog(dms) {
|
|
if (dms) dms = parseDms(dms);
|
|
formDialog.value = {
|
|
show: true,
|
|
dms,
|
|
};
|
|
}
|
|
|
|
function parseDms(data) {
|
|
for (let prop in data) {
|
|
if (prop.endsWith('Fk')) data[prop.replace('Fk', 'Id')] = data[prop];
|
|
}
|
|
return data;
|
|
}
|
|
|
|
async function open(url) {
|
|
window.open(url).focus();
|
|
}
|
|
|
|
function shouldRenderButton(button, isExternal = false) {
|
|
if (button.name == 'download') return true;
|
|
return button.external === isExternal;
|
|
}
|
|
</script>
|
|
<template>
|
|
<VnPaginate
|
|
ref="dmsRef"
|
|
:data-key="$props.model"
|
|
:url="$props.model"
|
|
:filter="dmsFilter"
|
|
:order="['dmsFk DESC']"
|
|
:auto-load="true"
|
|
@on-fetch="setData"
|
|
>
|
|
<template #body>
|
|
<QTable
|
|
:columns="columns"
|
|
:rows="rows"
|
|
class="full-width q-mt-md"
|
|
hide-bottom
|
|
row-key="clientFk"
|
|
:grid="$q.screen.lt.sm"
|
|
>
|
|
<template #body-cell="props">
|
|
<QTd :props="props">
|
|
<QTr :props="props">
|
|
<component
|
|
v-if="props.col.component"
|
|
:is="props.col.component"
|
|
v-bind="props.col.props && props.col.props(props)"
|
|
>
|
|
<span
|
|
v-if="props.col.component == 'span'"
|
|
style="white-space: wrap"
|
|
>{{ props.value }}</span
|
|
>
|
|
</component>
|
|
</QTr>
|
|
|
|
<div class="row no-wrap" v-if="props.col.name == 'options'">
|
|
<div v-for="button of props.col.components" :key="button.id">
|
|
<component
|
|
v-if="
|
|
shouldRenderButton(button, props.row.isDocuware)
|
|
"
|
|
:is="button.component"
|
|
v-bind="button.props(props)"
|
|
@click="button.click(props)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</QTd>
|
|
</template>
|
|
<template #item="props">
|
|
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
|
<QCard
|
|
bordered
|
|
flat
|
|
@keyup.ctrl.enter.stop="claimDevelopmentForm?.saveChanges()"
|
|
>
|
|
<QSeparator />
|
|
<QList dense>
|
|
<QItem v-for="col in props.cols" :key="col.name">
|
|
<div v-if="col.name != 'options'" class="row">
|
|
<span class="labelColor">{{ col.label }}:</span>
|
|
<span>{{ col.value }}</span>
|
|
</div>
|
|
<div v-if="col.name == 'options'" class="row">
|
|
<div
|
|
v-for="button of col.components"
|
|
:key="button.id"
|
|
class="row"
|
|
>
|
|
<component
|
|
v-if="
|
|
shouldRenderButton(
|
|
button.name,
|
|
props.row.isDocuware
|
|
)
|
|
"
|
|
:is="button.component"
|
|
v-bind="button.props(col)"
|
|
@click="button.click(col)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</QItem>
|
|
</QList>
|
|
</QCard>
|
|
</div>
|
|
</template>
|
|
</QTable>
|
|
</template>
|
|
</VnPaginate>
|
|
<QDialog v-model="formDialog.show">
|
|
<VnDms
|
|
:model="updateModel ?? model"
|
|
:default-dms-code="defaultDmsCode"
|
|
:form-initial-data="formDialog.dms"
|
|
@on-data-saved="dmsRef.fetch()"
|
|
:description="$props.description"
|
|
/>
|
|
</QDialog>
|
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
|
<QBtn fab color="primary" icon="add" @click="showFormDialog()" />
|
|
</QPageSticky>
|
|
</template>
|
|
<style scoped>
|
|
.q-gutter-y-ms {
|
|
display: grid;
|
|
row-gap: 20px;
|
|
}
|
|
.labelColor {
|
|
color: var(--vn-label-color);
|
|
}
|
|
</style>
|
|
<i18n>
|
|
en:
|
|
contentTypesInfo: Allowed file types {allowedContentTypes}
|
|
es:
|
|
contentTypesInfo: Tipos de archivo permitidos {allowedContentTypes}
|
|
Generate identifier for original file: Generar identificador para archivo original
|
|
</i18n>
|