This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="max-w-lg mx-auto py-6 px-4 md:px-6">
|
||||
<div class="max-w-prose mx-auto py-6 px-4 md:px-6">
|
||||
<section class="content">
|
||||
<div class="max-w-lg mx-auto py-8">
|
||||
<div class="max-w-prose mx-auto py-8">
|
||||
<!-- Секция выбора размещения -->
|
||||
<CreateSection :isActive="activeSteps.includes('placement')">
|
||||
<CreatePlacementSection v-model="placement" />
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
<template>
|
||||
<div class="flex flex-col min-h-screen">
|
||||
<main class="flex-grow flex items-center justify-center py-6 px-4 md:px-6">
|
||||
<section class="max-w-lg w-full flex flex-col gap-1">
|
||||
<section class="max-w-prose w-full flex flex-col gap-1">
|
||||
<h2 class="text-xl font-semibold mb-4">Ваш QR‑код готов</h2>
|
||||
<p class="text-gray-600 mb-4">Сохраните его и ознакомьтесь с инструкциями по размещению.</p>
|
||||
|
||||
<!-- Рендер QR‑кода -->
|
||||
<div v-if="!loading && svgUrl" class="border p-4 bg-white rounded-lg mb-6">
|
||||
<img :src="svgUrl" alt="QR‑код" />
|
||||
<div v-if="!svgQueryIsLoading && svgQueryData" class="border p-4 bg-white rounded-lg mb-6">
|
||||
<img :src="svgQueryData" alt="QR‑код" />
|
||||
</div>
|
||||
|
||||
<!-- Сообщение об ошибке -->
|
||||
<p v-if="error" class="text-red-500 mt-4">{{ error }}</p>
|
||||
<p v-if="loading" class="text-gray-500 mt-4">Загрузка...</p>
|
||||
<p v-if="qrCodeQueryIsError" class="text-red-500 mt-4">
|
||||
Ошибка загрузки данных QR‑кода: {{ qrCodeQueryError!.message }}
|
||||
</p>
|
||||
<p v-if="svgQueryIsLoading" class="text-gray-500 mt-4">Загрузка...</p>
|
||||
|
||||
<!-- Кнопки для скачивания -->
|
||||
<div v-if="!loading && !error" class="flex flex-row gap-4 justify-center">
|
||||
<div
|
||||
v-if="!svgQueryIsLoading && !qrCodeQueryIsError && svgQueryData"
|
||||
class="flex flex-row gap-4 justify-center"
|
||||
>
|
||||
<Button
|
||||
v-if="svgUrl"
|
||||
label="Скачать SVG"
|
||||
icon="pi pi-download"
|
||||
class="p-button-sm"
|
||||
:href="svgUrl"
|
||||
:href="svgQueryData"
|
||||
:download="`${sanitizedFileName}.svg`"
|
||||
as="a"
|
||||
/>
|
||||
@@ -32,6 +36,12 @@
|
||||
@click="downloadPng"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Инструкции по размещению -->
|
||||
<ManagePlacementInstructions
|
||||
:placement="qrCodeDoc?.placement"
|
||||
v-if="qrCodeDoc?.placement"
|
||||
/>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -50,27 +60,23 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import QRCodeStyling from 'qr-code-styling'
|
||||
import { getQrCodeDocument } from '@/api/qrCode'
|
||||
import { optimize } from 'svgo'
|
||||
import type { QRCodeDocument } from '@/types/DBDocumentTypes'
|
||||
import { getQrCodeDocument } from '@/api/qrCode'
|
||||
import { type QRCodeDocument } from '@/types/DBDocumentTypes'
|
||||
|
||||
const { qr_code_uri } = defineProps<{ qr_code_uri: QRCodeDocument['uri'] }>()
|
||||
|
||||
// Локальные состояния
|
||||
const loading = ref(true)
|
||||
const error = ref<string | null>(null)
|
||||
const qrCodeData = ref<null | { name: string; url: string }>(null)
|
||||
const svgUrl = ref<string | null>(null)
|
||||
|
||||
// Получение имени файла
|
||||
const sanitizedFileName = computed(() => {
|
||||
const sanitized = qrCodeData.value?.name
|
||||
.replace(/[<>:"/\\|?*\x00-\x1F]/g, '') // Убираем запрещённые символы
|
||||
.replace(/\s+/g, '_') // Заменяем пробелы на подчёркивания
|
||||
.trim()
|
||||
return sanitized ? `${sanitized}_QR-Code_HereConnect` : 'QR-Code_HereConnect'
|
||||
// Хук для загрузки данных QR‑кода
|
||||
const {
|
||||
data: qrCodeDoc,
|
||||
isError: qrCodeQueryIsError,
|
||||
error: qrCodeQueryError,
|
||||
} = useQuery({
|
||||
queryKey: ['qrCode', computed(() => qr_code_uri)],
|
||||
queryFn: () => getQrCodeDocument(qr_code_uri),
|
||||
})
|
||||
|
||||
// Инициализация QRCodeStyling
|
||||
@@ -84,10 +90,26 @@ const qrCode = new QRCodeStyling({
|
||||
},
|
||||
})
|
||||
|
||||
// Генерация и оптимизация SVG
|
||||
async function generateOptimizedSvg(url: string) {
|
||||
try {
|
||||
qrCode.update({ data: url })
|
||||
// Получение имени файла
|
||||
const sanitizedFileName = computed(() => {
|
||||
const sanitized = qrCodeDoc.value?.name
|
||||
?.replace(/[<>:"/\\|?*\x00-\x1F]/g, '') // Убираем запрещённые символы
|
||||
.replace(/\s+/g, '_') // Заменяем пробелы на подчёркивания
|
||||
.trim()
|
||||
return sanitized ? `${sanitized}_QR-Code_HereConnect` : 'QR-Code_HereConnect'
|
||||
})
|
||||
|
||||
// Хук для генерации и оптимизации SVG
|
||||
const {
|
||||
isLoading: svgQueryIsLoading,
|
||||
data: svgQueryData,
|
||||
error: svgQueryError,
|
||||
} = useQuery({
|
||||
queryKey: ['svg', computed(() => qr_code_uri)],
|
||||
enabled: computed(() => !!qrCodeDoc.value?.url),
|
||||
queryFn: async () => {
|
||||
qrCode.update({ data: qrCodeDoc.value!.url })
|
||||
|
||||
const blob = await qrCode.getRawData('svg')
|
||||
if (blob && blob instanceof Blob) {
|
||||
const text = await blob.text()
|
||||
@@ -104,17 +126,20 @@ async function generateOptimizedSvg(url: string) {
|
||||
})
|
||||
|
||||
if (optimizedSvg.data) {
|
||||
svgUrl.value = URL.createObjectURL(new Blob([optimizedSvg.data], { type: 'image/svg+xml' }))
|
||||
return URL.createObjectURL(new Blob([optimizedSvg.data], { type: 'image/svg+xml' }))
|
||||
} else {
|
||||
throw new Error('Ошибка оптимизации SVG')
|
||||
}
|
||||
} else {
|
||||
throw new Error('Ошибка генерации QR‑кода')
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = (err as Error).message || 'Неизвестная ошибка'
|
||||
}
|
||||
}
|
||||
},
|
||||
onSettled(data) {
|
||||
if (!data && svgQueryError) {
|
||||
console.error('Ошибка загрузки SVG:', svgQueryError.message)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// Скачивание PNG
|
||||
async function downloadPng() {
|
||||
@@ -124,28 +149,7 @@ async function downloadPng() {
|
||||
extension: 'png',
|
||||
})
|
||||
} catch (err) {
|
||||
error.value = (err as Error).message || 'Ошибка при скачивании QR‑кода'
|
||||
console.error('Ошибка скачивания PNG:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// Монтирование
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// Загружаем данные QR‑кода
|
||||
const doc = await getQrCodeDocument(qr_code_uri)
|
||||
qrCodeData.value = { name: doc.name, url: doc.url }
|
||||
await generateOptimizedSvg(doc.url)
|
||||
} catch (err) {
|
||||
error.value = (err as Error).message || 'Ошибка загрузки данных QR‑кода'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
// Очистка ресурсов при размонтировании
|
||||
onUnmounted(() => {
|
||||
if (svgUrl.value) {
|
||||
URL.revokeObjectURL(svgUrl.value)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col min-h-screen">
|
||||
<main class="flex-grow flex items-center justify-center py-6 px-4 md:px-6">
|
||||
<section class="max-w-lg w-full flex flex-col gap-10">
|
||||
<section class="max-w-prose w-full flex flex-col gap-10">
|
||||
<template v-for="action in actions">
|
||||
<ReadContactInfo v-if="action === 'viewContactInfo'" :contactInfo="contactInfo" />
|
||||
<ReadMessageSender
|
||||
|
||||
Reference in New Issue
Block a user