diff --git a/src/components/common/VnDms.vue b/src/components/common/VnDms.vue index 08255f8a..daef5940 100644 --- a/src/components/common/VnDms.vue +++ b/src/components/common/VnDms.vue @@ -198,9 +198,11 @@ function addDefaultData(data) { en: contentTypesInfo: Allowed file types {allowedContentTypes} EntryDmsDescription: Reference {reference} + WorkersDescription: Working of employee id {reference} es: Generate identifier for original file: Generar identificador para archivo original contentTypesInfo: Tipos de archivo permitidos {allowedContentTypes} EntryDmsDescription: Referencia {reference} + WorkersDescription: Laboral del empleado {reference} </i18n> diff --git a/src/components/common/VnDmsList.vue b/src/components/common/VnDmsList.vue index 9bf90230..8c3ffc80 100644 --- a/src/components/common/VnDmsList.vue +++ b/src/components/common/VnDmsList.vue @@ -5,11 +5,12 @@ import { useRoute } from 'vue-router'; import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar'; import axios from 'axios'; -import FetchData from 'components/FetchData.vue'; +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'; -import { getUrlFindOne } from 'composables/getUrl'; const route = useRoute(); const quasar = useQuasar(); @@ -27,6 +28,11 @@ const $props = defineProps({ type: String, default: null, }, + downloadModel: { + type: String, + required: false, + default: null, + }, defaultDmsCode: { type: String, required: true, @@ -75,7 +81,7 @@ const dmsFilter = { ], }, }, - order: ['dmsFk DESC'], + where: { [$props.filter]: route.params.id }, }; const columns = computed(() => [ @@ -95,12 +101,12 @@ const columns = computed(() => [ props: (prop) => ({ readonly: true, borderless: true, - 'model-value': prop.row.dmsType.name, + 'model-value': prop.row.dmsType?.name, }), }, { align: 'left', - field: 'order', + field: 'hardCopyNumber', label: t('globals.order'), name: 'order', component: 'span', @@ -118,6 +124,7 @@ const columns = computed(() => [ label: t('globals.description'), name: 'description', component: 'span', + props: (prop) => ({ value: prop.value?.toUpperCase() }), }, { align: 'left', @@ -137,6 +144,28 @@ const columns = computed(() => [ 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', @@ -144,16 +173,24 @@ const columns = computed(() => [ { component: QBtn, name: 'download', + isDocuware: true, props: () => ({ icon: 'cloud_download', flat: true, color: 'primary', }), - click: (prop) => downloadFile(prop.row.id, prop.row.isDocuware), + click: (prop) => + downloadFile( + prop.row.id, + $props.downloadModel, + null, + prop.row.download + ), }, { component: QBtn, name: 'edit', + external: false, props: () => ({ icon: 'edit', flat: true, @@ -164,6 +201,7 @@ const columns = computed(() => [ { component: QBtn, name: 'delete', + external: false, props: () => ({ icon: 'delete', flat: true, @@ -173,20 +211,22 @@ const columns = computed(() => [ }, { component: QBtn, - name: 'openDocuware', + name: 'open', + external: true, props: () => ({ icon: 'open_in_new', flat: true, color: 'primary', }), - click: () => openDocuware(), + click: (prop) => open(prop.row.url), }, ], }, ]); function setData(data) { - const newData = data.map((value) => value.dms); + const newData = data.map((value) => value.dms || value); + newData.sort((a, b) => new Date(b.created) - new Date(a.created)); rows.value = newData; } @@ -221,100 +261,105 @@ function parseDms(data) { return data; } -async function openDocuware() { - const url = await getUrlFindOne('WebClient', 'docuware'); - if (url) window.open(url).focus(); +async function open(url) { + window.open(url).focus(); } -function shouldRenderButton(buttonName, isDocuware = false) { - // Renderizar el botón si no se llama 'openDocuware' o (se llama 'openDocuware' y props.row.isDocuware = true) - return buttonName !== 'openDocuware' || (buttonName === 'openDocuware' && isDocuware); +function shouldRenderButton(button, isExternal = false) { + if (button.name == 'download') return true; + return button.external === isExternal; } </script> <template> - <FetchData + <VnPaginate ref="dmsRef" + :data-key="$props.model" :url="$props.model" :filter="dmsFilter" - :where="{ [$props.filter]: route.params.id }" + :order="['dmsFk DESC']" + :auto-load="true" @on-fetch="setData" - auto-load - /> - <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="flex justify-center" v-if="props.col.name == 'options'"> - <div v-for="button of props.col.components" :key="button.id"> - <component - v-if="shouldRenderButton(button.name, 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" + <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 - v-if=" - shouldRenderButton( - button.name, - props.row.isDocuware - ) - " - :is="button.component" - v-bind="button.props(col)" - @click="button.click(col)" - /> - </div> + </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> - </QItem> - </QList> - </QCard> - </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> - </QTable> + </VnPaginate> <QDialog v-model="formDialog.show"> <VnDms :model="updateModel ?? model" diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index d1b2f5cc..4cb2e6d6 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -110,7 +110,7 @@ async function paginate() { if (!arrayData.hasMoreData.value) { if (store.userParamsChanged) arrayData.hasMoreData.value = true; store.userParamsChanged = false; - isLoading.value = false; + endPagination(); return; } @@ -120,12 +120,14 @@ async function paginate() { pagination.value.sortBy = sortBy; pagination.value.descending = descending; - isLoading.value = false; + endPagination(); +} +function endPagination() { + isLoading.value = false; emit('onFetch', store.data); emit('onPaginate'); } - async function onLoad(index, done) { if (!store.data) { return done(); @@ -188,6 +190,12 @@ async function onLoad(index, done) { <QSpinner color="orange" size="md" /> </div> </QInfiniteScroll> + <div + v-if="!isLoading && arrayData.hasMoreData" + class="w-full flex justify-center q-mt-md" + > + <QBtn color="primary" :label="t('Load more data')" @click="paginate()" /> + </div> </template> <style lang="scss" scoped> @@ -204,4 +212,5 @@ async function onLoad(index, done) { es: No data to display: Sin datos que mostrar No results found: No se han encontrado resultados + Load more data: Cargar más resultados </i18n> diff --git a/src/components/ui/VnTree.vue b/src/components/ui/VnTree.vue index 9a99124c..13aa0563 100644 --- a/src/components/ui/VnTree.vue +++ b/src/components/ui/VnTree.vue @@ -76,7 +76,7 @@ const removeNode = (node) => { notify(t('department.departmentRemoved'), 'positive'); await fetchNodeLeaves(parentFk); } catch (err) { - console.log('Error removing department'); + console.error('Error removing department'); } }); }; diff --git a/src/composables/downloadFile.js b/src/composables/downloadFile.js index 45162f81..12639dcd 100644 --- a/src/composables/downloadFile.js +++ b/src/composables/downloadFile.js @@ -4,9 +4,8 @@ import { getUrl } from './getUrl'; const { getTokenMultimedia } = useSession(); const token = getTokenMultimedia(); -export async function downloadFile(dmsId, isDocuware = false) { +export async function downloadFile(id, model = 'dms', urlPath = '/downloadFile', url) { let appUrl = await getUrl('', 'lilium'); appUrl = appUrl.replace('/#/', ''); - const urlPath = isDocuware ? '/docuwareDownload' : '/downloadFile'; - window.open(`${appUrl}/api/dms/${dmsId}${urlPath}?access_token=${token}`); + window.open(url ?? `${appUrl}/api/${model}/${id}${urlPath}?access_token=${token}`); } diff --git a/src/composables/getUrl.js b/src/composables/getUrl.js index 7b710356..1e6aec4c 100644 --- a/src/composables/getUrl.js +++ b/src/composables/getUrl.js @@ -1,7 +1,4 @@ import axios from 'axios'; -import useNotify from 'src/composables/useNotify.js'; - -const { notify } = useNotify(); export async function getUrl(route, app = 'salix') { let url; @@ -11,24 +8,3 @@ export async function getUrl(route, app = 'salix') { }); return url; } - -export async function getUrlFindOne(route, app = 'salix') { - try { - const env = process.env.NODE_ENV; - - const filter = { - where: { and: [{ appName: app }, { environment: env }] }, - }; - - const { data } = await axios.get('Urls/findOne', { - params: { filter: JSON.stringify(filter) }, - }); - - if (!data) return null; - - return data.url + route; - } catch (err) { - notify('Direction not found', 'negative'); - console.error('Error finding url: ', err); - } -} diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index b6b81f2d..d32eeb32 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -98,7 +98,7 @@ export function useArrayData(key, userOptions) { const { limit } = filter; - hasMoreData.value = response.data.length === limit; + hasMoreData.value = response.data.length >= limit; if (append) { if (!store.data) store.data = []; diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js index ff86aec4..793fc42f 100644 --- a/src/i18n/en/index.js +++ b/src/i18n/en/index.js @@ -92,6 +92,8 @@ export default { log: 'Logs', parkingList: 'Parkings list', }, + created: 'Created', + worker: 'Worker', }, errors: { statusUnauthorized: 'Access denied', diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js index fbf8bc23..74e28903 100644 --- a/src/i18n/es/index.js +++ b/src/i18n/es/index.js @@ -92,6 +92,8 @@ export default { log: 'Historial', parkingList: 'Listado de parkings', }, + created: 'Fecha creación', + worker: 'Trabajador', }, errors: { statusUnauthorized: 'Acceso denegado', diff --git a/src/pages/Department/Card/DepartmentDescriptor.vue b/src/pages/Department/Card/DepartmentDescriptor.vue index 7049d414..e60a8c91 100644 --- a/src/pages/Department/Card/DepartmentDescriptor.vue +++ b/src/pages/Department/Card/DepartmentDescriptor.vue @@ -63,7 +63,7 @@ const removeDepartment = () => { router.push({ name: 'WorkerDepartment' }); notify('department.departmentRemoved', 'positive'); } catch (err) { - console.log('Error removing department'); + console.error('Error removing department'); } }); }; diff --git a/src/pages/Worker/Card/WorkerDms.vue b/src/pages/Worker/Card/WorkerDms.vue index d0c5cf5e..aef18d13 100644 --- a/src/pages/Worker/Card/WorkerDms.vue +++ b/src/pages/Worker/Card/WorkerDms.vue @@ -1,11 +1,14 @@ <script setup> import VnDmsList from 'src/components/common/VnDmsList.vue'; +import { useRoute } from 'vue-router'; +const route = useRoute(); </script> <template> <VnDmsList - model="WorkerDms" + :model="`WorkerDms/${route.params.id}/filter`" update-model="Workers" + download-model="WorkerDms" default-dms-code="hhrrData" - filter="workerFk" + filter="worker" /> </template>