Add KycProfileCard component with full company info
Some checks failed
Build Docker Image / build (push) Has been cancelled

- New KycProfileCard shows full KYC profile data (INN, OGRN, director, capital, activities)
- Added to offer detail page /catalog/suppliers/[supplierId]/[productId]/[hubId]
- Uses kycProfileFull endpoint for authorized detailed company info
This commit is contained in:
Ruslan Bakiev
2026-01-21 14:52:01 +07:00
parent 1b0fae1164
commit c1ae984fcc
3 changed files with 170 additions and 2 deletions

View File

@@ -27,6 +27,7 @@
:unit="getOfferData(option.sourceUuid)?.unit"
:stages="getRouteStages(option)"
:kyc-profile-uuid="getKycProfileUuid(option.sourceUuid)"
@select="navigateToOffer(option.sourceUuid)"
/>
</div>
@@ -68,6 +69,7 @@ import type { RouteStageItem } from '~/components/RouteStagesList.vue'
import { GetOfferDocument, GetSupplierProfileByTeamDocument } from '~/composables/graphql/public/exchange-generated'
const route = useRoute()
const localePath = useLocalePath()
const searchStore = useSearchStore()
const { execute } = useGraphQL()
@@ -175,6 +177,16 @@ const getKycProfileUuid = (offerUuid?: string | null) => {
return supplier?.kycProfileUuid || null
}
// Navigate to offer detail page
const navigateToOffer = (offerUuid?: string | null) => {
if (!offerUuid) return
const offer = offersData.value.get(offerUuid)
if (!offer?.teamUuid || !productUuid.value || !destinationUuid.value) return
// Navigate to /catalog/suppliers/[supplierId]/[productId]/[hubId]
navigateTo(localePath(`/catalog/suppliers/${offer.teamUuid}/${productUuid.value}/${destinationUuid.value}`))
}
// Load offer details for prices
const loadOfferDetails = async (options: ProductRouteOption[]) => {
if (options.length === 0) {

View File

@@ -0,0 +1,155 @@
<template>
<Card v-if="kycProfileUuid" padding="md">
<!-- Loading -->
<div v-if="pending" class="flex items-center gap-2">
<Spinner size="sm" />
<Text tone="muted" size="sm">Загрузка данных о компании...</Text>
</div>
<!-- Error or no data -->
<div v-else-if="!profileData" class="text-sm text-base-content/60">
Данные о компании недоступны
</div>
<!-- Profile data -->
<Stack v-else gap="4">
<!-- Header -->
<div class="flex items-start justify-between">
<div>
<Text weight="semibold" size="lg">{{ profileData.name }}</Text>
<div class="flex items-center gap-2 mt-1">
<span v-if="profileData.companyType" class="badge badge-outline badge-sm">
{{ profileData.companyType }}
</span>
<span v-if="profileData.registrationYear" class="text-xs text-base-content/60">
с {{ profileData.registrationYear }} г.
</span>
<span v-if="profileData.isActive" class="badge badge-success badge-xs">Активна</span>
<span v-else class="badge badge-error badge-xs">Неактивна</span>
</div>
</div>
</div>
<!-- Details grid -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- INN -->
<div v-if="profileData.inn">
<Text tone="muted" size="sm">ИНН</Text>
<Text weight="medium">{{ profileData.inn }}</Text>
</div>
<!-- OGRN -->
<div v-if="profileData.ogrn">
<Text tone="muted" size="sm">ОГРН</Text>
<Text weight="medium">{{ profileData.ogrn }}</Text>
</div>
<!-- Director -->
<div v-if="profileData.director">
<Text tone="muted" size="sm">Руководитель</Text>
<Text weight="medium">{{ profileData.director }}</Text>
</div>
<!-- Capital -->
<div v-if="profileData.capital">
<Text tone="muted" size="sm">Уставный капитал</Text>
<Text weight="medium">{{ profileData.capital }}</Text>
</div>
<!-- Address -->
<div v-if="profileData.address" class="md:col-span-2">
<Text tone="muted" size="sm">Адрес</Text>
<Text weight="medium">{{ profileData.address }}</Text>
</div>
<!-- Activities -->
<div v-if="profileData.activities?.length" class="md:col-span-2">
<Text tone="muted" size="sm">Виды деятельности</Text>
<div class="flex flex-wrap gap-1 mt-1">
<span
v-for="(activity, idx) in profileData.activities.slice(0, 5)"
:key="idx"
class="badge badge-ghost badge-sm"
>
{{ activity }}
</span>
<span v-if="profileData.activities.length > 5" class="text-xs text-base-content/60">
+{{ profileData.activities.length - 5 }}
</span>
</div>
</div>
</div>
<!-- Footer: sources and last updated -->
<div class="flex items-center justify-between text-xs text-base-content/50 pt-2 border-t border-base-200">
<span v-if="profileData.sources?.length">
Источники: {{ profileData.sources.join(', ') }}
</span>
<span v-if="profileData.lastUpdated">
Обновлено: {{ formatDate(profileData.lastUpdated) }}
</span>
</div>
</Stack>
</Card>
</template>
<script setup lang="ts">
import { GetKycProfileFullDocument } from '~/composables/graphql/public/kyc-generated'
const props = defineProps<{
kycProfileUuid?: string | null
}>()
const { execute } = useGraphQL()
const profileData = ref<{
inn?: string | null
ogrn?: string | null
name?: string | null
companyType?: string | null
registrationYear?: number | null
isActive?: boolean | null
address?: string | null
director?: string | null
capital?: string | null
activities?: string[] | null
sources?: string[] | null
lastUpdated?: string | null
} | null>(null)
const pending = ref(false)
const loadProfile = async () => {
if (!props.kycProfileUuid) return
pending.value = true
try {
const data = await execute(
GetKycProfileFullDocument,
{ profileUuid: props.kycProfileUuid },
'public',
'kyc'
)
profileData.value = data?.kycProfileFull || null
} catch (error) {
console.error('Error loading KYC profile:', error)
} finally {
pending.value = false
}
}
watch(() => props.kycProfileUuid, (uuid) => {
if (uuid) {
loadProfile()
} else {
profileData.value = null
}
}, { immediate: true })
const formatDate = (dateStr: string) => {
try {
return new Date(dateStr).toLocaleDateString('ru-RU')
} catch {
return dateStr
}
}
</script>

View File

@@ -45,11 +45,12 @@
<div v-if="supplier?.isVerified" class="badge badge-success badge-sm ml-auto">Верифицирован</div>
</div>
<!-- KYC Info -->
<SupplierInfoBlock v-if="supplier?.kycProfileUuid" :kyc-profile-uuid="supplier.kycProfileUuid" />
</Stack>
</Card>
<!-- KYC Profile Card (full company info) -->
<KycProfileCard v-if="supplier?.kycProfileUuid" :kyc-profile-uuid="supplier.kycProfileUuid" />
<!-- Price Chart -->
<Card padding="md">
<div class="h-48">