@testdracul/media-frontend 2.0.0 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -5
- package/.env.development +0 -4
- package/.env.example +0 -3
- package/.eslintrc.json +0 -25
- package/babel.config.js +0 -5
- package/docs-en.md +0 -45
- package/docs-es.md +0 -45
- package/src/components/CsvWebViewer/CsvWebViewer.vue +0 -81
- package/src/components/CsvWebViewer/index.ts +0 -4
- package/src/components/FileUpload/FileUpload.vue +0 -94
- package/src/components/FileUpload/index.ts +0 -4
- package/src/components/FileUploadButton/FileUploadButton.vue +0 -127
- package/src/components/FileUploadButton/index.ts +0 -4
- package/src/components/FileUploadExpiration/FileUploadExpiration.vue +0 -274
- package/src/components/FileUploadExpiration/index.ts +0 -4
- package/src/components/FileUploadExpress/FileUploadExpress.vue +0 -208
- package/src/components/FileUploadExpress/index.ts +0 -4
- package/src/components/FileView/FileView.vue +0 -336
- package/src/components/FileView/index.ts +0 -4
- package/src/components/GroupsShow/GroupsShow.vue +0 -40
- package/src/components/GroupsShow/index.ts +0 -4
- package/src/components/MediaField/MediaField.vue +0 -62
- package/src/components/MediaField/index.ts +0 -4
- package/src/components/PdfWebViewer/PdfWebViewer.vue +0 -81
- package/src/components/PdfWebViewer/index.ts +0 -4
- package/src/components/UsersShow/UsersShow.vue +0 -39
- package/src/components/UsersShow/index.ts +0 -4
- package/src/components/XlsxWebViewer/XlsxWebViewer.vue +0 -70
- package/src/components/XlsxWebViewer/index.ts +0 -4
- package/src/helpers/redeableBytes.ts +0 -9
- package/src/i18n/index.ts +0 -22
- package/src/i18n/messages/DocMessages.ts +0 -31
- package/src/i18n/messages/ExtraMessages.ts +0 -29
- package/src/i18n/messages/FileMessages.ts +0 -223
- package/src/i18n/messages/UserStorageMessages.ts +0 -145
- package/src/i18n/permissions/FilePermissionMessages.ts +0 -50
- package/src/i18n/permissions/OldPermissionMessages.ts +0 -59
- package/src/i18n/permissions/UserStoragePermissionMessages.ts +0 -40
- package/src/index.ts +0 -70
- package/src/mixins/readableBytesMixin.ts +0 -9
- package/src/pages/FileManagementPage/FileCreate/FileCreate.vue +0 -108
- package/src/pages/FileManagementPage/FileCreate/index.ts +0 -3
- package/src/pages/FileManagementPage/FileCrud/FileCrud.vue +0 -133
- package/src/pages/FileManagementPage/FileCrud/index.ts +0 -4
- package/src/pages/FileManagementPage/FileDelete/FileDelete.vue +0 -61
- package/src/pages/FileManagementPage/FileDelete/index.ts +0 -3
- package/src/pages/FileManagementPage/FileFilters/FileFilters.vue +0 -150
- package/src/pages/FileManagementPage/FileFilters/index.ts +0 -3
- package/src/pages/FileManagementPage/FileForm/FileForm.vue +0 -184
- package/src/pages/FileManagementPage/FileForm/UserCombobox.vue +0 -66
- package/src/pages/FileManagementPage/FileForm/index.ts +0 -3
- package/src/pages/FileManagementPage/FileList/FileEditButton.vue +0 -410
- package/src/pages/FileManagementPage/FileList/FileList.vue +0 -178
- package/src/pages/FileManagementPage/FileList/index.ts +0 -4
- package/src/pages/FileManagementPage/FileShow/FileShow.vue +0 -23
- package/src/pages/FileManagementPage/FileShow/FileShowData.vue +0 -35
- package/src/pages/FileManagementPage/FileShow/index.ts +0 -3
- package/src/pages/FileManagementPage/FileUpdate/FileUpdate.vue +0 -107
- package/src/pages/FileManagementPage/FileUpdate/index.ts +0 -4
- package/src/pages/FileManagementPage/index.vue +0 -20
- package/src/pages/MediaDocPage/MediaDocCard.vue +0 -35
- package/src/pages/MediaDocPage/MediaDocPage.vue +0 -78
- package/src/pages/UserStoragePage/UserStorage.vue +0 -311
- package/src/pages/UserStoragePage/UserStorageForm/UserStorageForm.vue +0 -172
- package/src/pages/UserStoragePage/UserStorageUpdate/UserStorageUpdate.vue +0 -91
- package/src/pages/UserStoragePage/index.vue +0 -14
- package/src/providers/FileMetricsProvider.ts +0 -47
- package/src/providers/FileProvider.ts +0 -60
- package/src/providers/UploadProvider.ts +0 -32
- package/src/providers/UserStorageProvider.ts +0 -47
- package/src/providers/gql/almacenamientoPorUsuario.graphql +0 -10
- package/src/providers/gql/cantidadArchivosPorUsuario.graphql +0 -10
- package/src/providers/gql/fetchMediaVariables.graphql +0 -6
- package/src/providers/gql/fileCreate.graphql +0 -27
- package/src/providers/gql/fileDelete.graphql +0 -7
- package/src/providers/gql/fileFetch.graphql +0 -29
- package/src/providers/gql/fileFind.graphql +0 -29
- package/src/providers/gql/fileGlobalMetrics.graphql +0 -6
- package/src/providers/gql/filePaginate.graphql +0 -38
- package/src/providers/gql/fileUpdate.graphql +0 -29
- package/src/providers/gql/fileUpload.graphql +0 -29
- package/src/providers/gql/fileUploadAnonymous.graphql +0 -25
- package/src/providers/gql/fileUserMetrics.graphql +0 -9
- package/src/providers/gql/userStorageFetch.graphql +0 -17
- package/src/providers/gql/userStorageFindByUser.graphql +0 -17
- package/src/providers/gql/userStorageUpdate.graphql +0 -31
- package/src/routes/index.ts +0 -32
- package/vite.config.ts +0 -65
- package/vue.config.js +0 -22
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<v-container v-if="file" class="pt-0 mt-0 mainContainer">
|
|
3
|
-
<v-tabs v-model="activeTab" color="primary">
|
|
4
|
-
<v-tab value="previewTab">Previsualización</v-tab>
|
|
5
|
-
<v-tab value="metadataTab">Metadata</v-tab>
|
|
6
|
-
<v-tab value="privacyTab">Privacidad</v-tab>
|
|
7
|
-
<v-tab value="fileHistoryTab">Historial</v-tab>
|
|
8
|
-
</v-tabs>
|
|
9
|
-
|
|
10
|
-
<v-divider class="mb-4"></v-divider>
|
|
11
|
-
|
|
12
|
-
<v-window v-model="activeTab">
|
|
13
|
-
<v-window-item value="previewTab">
|
|
14
|
-
<div v-if="!isImage && !isAudio && !isVideo && !isPdf">
|
|
15
|
-
<csv-web-viewer v-if="isCsv && fileObjectUrl" :url="fileObjectUrl"></csv-web-viewer>
|
|
16
|
-
<xlsx-web-viewer v-if="isXlsx && fileObjectUrl" :url="fileObjectUrl"></xlsx-web-viewer>
|
|
17
|
-
<v-btn block v-if="hasPermission('FILE_DOWNLOAD')" @click="downloadFile" class="text-uppercase mb-2" color="success">
|
|
18
|
-
<v-icon icon="mdi-arrow-down-bold-circle"></v-icon>
|
|
19
|
-
{{ $t('media.file.download') }}
|
|
20
|
-
</v-btn>
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<v-img v-if="isImage && fileObjectUrl" :src="fileObjectUrl" width="100%"></v-img>
|
|
24
|
-
|
|
25
|
-
<audio v-if="isAudio && fileObjectUrl" controls :src="fileObjectUrl" :type="file.mimetype" width="100%"></audio>
|
|
26
|
-
|
|
27
|
-
<video v-if="isVideo && fileObjectUrl" width="100%" controls :src="fileObjectUrl" :type="file.mimetype"></video>
|
|
28
|
-
|
|
29
|
-
<v-container fluid>
|
|
30
|
-
<v-alert v-if="hasFileLoadingError" type="error" density="compact">
|
|
31
|
-
Error al cargar el archivo (CORS o permisos).
|
|
32
|
-
</v-alert>
|
|
33
|
-
<pdf-web-viewer v-if="isPdf && fileObjectUrl" :url="fileObjectUrl" style="max-height: 50vh; overflow: auto;"></pdf-web-viewer>
|
|
34
|
-
</v-container>
|
|
35
|
-
</v-window-item>
|
|
36
|
-
|
|
37
|
-
<v-window-item value="metadataTab">
|
|
38
|
-
<v-list lines="two">
|
|
39
|
-
<v-row dense>
|
|
40
|
-
<v-col cols="12" md="6">
|
|
41
|
-
<show-field :model-value="file.id" :label="$t('media.file.id')" icon="mdi-badge"/>
|
|
42
|
-
</v-col>
|
|
43
|
-
<v-col cols="12" md="6">
|
|
44
|
-
<show-field :model-value="file.filename" :label="$t('media.file.filename')" icon="mdi-text-short"/>
|
|
45
|
-
</v-col>
|
|
46
|
-
<v-col cols="12">
|
|
47
|
-
<show-field :model-value="file.description" :label="$t('media.file.description')" icon="mdi-text-box"/>
|
|
48
|
-
</v-col>
|
|
49
|
-
<v-col cols="12" md="6">
|
|
50
|
-
<show-field :model-value="file.mimetype" :label="$t('media.file.mimetype')" icon="mdi-folder"/>
|
|
51
|
-
</v-col>
|
|
52
|
-
<v-col cols="12" md="6">
|
|
53
|
-
<show-field :model-value="getSizeInMegaBytes" :label="$t('media.file.size')" icon="mdi-weight"/>
|
|
54
|
-
</v-col>
|
|
55
|
-
<v-col cols="12" md="6">
|
|
56
|
-
<show-chip-field :chips="file.tags" :label="$t('media.file.tags')" icon="mdi-tag"/>
|
|
57
|
-
</v-col>
|
|
58
|
-
<v-col cols="12" md="6">
|
|
59
|
-
<show-field :model-value="hits" :label="$t('media.file.hits')" icon="mdi-eye"/>
|
|
60
|
-
</v-col>
|
|
61
|
-
|
|
62
|
-
<v-col cols="12">
|
|
63
|
-
<v-list-item v-if="hasPermission('FILE_DOWNLOAD')">
|
|
64
|
-
<template v-slot:prepend>
|
|
65
|
-
<v-btn size="small" icon @click="copyToClipboard" class="mr-4">
|
|
66
|
-
<v-icon color="black">mdi-content-copy</v-icon>
|
|
67
|
-
</v-btn>
|
|
68
|
-
<input type="hidden" id="url" :value="file.url">
|
|
69
|
-
</template>
|
|
70
|
-
<v-list-item-title>
|
|
71
|
-
{{ file.url }}
|
|
72
|
-
<v-btn size="x-small" icon color="blue" variant="text" @click="openFileInNewTab" class="ml-2">
|
|
73
|
-
<v-icon>mdi-launch</v-icon>
|
|
74
|
-
</v-btn>
|
|
75
|
-
</v-list-item-title>
|
|
76
|
-
<v-list-item-subtitle>URL del archivo</v-list-item-subtitle>
|
|
77
|
-
</v-list-item>
|
|
78
|
-
|
|
79
|
-
<v-list-item v-else>
|
|
80
|
-
<template v-slot:prepend>
|
|
81
|
-
<v-icon color="black" class="mr-5">mdi-book-open</v-icon>
|
|
82
|
-
</template>
|
|
83
|
-
<v-list-item-title v-if="isPdf">
|
|
84
|
-
Abrir en nueva pestaña
|
|
85
|
-
<v-btn size="x-small" icon color="blue" variant="text" @click="openFileInNewTab" class="ml-2">
|
|
86
|
-
<v-icon>mdi-launch</v-icon>
|
|
87
|
-
</v-btn>
|
|
88
|
-
</v-list-item-title>
|
|
89
|
-
</v-list-item>
|
|
90
|
-
</v-col>
|
|
91
|
-
</v-row>
|
|
92
|
-
</v-list>
|
|
93
|
-
|
|
94
|
-
<v-snackbar v-model="showClipboardSnackbar" :timeout="2000">
|
|
95
|
-
{{ clipboardSnackbarText }}
|
|
96
|
-
<template v-slot:actions>
|
|
97
|
-
<v-btn color="pink" variant="text" @click="showClipboardSnackbar = false">
|
|
98
|
-
<v-icon>mdi-close</v-icon>
|
|
99
|
-
</v-btn>
|
|
100
|
-
</template>
|
|
101
|
-
</v-snackbar>
|
|
102
|
-
</v-window-item>
|
|
103
|
-
|
|
104
|
-
<v-window-item value="privacyTab">
|
|
105
|
-
<v-list lines="two">
|
|
106
|
-
<show-field :model-value="isPublic" label="Privacidad del archivo" icon="mdi-cctv"/>
|
|
107
|
-
<v-divider class="my-2"></v-divider>
|
|
108
|
-
<groups-show v-if="hasPermission('SECURITY_GROUP_SHOW')" :fileIdGroups="file.groups"></groups-show>
|
|
109
|
-
<v-divider class="my-2"></v-divider>
|
|
110
|
-
<users-show v-if="hasPermission('SECURITY_USER_SHOW')" :fileIdUsers="file.users"></users-show>
|
|
111
|
-
</v-list>
|
|
112
|
-
</v-window-item>
|
|
113
|
-
|
|
114
|
-
<v-window-item value="fileHistoryTab">
|
|
115
|
-
<v-data-table
|
|
116
|
-
:headers="[{title: t('media.file.history.date'), key: 'date', sortable: true, align: 'center'}, {title: t('media.file.history.user'), key: 'username', sortable: true, align: 'center'}]"
|
|
117
|
-
:items="formattedFileReplaces"
|
|
118
|
-
:items-per-page="5"
|
|
119
|
-
:items-per-page-options="[5, 10, 25, 50]"
|
|
120
|
-
:items-per-page-text="t('common.itemsPerPageText')"
|
|
121
|
-
class="elevation-1"
|
|
122
|
-
density="compact"
|
|
123
|
-
></v-data-table>
|
|
124
|
-
</v-window-item>
|
|
125
|
-
</v-window>
|
|
126
|
-
</v-container>
|
|
127
|
-
</template>
|
|
128
|
-
|
|
129
|
-
<script setup>
|
|
130
|
-
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
|
|
131
|
-
import { useStore } from 'vuex'
|
|
132
|
-
import { useI18n } from 'vue-i18n'
|
|
133
|
-
import { ShowField, ShowChipField } from '@testdracul/common-frontend'
|
|
134
|
-
import { useDayjs } from '@testdracul/dayjs-frontend'
|
|
135
|
-
import PdfWebViewer from '../PdfWebViewer'
|
|
136
|
-
import GroupsShow from '../GroupsShow'
|
|
137
|
-
import UsersShow from '../UsersShow'
|
|
138
|
-
import CsvWebViewer from '../CsvWebViewer'
|
|
139
|
-
import XlsxWebViewer from '../XlsxWebViewer'
|
|
140
|
-
|
|
141
|
-
const props = defineProps({
|
|
142
|
-
file: { type: Object }
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
const { t } = useI18n()
|
|
146
|
-
const store = useStore()
|
|
147
|
-
const { getDateTimeFormat } = useDayjs()
|
|
148
|
-
|
|
149
|
-
const showClipboardSnackbar = ref(false)
|
|
150
|
-
const clipboardSnackbarText = ref('')
|
|
151
|
-
const activeTab = ref(null)
|
|
152
|
-
const fileObjectUrl = ref(null)
|
|
153
|
-
const isFileLoading = ref(false)
|
|
154
|
-
const hasFileLoadingError = ref(false)
|
|
155
|
-
|
|
156
|
-
const formattedFileReplaces = computed(() => {
|
|
157
|
-
if (!props.file || !props.file.fileReplaces) return []
|
|
158
|
-
return props.file.fileReplaces.map(item => ({
|
|
159
|
-
...item,
|
|
160
|
-
date: formatDate(item.date)
|
|
161
|
-
}))
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
const hasPermission = (permission) => {
|
|
165
|
-
return store.getters.hasPermission(permission)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const isImage = computed(() => {
|
|
169
|
-
return (props.file && props.file.type === 'image')
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
const isAudio = computed(() => {
|
|
173
|
-
return (props.file && props.file.type === 'audio')
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
const isVideo = computed(() => {
|
|
177
|
-
return (props.file && props.file.type === 'video')
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
const isPdf = computed(() => {
|
|
181
|
-
return (props.file && props.file.mimetype === 'application/pdf')
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
const isCsv = computed(() => {
|
|
185
|
-
return (props.file && props.file.extension === ".csv")
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
const isXlsx = computed(() => {
|
|
189
|
-
return (props.file && props.file.extension === ".xlsx")
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
const getSizeInMegaBytes = computed(() => {
|
|
193
|
-
return props.file.size.toFixed(5) + ' MB'
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
const hits = computed(() => {
|
|
197
|
-
return (props.file && String(props.file.hits))
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
const isPublic = computed(() => {
|
|
201
|
-
return props.file.isPublic ? 'Público' : 'Privado'
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
const formatDate = (date) => {
|
|
205
|
-
return getDateTimeFormat(date, true)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const fetchFileWithAuth = async (returnFullResponse = false) => {
|
|
209
|
-
const authToken = store.state.user.access_token
|
|
210
|
-
if (!authToken || !props.file.url) return null
|
|
211
|
-
|
|
212
|
-
const response = await fetch(props.file.url, {
|
|
213
|
-
method: 'GET',
|
|
214
|
-
headers: { 'Authorization': `Bearer ${authToken}` },
|
|
215
|
-
cache: 'no-store'
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
if (!response.ok) throw new Error(`Error fetching file: ${response.status} ${response.statusText}`)
|
|
219
|
-
|
|
220
|
-
const blobData = await response.blob()
|
|
221
|
-
const finalBlob = (blobData && blobData.type) ? blobData : new Blob([blobData], { type: (props.file.mimetype || 'application/octet-stream') })
|
|
222
|
-
|
|
223
|
-
if (returnFullResponse) return { response, blob: finalBlob }
|
|
224
|
-
return finalBlob
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const loadFileAsBlob = async () => {
|
|
228
|
-
if (!props.file || !props.file.url) return
|
|
229
|
-
|
|
230
|
-
isFileLoading.value = true
|
|
231
|
-
hasFileLoadingError.value = false
|
|
232
|
-
revokeFileUrl()
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
const blob = await fetchFileWithAuth()
|
|
236
|
-
if (!blob) {
|
|
237
|
-
hasFileLoadingError.value = true
|
|
238
|
-
return
|
|
239
|
-
}
|
|
240
|
-
fileObjectUrl.value = URL.createObjectURL(blob)
|
|
241
|
-
} catch (error) {
|
|
242
|
-
console.error("Error loading file as blob:", error)
|
|
243
|
-
hasFileLoadingError.value = true
|
|
244
|
-
} finally {
|
|
245
|
-
isFileLoading.value = false
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const revokeFileUrl = () => {
|
|
250
|
-
if (fileObjectUrl.value) {
|
|
251
|
-
URL.revokeObjectURL(fileObjectUrl.value)
|
|
252
|
-
fileObjectUrl.value = null
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const downloadFile = async () => {
|
|
257
|
-
try {
|
|
258
|
-
const { response, blob } = await fetchFileWithAuth(true)
|
|
259
|
-
if (!response) return
|
|
260
|
-
|
|
261
|
-
const contentDispositionHeader = response.headers.get('content-disposition') || ''
|
|
262
|
-
const filenameFromHeader = extractFilenameFromContentDisposition(contentDispositionHeader)
|
|
263
|
-
const filename = filenameFromHeader || props.file.filename || 'download'
|
|
264
|
-
|
|
265
|
-
const objectUrl = URL.createObjectURL(blob)
|
|
266
|
-
const downloadLink = document.createElement('a')
|
|
267
|
-
downloadLink.href = objectUrl
|
|
268
|
-
downloadLink.download = filename
|
|
269
|
-
document.body.appendChild(downloadLink)
|
|
270
|
-
downloadLink.click()
|
|
271
|
-
document.body.removeChild(downloadLink)
|
|
272
|
-
setTimeout(() => URL.revokeObjectURL(objectUrl), 150)
|
|
273
|
-
} catch (error) {
|
|
274
|
-
console.error("Error downloading file:", error)
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const extractFilenameFromContentDisposition = (headerValue) => {
|
|
279
|
-
if (!headerValue) return null
|
|
280
|
-
const match = headerValue.match(/filename\*?=(?:UTF-8'')?["']?([^;"']+)/i)
|
|
281
|
-
if (!match) return null
|
|
282
|
-
try {
|
|
283
|
-
return decodeURIComponent(match[1].replace(/["']/g, ''))
|
|
284
|
-
} catch (e) {
|
|
285
|
-
return match[1].replace(/["']/g, '')
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const openFileInNewTab = async () => {
|
|
290
|
-
if (fileObjectUrl.value) {
|
|
291
|
-
window.open(fileObjectUrl.value, '_blank')
|
|
292
|
-
return
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
try {
|
|
296
|
-
const blob = await fetchFileWithAuth()
|
|
297
|
-
if (blob) {
|
|
298
|
-
const objectUrl = URL.createObjectURL(blob)
|
|
299
|
-
window.open(objectUrl, '_blank')
|
|
300
|
-
}
|
|
301
|
-
} catch (error) {
|
|
302
|
-
console.error("Could not open file in new tab:", error)
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const copyToClipboard = async () => {
|
|
307
|
-
const urlToCopy = props.file.url || ''
|
|
308
|
-
try {
|
|
309
|
-
await navigator.clipboard.writeText(urlToCopy)
|
|
310
|
-
clipboardSnackbarText.value = 'URL copiada al portapapeles'
|
|
311
|
-
showClipboardSnackbar.value = true
|
|
312
|
-
} catch (error) {
|
|
313
|
-
clipboardSnackbarText.value = 'Error al copiar la URL'
|
|
314
|
-
showClipboardSnackbar.value = true
|
|
315
|
-
console.error('Failed to copy to clipboard:', error)
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
watch(() => props.file?.url, (newUrl, oldUrl) => {
|
|
320
|
-
if (newUrl !== oldUrl) loadFileAsBlob()
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
onMounted(() => {
|
|
324
|
-
loadFileAsBlob()
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
onBeforeUnmount(() => {
|
|
328
|
-
revokeFileUrl()
|
|
329
|
-
})
|
|
330
|
-
</script>
|
|
331
|
-
|
|
332
|
-
<style scoped>
|
|
333
|
-
.mainContainer {
|
|
334
|
-
max-height: 65vh;
|
|
335
|
-
}
|
|
336
|
-
</style>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<show-chip-field :chips="fileGroups" :label="$t('media.file.groups')" icon="mdi-account-group"/>
|
|
3
|
-
</template>
|
|
4
|
-
|
|
5
|
-
<script setup>
|
|
6
|
-
import { ref, onMounted } from 'vue'
|
|
7
|
-
import { groupProvider } from "@testdracul/user-frontend"
|
|
8
|
-
import { ShowChipField } from '@testdracul/common-frontend'
|
|
9
|
-
|
|
10
|
-
const props = defineProps({
|
|
11
|
-
fileIdGroups: { type: Array },
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const fileGroups = ref([])
|
|
15
|
-
const sharedWith = ref('')
|
|
16
|
-
|
|
17
|
-
onMounted(() => {
|
|
18
|
-
groupProvider.groups().then((result) => {
|
|
19
|
-
if(!props.fileIdGroups) return;
|
|
20
|
-
fileGroups.value = result.data.groups.filter((group) => props.fileIdGroups.includes(group.id))
|
|
21
|
-
|
|
22
|
-
if(fileGroups.value.length > 1){
|
|
23
|
-
for (let groupsCounter = 0; groupsCounter < fileGroups.value.length; groupsCounter++) {
|
|
24
|
-
if (groupsCounter == 0){
|
|
25
|
-
sharedWith.value += `${fileGroups.value[groupsCounter].name}`
|
|
26
|
-
}else{
|
|
27
|
-
sharedWith.value += `, ${fileGroups.value[groupsCounter].name}`
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}else if (fileGroups.value.length == 1){
|
|
31
|
-
sharedWith.value = fileGroups.value[0].name
|
|
32
|
-
}else{
|
|
33
|
-
sharedWith.value = '-'
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
</script>
|
|
38
|
-
|
|
39
|
-
<style scoped>
|
|
40
|
-
</style>
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<v-row>
|
|
3
|
-
<v-col class="flex-grow-1 flex-shrink-0">
|
|
4
|
-
<v-text-field
|
|
5
|
-
:prepend-inner-icon="icon"
|
|
6
|
-
:name="fieldName"
|
|
7
|
-
v-model="field"
|
|
8
|
-
:label="$te(label) ? $t(label) : label"
|
|
9
|
-
:placeholder="label"
|
|
10
|
-
:error="hasInputErrors(fieldName)"
|
|
11
|
-
:error-messages="getInputErrors(fieldName)"
|
|
12
|
-
color="secondary"
|
|
13
|
-
:rules="isRequired ? required : []"
|
|
14
|
-
:readonly="readOnly"
|
|
15
|
-
></v-text-field>
|
|
16
|
-
</v-col>
|
|
17
|
-
<v-col class="flex-shrink-0 flex-grow-0">
|
|
18
|
-
<file-upload-express :accept="accept"
|
|
19
|
-
:auto-submit="true"
|
|
20
|
-
@fileUploaded="imageUploaded"
|
|
21
|
-
/>
|
|
22
|
-
</v-col>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
</v-row>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<script setup>
|
|
29
|
-
import { computed } from 'vue'
|
|
30
|
-
import {InputErrorsByProps, RequiredRule} from "@testdracul/common-frontend";
|
|
31
|
-
import FileUploadExpress from "../FileUploadExpress";
|
|
32
|
-
|
|
33
|
-
const props = defineProps({
|
|
34
|
-
fieldName: {type: String, required: false, default: "file"},
|
|
35
|
-
modelValue: {type: String, required: true},
|
|
36
|
-
label: {type: String, required: false, default: "media.file.chooseFile"},
|
|
37
|
-
accept: {type: String, default: "*"},
|
|
38
|
-
icon: {type: String, required: false, default: "mdi-paperclip"},
|
|
39
|
-
isRequired: {type: Boolean, default: false},
|
|
40
|
-
readOnly: {type: Boolean,default: false},
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const emit = defineEmits(['update:modelValue', 'fileUploaded'])
|
|
44
|
-
|
|
45
|
-
const field = computed({
|
|
46
|
-
get() {
|
|
47
|
-
return props.modelValue
|
|
48
|
-
},
|
|
49
|
-
set(val) {
|
|
50
|
-
emit('update:modelValue', val)
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const imageUploaded = (file) => {
|
|
55
|
-
emit('fileUploaded', file)
|
|
56
|
-
field.value = file.url
|
|
57
|
-
}
|
|
58
|
-
</script>
|
|
59
|
-
|
|
60
|
-
<style scoped>
|
|
61
|
-
|
|
62
|
-
</style>
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div id="app" class="pdfViewer">
|
|
3
|
-
<div class="app-header">
|
|
4
|
-
<template v-if="isLoading">
|
|
5
|
-
Loading...
|
|
6
|
-
</template>
|
|
7
|
-
|
|
8
|
-
<template v-else>
|
|
9
|
-
|
|
10
|
-
<span class="d-flex">
|
|
11
|
-
<v-spacer/>
|
|
12
|
-
<v-btn :disabled="page <= 1" @click="page--">❮</v-btn>
|
|
13
|
-
<v-spacer/>
|
|
14
|
-
{{ page }} / {{ totalPages }}
|
|
15
|
-
<v-spacer/>
|
|
16
|
-
<v-btn :disabled="page >= totalPages" @click="page++">❯</v-btn>
|
|
17
|
-
<v-spacer/>
|
|
18
|
-
|
|
19
|
-
</span>
|
|
20
|
-
</template>
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<v-card height="100%" flat>
|
|
24
|
-
<v-spacer/>
|
|
25
|
-
<vue-pdf-embed
|
|
26
|
-
ref="pdfRef"
|
|
27
|
-
:source="pdfSource"
|
|
28
|
-
:page="page"
|
|
29
|
-
@rendered="handleDocumentRender"
|
|
30
|
-
/>
|
|
31
|
-
</v-card>
|
|
32
|
-
</div>
|
|
33
|
-
</template>
|
|
34
|
-
|
|
35
|
-
<script setup>
|
|
36
|
-
import { ref, computed, onMounted } from 'vue'
|
|
37
|
-
import { useStore } from 'vuex'
|
|
38
|
-
import { Buffer } from 'buffer'
|
|
39
|
-
|
|
40
|
-
global.Buffer = global.Buffer || Buffer
|
|
41
|
-
|
|
42
|
-
import VuePdfEmbed from 'vue-pdf-embed'
|
|
43
|
-
|
|
44
|
-
const props = defineProps({
|
|
45
|
-
url: { type: String },
|
|
46
|
-
width: { type: String }
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
const store = useStore()
|
|
50
|
-
|
|
51
|
-
const pdfSource = ref(props.url)
|
|
52
|
-
const page = ref(1)
|
|
53
|
-
const totalPages = ref(null)
|
|
54
|
-
const isLoading = ref(true)
|
|
55
|
-
const pdfRef = ref(null)
|
|
56
|
-
|
|
57
|
-
const me = computed(() => store.getters.me)
|
|
58
|
-
|
|
59
|
-
const handleDocumentRender = () => {
|
|
60
|
-
isLoading.value = false
|
|
61
|
-
totalPages.value = pdfRef.value.pageCount
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const avoidPrint = () => {
|
|
65
|
-
if (!me.value?.role?.permissions.includes('FILE_SHOW_OWN')) {
|
|
66
|
-
window.onbeforeprint = () => {
|
|
67
|
-
let url = window.location.href
|
|
68
|
-
window.location.href = url
|
|
69
|
-
alert("No tiene permisos para imprimir")
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
watch(() => props.url, (newValue) => {
|
|
75
|
-
pdfSource.value = newValue
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
onMounted(() => {
|
|
79
|
-
avoidPrint()
|
|
80
|
-
})
|
|
81
|
-
</script>
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<show-chip-field :chips="fileUsers" :label="$t('media.file.users')" icon="mdi-account"/>
|
|
3
|
-
</template>
|
|
4
|
-
|
|
5
|
-
<script setup>
|
|
6
|
-
import { ref, onMounted } from 'vue'
|
|
7
|
-
import { userProvider } from "@testdracul/user-frontend"
|
|
8
|
-
import { ShowChipField } from '@testdracul/common-frontend'
|
|
9
|
-
|
|
10
|
-
const props = defineProps({
|
|
11
|
-
fileIdUsers: { type: Array },
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const fileUsers = ref([])
|
|
15
|
-
const sharedWith = ref('')
|
|
16
|
-
|
|
17
|
-
onMounted(() => {
|
|
18
|
-
userProvider.users().then((result) => {
|
|
19
|
-
fileUsers.value = result.data.users.filter((user) => props.fileIdUsers.includes(user.id))
|
|
20
|
-
|
|
21
|
-
if(fileUsers.value.length > 1){
|
|
22
|
-
for (let userCounter = 0; userCounter < fileUsers.value.length; userCounter++) {
|
|
23
|
-
if (userCounter == 0){
|
|
24
|
-
sharedWith.value += `${fileUsers.value[userCounter].name}`
|
|
25
|
-
}else{
|
|
26
|
-
sharedWith.value += `, ${fileUsers.value[userCounter].name}`
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}else if (fileUsers.value.length == 1){
|
|
30
|
-
sharedWith.value = fileUsers.value[0].name
|
|
31
|
-
}else{
|
|
32
|
-
sharedWith.value = '-'
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
})
|
|
36
|
-
</script>
|
|
37
|
-
|
|
38
|
-
<style scoped>
|
|
39
|
-
</style>
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<v-data-table class="mx-auto elevation-1" height="50vh" fixed-header :hide-default-footer="!pagination"
|
|
4
|
-
:items-per-page="10" :disable-pagination="!pagination" :headers="headers" :items="content"
|
|
5
|
-
:no-data-text="noDataText"></v-data-table>
|
|
6
|
-
<snackbar v-model="snackbarMessage" :color="snackbarColor" :timeout="snackbarTimeOut"
|
|
7
|
-
@update:modelValue="val => !val && (snackbarMessage = null)" />
|
|
8
|
-
</div>
|
|
9
|
-
</template>
|
|
10
|
-
|
|
11
|
-
<script setup>
|
|
12
|
-
import { ref, computed, onMounted } from 'vue'
|
|
13
|
-
import { Snackbar } from "@testdracul/common-frontend";
|
|
14
|
-
import * as XLSX from "xlsx"
|
|
15
|
-
|
|
16
|
-
const props = defineProps({
|
|
17
|
-
url: { type: String }
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const headers = ref([])
|
|
21
|
-
const content = ref([])
|
|
22
|
-
const snackbarColor = ref("")
|
|
23
|
-
const snackbarMessage = ref("")
|
|
24
|
-
const snackbarTimeOut = ref(3000)
|
|
25
|
-
const noDataText = ref("No se pudo procesar la información del xlsx. Por favor intente nuevamente más tarde!")
|
|
26
|
-
|
|
27
|
-
const pagination = computed(() => content.value.length > 10)
|
|
28
|
-
|
|
29
|
-
const parseFileXlsx = async () => {
|
|
30
|
-
try {
|
|
31
|
-
const file = await fetch(props.url)
|
|
32
|
-
const fileArrayBuffer = await file.arrayBuffer()
|
|
33
|
-
|
|
34
|
-
const xlsxFile = XLSX.read(new Uint8Array(fileArrayBuffer, { type: 'array' }))
|
|
35
|
-
const jsonSheets = XLSX.utils.sheet_to_json(xlsxFile.Sheets[xlsxFile.SheetNames[0]])
|
|
36
|
-
|
|
37
|
-
if (jsonSheets.length < 0) {
|
|
38
|
-
noDataText.value = 'No existen datos en este registro'
|
|
39
|
-
} else {
|
|
40
|
-
jsonSheets.forEach((element, index) => {
|
|
41
|
-
if (index === 0) {
|
|
42
|
-
Object.keys(element).forEach(key => {
|
|
43
|
-
let width = key?.length * 6
|
|
44
|
-
|
|
45
|
-
jsonSheets.forEach(data => {
|
|
46
|
-
if (width < (data[key]?.length || 0) * 6) width = (data[key]?.length || 0) * 6
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
headers.value.push(
|
|
50
|
-
{
|
|
51
|
-
width,
|
|
52
|
-
title: key,
|
|
53
|
-
value: key,
|
|
54
|
-
sortable: false
|
|
55
|
-
}
|
|
56
|
-
)
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
content.value.push(element)
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
63
|
-
noDataText.value = `Error al parsear el archivo xlsx, error: ${error}`
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
onMounted(() => {
|
|
68
|
-
parseFileXlsx()
|
|
69
|
-
})
|
|
70
|
-
</script>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const readableBytes = function (bytes) {
|
|
2
|
-
var i = Math.floor(Math.log(bytes) / Math.log(1024)),
|
|
3
|
-
sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
4
|
-
|
|
5
|
-
return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export {readableBytes}
|
|
9
|
-
export default readableBytes
|