Added attachment preview
Build and Deploy Web App / build-and-deploy (push) Successful in 18s
Details
Build and Deploy Web App / build-and-deploy (push) Successful in 18s
Details
This commit is contained in:
parent
92a3dc4c62
commit
dc0c48b2df
|
|
@ -18,10 +18,14 @@ export class AttachmentApiClient extends ApiClient {
|
||||||
this.profileName = getSelectedProfile(route)
|
this.profileName = getSelectedProfile(route)
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadAttachment(attachmentId: number, token: string) {
|
getAttachmentUrl(attachmentId: number, token: string) {
|
||||||
const url =
|
return (
|
||||||
import.meta.env.VITE_API_BASE_URL +
|
import.meta.env.VITE_API_BASE_URL +
|
||||||
`/profiles/${this.profileName}/attachments/${attachmentId}/download?t=${token}`
|
`/profiles/${this.profileName}/attachments/${attachmentId}/download?t=${token}`
|
||||||
window.open(url, '_blank')
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadAttachment(attachmentId: number, token: string) {
|
||||||
|
window.open(this.getAttachmentUrl(attachmentId, token), '_blank')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,40 @@ import { AttachmentApiClient } from '@/api/attachment'
|
||||||
import { useAuthStore } from '@/stores/auth-store'
|
import { useAuthStore } from '@/stores/auth-store'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import AppButton from './AppButton.vue'
|
import AppButton from './AppButton.vue'
|
||||||
|
import { computed, useTemplateRef, type Ref } from 'vue'
|
||||||
|
import ModalWrapper from './ModalWrapper.vue'
|
||||||
|
|
||||||
interface AttachmentInfo {
|
interface AttachmentInfo {
|
||||||
filename: string
|
filename: string
|
||||||
contentType: string
|
contentType: string
|
||||||
size: number
|
size: number
|
||||||
id?: number
|
id?: number
|
||||||
|
file?: File
|
||||||
}
|
}
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const api = new AttachmentApiClient(route)
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const props = defineProps<{ attachment: AttachmentInfo; disabled?: boolean }>()
|
const props = defineProps<{ attachment: AttachmentInfo; disabled?: boolean }>()
|
||||||
defineEmits<{ deleted: void }>()
|
defineEmits<{ deleted: void }>()
|
||||||
|
const srcUrl: Ref<string | null> = computed(() => {
|
||||||
|
if (props.attachment.file !== undefined) {
|
||||||
|
return URL.createObjectURL(props.attachment.file)
|
||||||
|
}
|
||||||
|
if (props.attachment.id === undefined || authStore.state === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return api.getAttachmentUrl(props.attachment.id, authStore.state.token)
|
||||||
|
})
|
||||||
|
const canPreviewAttachment = computed(() => {
|
||||||
|
if (!srcUrl.value) return false
|
||||||
|
const c = props.attachment.contentType
|
||||||
|
return c.startsWith('image') || c === 'application/pdf'
|
||||||
|
})
|
||||||
|
|
||||||
|
const attachmentViewerModal = useTemplateRef('attachmentViewer')
|
||||||
|
|
||||||
function downloadFile() {
|
function downloadFile() {
|
||||||
const api = new AttachmentApiClient(route)
|
|
||||||
if (!authStore.state) return
|
if (!authStore.state) return
|
||||||
api.downloadAttachment(props.attachment?.id ?? 0, authStore.state.token)
|
api.downloadAttachment(props.attachment?.id ?? 0, authStore.state.token)
|
||||||
}
|
}
|
||||||
|
|
@ -31,19 +50,39 @@ function downloadFile() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
<AppButton
|
||||||
|
icon="eye"
|
||||||
|
v-if="canPreviewAttachment"
|
||||||
|
@click="attachmentViewerModal?.show()"
|
||||||
|
></AppButton>
|
||||||
<AppButton
|
<AppButton
|
||||||
icon="download"
|
icon="download"
|
||||||
type="button"
|
|
||||||
@click="downloadFile()"
|
@click="downloadFile()"
|
||||||
v-if="attachment.id !== undefined"
|
v-if="attachment.id !== undefined"
|
||||||
/>
|
/>
|
||||||
<AppButton
|
<AppButton
|
||||||
v-if="!disabled"
|
v-if="!disabled"
|
||||||
type="button"
|
|
||||||
icon="trash"
|
icon="trash"
|
||||||
@click="$emit('deleted')"
|
@click="$emit('deleted')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ModalWrapper
|
||||||
|
ref="attachmentViewer"
|
||||||
|
v-if="canPreviewAttachment"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h3 style="margin-top: 0; margin-bottom: 0.25rem">{{ attachment.filename }}</h3>
|
||||||
|
<embed
|
||||||
|
:src="srcUrl ?? ''"
|
||||||
|
:type="attachment.contentType"
|
||||||
|
:class="{
|
||||||
|
'attachment-embed-img': attachment.contentType.startsWith('image'),
|
||||||
|
'attachment-embed-pdf': attachment.contentType === 'application/pdf',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ModalWrapper>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style lang="css">
|
<style lang="css">
|
||||||
|
|
@ -55,4 +94,13 @@ function downloadFile() {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.attachment-embed-img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment-embed-pdf {
|
||||||
|
min-width: 500px;
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,16 @@ defineExpose({ show, close })
|
||||||
color: inherit;
|
color: inherit;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
/* border: 3px solid var(--theme-secondary); */
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-modal-dialog::backdrop {
|
||||||
|
background-color: rgb(0 0 0 / 60%);
|
||||||
|
}
|
||||||
|
|
||||||
.app-modal-dialog-header {
|
.app-modal-dialog-header {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue