Use geo offers for quote results
All checks were successful
Build Docker Image / build (push) Successful in 5m9s

This commit is contained in:
Ruslan Bakiev
2026-02-06 18:25:44 +07:00
parent 0453aeae07
commit 87133ed37a
2 changed files with 110 additions and 19 deletions

View File

@@ -34,7 +34,8 @@
:quantity="offer.quantity" :quantity="offer.quantity"
:currency="offer.currency" :currency="offer.currency"
:unit="offer.unit" :unit="offer.unit"
:stages="[]" :stages="getOfferStages(offer)"
:total-time-seconds="offer.routes?.[0]?.totalTimeSeconds ?? null"
/> />
</div> </div>
</div> </div>
@@ -48,6 +49,7 @@ interface Offer {
productName?: string | null productName?: string | null
productUuid?: string | null productUuid?: string | null
supplierName?: string | null supplierName?: string | null
supplierUuid?: string | null
quantity?: number | string | null quantity?: number | string | null
unit?: string | null unit?: string | null
pricePerUnit?: number | string | null pricePerUnit?: number | string | null
@@ -55,6 +57,15 @@ interface Offer {
locationName?: string | null locationName?: string | null
locationCountry?: string | null locationCountry?: string | null
locationCountryCode?: string | null locationCountryCode?: string | null
routes?: Array<{
totalTimeSeconds?: number | null
stages?: Array<{
transportType?: string | null
distanceKm?: number | null
travelTimeSeconds?: number | null
fromName?: string | null
} | null> | null
} | null> | null
} }
const emit = defineEmits<{ const emit = defineEmits<{
@@ -69,4 +80,17 @@ const props = defineProps<{
const offersWithPrice = computed(() => const offersWithPrice = computed(() =>
(props.offers || []).filter(o => o?.pricePerUnit != null) (props.offers || []).filter(o => o?.pricePerUnit != null)
) )
const getOfferStages = (offer: Offer) => {
const route = offer.routes?.[0]
if (!route?.stages) return []
return route.stages
.filter((stage): stage is NonNullable<typeof stage> => stage !== null)
.map((stage) => ({
transportType: stage.transportType,
distanceKm: stage.distanceKm,
travelTimeSeconds: stage.travelTimeSeconds,
fromName: stage.fromName
}))
}
</script> </script>

View File

@@ -83,11 +83,33 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { GetOffersDocument, GetOfferDocument, type GetOffersQueryVariables, type GetOffersQueryResult } from '~/composables/graphql/public/exchange-generated' import { GetOffersDocument, GetOfferDocument, type GetOffersQueryVariables } from '~/composables/graphql/public/exchange-generated'
import { GetNodeDocument, NearestOffersDocument } from '~/composables/graphql/public/geo-generated'
import type { MapBounds } from '~/components/catalog/CatalogMap.vue' import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
// Offer type from search results type QuoteOffer = {
type OfferResult = NonNullable<NonNullable<GetOffersQueryResult['getOffers']>[number]> uuid: string
productUuid?: string | null
productName?: string | null
supplierUuid?: string | null
supplierName?: string | null
teamUuid?: string | null
quantity?: number | string | null
unit?: string | null
pricePerUnit?: number | string | null
currency?: string | null
locationName?: string | null
locationCountry?: string | null
routes?: Array<{
totalTimeSeconds?: number | null
stages?: Array<{
transportType?: string | null
distanceKm?: number | null
travelTimeSeconds?: number | null
fromName?: string | null
} | null> | null
} | null> | null
}
definePageMeta({ definePageMeta({
layout: 'topnav' layout: 'topnav'
@@ -393,7 +415,7 @@ const relatedPoints = computed(() => {
}) })
// Offers data for quote results // Offers data for quote results
const offers = ref<OfferResult[]>([]) const offers = ref<QuoteOffer[]>([])
const offersLoading = ref(false) const offersLoading = ref(false)
const showQuoteResults = ref(false) const showQuoteResults = ref(false)
@@ -574,24 +596,69 @@ const onSearch = async () => {
showQuoteResults.value = true showQuoteResults.value = true
try { try {
const vars: GetOffersQueryVariables = {} // Prefer geo-based offers with routes when hub + product are selected
if (productId.value) vars.productUuid = productId.value if (hubId.value && productId.value) {
if (supplierId.value) vars.teamUuid = supplierId.value const hubData = await execute(GetNodeDocument, { uuid: hubId.value }, 'public', 'geo')
if (hubId.value) vars.locationUuid = hubId.value const hub = hubData?.node
if (hub?.latitude != null && hub?.longitude != null) {
const geoData = await execute(
NearestOffersDocument,
{
lat: hub.latitude,
lon: hub.longitude,
productUuid: productId.value,
hubUuid: hubId.value,
radius: 500,
limit: 12
},
'public',
'geo'
)
const data = await execute(GetOffersDocument, vars, 'public', 'exchange') let nearest = (geoData?.nearestOffers || []).filter((o): o is QuoteOffer => o !== null)
offers.value = (data?.getOffers || []).filter((o): o is OfferResult => o !== null) if (supplierId.value) {
nearest = nearest.filter(o => o?.supplierUuid === supplierId.value)
}
offers.value = nearest
// Update labels from response const first = offers.value[0]
const first = offers.value[0] if (first?.productName) {
if (first) { setLabel('product', productId.value, first.productName)
if (productId.value && first.productName) { }
setLabel('product', productId.value, first.productName) } else {
offers.value = []
} }
if (hubId.value && first.locationName) { } else {
setLabel('hub', hubId.value, first.locationName) const vars: GetOffersQueryVariables = {}
if (productId.value) vars.productUuid = productId.value
if (supplierId.value) vars.teamUuid = supplierId.value
if (hubId.value) vars.locationUuid = hubId.value
const data = await execute(GetOffersDocument, vars, 'public', 'exchange')
const exchangeOffers = (data?.getOffers || []).filter((o): o is NonNullable<typeof o> => o !== null)
offers.value = exchangeOffers.map((offer) => ({
uuid: offer.uuid,
productUuid: offer.productUuid,
productName: offer.productName,
teamUuid: offer.teamUuid,
quantity: offer.quantity,
unit: offer.unit,
pricePerUnit: offer.pricePerUnit,
currency: offer.currency,
locationName: offer.locationName,
locationCountry: offer.locationCountry
}))
// Update labels from response
const first = offers.value[0]
if (first) {
if (productId.value && first.productName) {
setLabel('product', productId.value, first.productName)
}
if (hubId.value && first.locationName) {
setLabel('hub', hubId.value, first.locationName)
}
} }
// Note: teamName not included in GetOffers query, supplier label cannot be updated from offer
} }
} finally { } finally {
offersLoading.value = false offersLoading.value = false