2024-11-19 00:51:11 +02:00
|
|
|
<template>
|
2024-11-19 18:49:12 +02:00
|
|
|
<section class="max-w-prose w-full text-center">
|
2024-11-19 00:51:11 +02:00
|
|
|
<!-- Контактная информация -->
|
|
|
|
|
<div class="flex items-start bg-gray-100 border rounded-lg p-4">
|
|
|
|
|
<!-- Аватарка Gravatar -->
|
|
|
|
|
<div v-if="contactInfo.email" class="flex-shrink-0 mr-4">
|
|
|
|
|
<img
|
|
|
|
|
:src="gravatarUrl"
|
|
|
|
|
alt="Аватар"
|
|
|
|
|
class="w-16 h-16 rounded-full"
|
|
|
|
|
title="Аватар владельца"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Контакты -->
|
|
|
|
|
<div class="text-left flex-grow">
|
|
|
|
|
<p v-if="contactInfo.name" class="text-lg font-semibold">{{ contactInfo.name }}</p>
|
|
|
|
|
|
|
|
|
|
<p v-if="contactInfo.phone" class="text-gray-700">
|
|
|
|
|
Телефон:
|
|
|
|
|
<a :href="`tel:${formattedPhone}`" class="underline text-blue-600">
|
|
|
|
|
{{ contactInfo.phone }}
|
|
|
|
|
</a>
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<p v-if="contactInfo.email" class="text-gray-700">
|
|
|
|
|
Email:
|
|
|
|
|
<a :href="`mailto:${contactInfo.email}`" class="underline text-blue-600">
|
|
|
|
|
{{ contactInfo.email }}
|
|
|
|
|
</a>
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
v-if="hasContactInfo"
|
|
|
|
|
label="Добавить в адресную книгу"
|
|
|
|
|
icon="pi pi-user-plus"
|
|
|
|
|
class="p-button-sm mt-4 p-button-outlined"
|
|
|
|
|
@click="addToAddressBook"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<p v-if="success" class="text-green-500 mt-4">Контакт успешно добавлен в адресную книгу!</p>
|
|
|
|
|
<p v-if="error" class="text-red-500 mt-4">Ошибка добавления контакта: {{ error }}</p>
|
|
|
|
|
</section>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref, computed } from 'vue'
|
|
|
|
|
import md5 from 'md5'
|
2024-11-20 01:59:52 +02:00
|
|
|
import type { ContactInfo } from '@/types/DBDocumentTypes'
|
2024-11-19 00:51:11 +02:00
|
|
|
|
2024-11-20 01:59:52 +02:00
|
|
|
const { contactInfo } = defineProps<{ contactInfo: ContactInfo }>()
|
2024-11-19 00:51:11 +02:00
|
|
|
|
|
|
|
|
const success = ref(false)
|
|
|
|
|
const error = ref<string | null>(null)
|
|
|
|
|
|
|
|
|
|
// Форматирование номера телефона для протокола `tel:`
|
|
|
|
|
const formattedPhone = computed(() => {
|
|
|
|
|
if (!contactInfo.phone) return ''
|
|
|
|
|
return contactInfo.phone.replace(/[^0-9+]/g, '') // Удаляем все, кроме цифр и "+"
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Проверка наличия контактной информации
|
|
|
|
|
const hasContactInfo = computed(() => {
|
|
|
|
|
return !!contactInfo.name || !!contactInfo.phone || !!contactInfo.email
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Ссылка на аватар Gravatar
|
|
|
|
|
const gravatarUrl = computed(() => {
|
|
|
|
|
if (!contactInfo.email) return ''
|
|
|
|
|
const hash = md5(contactInfo.email.trim().toLowerCase())
|
|
|
|
|
return `https://www.gravatar.com/avatar/${hash}?d=identicon&s=128`
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Добавление в адресную книгу
|
|
|
|
|
function addToAddressBook() {
|
|
|
|
|
try {
|
|
|
|
|
const vCard = [
|
|
|
|
|
'BEGIN:VCARD',
|
|
|
|
|
'VERSION:3.0',
|
|
|
|
|
contactInfo.name ? `FN:${contactInfo.name}` : '',
|
|
|
|
|
contactInfo.phone ? `TEL;TYPE=VOICE:${formattedPhone.value}` : '',
|
|
|
|
|
contactInfo.email ? `EMAIL:${contactInfo.email}` : '',
|
|
|
|
|
'END:VCARD',
|
|
|
|
|
]
|
|
|
|
|
.filter(Boolean) // Убираем пустые строки
|
|
|
|
|
.join('\n')
|
|
|
|
|
|
|
|
|
|
const blob = new Blob([vCard], { type: 'text/vcard;charset=utf-8' })
|
|
|
|
|
const link = document.createElement('a')
|
|
|
|
|
|
|
|
|
|
const sanitized = contactInfo.name
|
|
|
|
|
?.replace(/[<>:"/\\|?*\x00-\x1F]/g, '') // Убираем запрещённые символы
|
|
|
|
|
.replace(/\s+/g, '_') // Заменяем пробелы на подчёркивания
|
|
|
|
|
.trim()
|
|
|
|
|
|
|
|
|
|
link.href = URL.createObjectURL(blob)
|
|
|
|
|
link.download = `${sanitized || 'contact'}.vcf`
|
|
|
|
|
link.click()
|
|
|
|
|
|
|
|
|
|
success.value = true
|
|
|
|
|
error.value = null
|
|
|
|
|
} catch {
|
|
|
|
|
error.value = 'Ошибка при создании vCard'
|
|
|
|
|
success.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|