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)
|
||||
}
|
||||
|
||||
downloadAttachment(attachmentId: number, token: string) {
|
||||
const url =
|
||||
getAttachmentUrl(attachmentId: number, token: string) {
|
||||
return (
|
||||
import.meta.env.VITE_API_BASE_URL +
|
||||
`/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 { useRoute } from 'vue-router'
|
||||
import AppButton from './AppButton.vue'
|
||||
import { computed, useTemplateRef, type Ref } from 'vue'
|
||||
import ModalWrapper from './ModalWrapper.vue'
|
||||
|
||||
interface AttachmentInfo {
|
||||
filename: string
|
||||
contentType: string
|
||||
size: number
|
||||
id?: number
|
||||
file?: File
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const api = new AttachmentApiClient(route)
|
||||
const authStore = useAuthStore()
|
||||
const props = defineProps<{ attachment: AttachmentInfo; disabled?: boolean }>()
|
||||
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() {
|
||||
const api = new AttachmentApiClient(route)
|
||||
if (!authStore.state) return
|
||||
api.downloadAttachment(props.attachment?.id ?? 0, authStore.state.token)
|
||||
}
|
||||
|
|
@ -31,19 +50,39 @@ function downloadFile() {
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<AppButton
|
||||
icon="eye"
|
||||
v-if="canPreviewAttachment"
|
||||
@click="attachmentViewerModal?.show()"
|
||||
></AppButton>
|
||||
<AppButton
|
||||
icon="download"
|
||||
type="button"
|
||||
@click="downloadFile()"
|
||||
v-if="attachment.id !== undefined"
|
||||
/>
|
||||
<AppButton
|
||||
v-if="!disabled"
|
||||
type="button"
|
||||
icon="trash"
|
||||
@click="$emit('deleted')"
|
||||
/>
|
||||
</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>
|
||||
</template>
|
||||
<style lang="css">
|
||||
|
|
@ -55,4 +94,13 @@ function downloadFile() {
|
|||
border-radius: 0.5rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.attachment-embed-img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.attachment-embed-pdf {
|
||||
min-width: 500px;
|
||||
min-height: 500px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -52,11 +52,16 @@ defineExpose({ show, close })
|
|||
color: inherit;
|
||||
border-radius: 1rem;
|
||||
border-width: 0;
|
||||
/* border: 3px solid var(--theme-secondary); */
|
||||
min-width: 300px;
|
||||
max-width: 500px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.app-modal-dialog::backdrop {
|
||||
background-color: rgb(0 0 0 / 60%);
|
||||
}
|
||||
|
||||
.app-modal-dialog-header {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue