diff --git a/app/pages/catalog/hubs/[id]/[productId].vue b/app/pages/catalog/hubs/[id]/[productId].vue
index 1474912..80a420c 100644
--- a/app/pages/catalog/hubs/[id]/[productId].vue
+++ b/app/pages/catalog/hubs/[id]/[productId].vue
@@ -44,6 +44,20 @@
Нет доступных источников
+
+
+
+
+
@@ -126,6 +140,54 @@ const handleRemoveFilter = (filterId: string) => {
}
}
+// Mock price history generator (seeded by uuid for consistent results)
+const getMockPriceHistory = (uuid: string): number[] => {
+ const seed = uuid.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
+ const basePrice = 100 + (seed % 200)
+ return Array.from({ length: 30 }, (_, i) => {
+ const variation = Math.sin(seed + i * 0.3) * 30 + Math.cos(seed * 0.2 + i) * 15
+ return Math.round(basePrice + variation)
+ })
+}
+
+// Chart configuration
+const priceHistory = computed(() => getMockPriceHistory(productId.value))
+
+const trend = computed(() => {
+ if (priceHistory.value.length < 2) return 0
+ const first = priceHistory.value[0]
+ const last = priceHistory.value[priceHistory.value.length - 1]
+ if (!first || first === 0) return 0
+ return Math.round(((last - first) / first) * 100)
+})
+
+const chartOptions = computed(() => ({
+ chart: {
+ type: 'area',
+ toolbar: { show: false },
+ animations: { enabled: true }
+ },
+ stroke: { curve: 'smooth', width: 2 },
+ fill: {
+ type: 'gradient',
+ gradient: { shadeIntensity: 1, opacityFrom: 0.4, opacityTo: 0.1 }
+ },
+ colors: [trend.value >= 0 ? '#22c55e' : '#ef4444'],
+ dataLabels: { enabled: false },
+ xaxis: {
+ categories: priceHistory.value.map((_, i) => `${i + 1}`),
+ labels: { show: false }
+ },
+ yaxis: { labels: { formatter: (val: number) => `$${val}` } },
+ tooltip: { y: { formatter: (val: number) => `$${val}` } },
+ grid: { borderColor: '#e5e7eb', strokeDashArray: 4 }
+}))
+
+const chartSeries = computed(() => [{
+ name: t('catalogHub.product.price'),
+ data: priceHistory.value
+}])
+
// Transform sources for CatalogPage
const sources = computed(() => {
return rawSources.value.map(source => ({
diff --git a/app/pages/catalog/offers/[productId]/[hubId].vue b/app/pages/catalog/offers/[productId]/[hubId].vue
index 9fd701f..79312f7 100644
--- a/app/pages/catalog/offers/[productId]/[hubId].vue
+++ b/app/pages/catalog/offers/[productId]/[hubId].vue
@@ -44,6 +44,20 @@
Нет доступных источников
+
+
+
+
+
@@ -126,6 +140,54 @@ const handleRemoveFilter = (filterId: string) => {
}
}
+// Mock price history generator (seeded by uuid for consistent results)
+const getMockPriceHistory = (uuid: string): number[] => {
+ const seed = uuid.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
+ const basePrice = 100 + (seed % 200)
+ return Array.from({ length: 30 }, (_, i) => {
+ const variation = Math.sin(seed + i * 0.3) * 30 + Math.cos(seed * 0.2 + i) * 15
+ return Math.round(basePrice + variation)
+ })
+}
+
+// Chart configuration
+const priceHistory = computed(() => getMockPriceHistory(productId.value))
+
+const trend = computed(() => {
+ if (priceHistory.value.length < 2) return 0
+ const first = priceHistory.value[0]
+ const last = priceHistory.value[priceHistory.value.length - 1]
+ if (!first || first === 0) return 0
+ return Math.round(((last - first) / first) * 100)
+})
+
+const chartOptions = computed(() => ({
+ chart: {
+ type: 'area',
+ toolbar: { show: false },
+ animations: { enabled: true }
+ },
+ stroke: { curve: 'smooth', width: 2 },
+ fill: {
+ type: 'gradient',
+ gradient: { shadeIntensity: 1, opacityFrom: 0.4, opacityTo: 0.1 }
+ },
+ colors: [trend.value >= 0 ? '#22c55e' : '#ef4444'],
+ dataLabels: { enabled: false },
+ xaxis: {
+ categories: priceHistory.value.map((_, i) => `${i + 1}`),
+ labels: { show: false }
+ },
+ yaxis: { labels: { formatter: (val: number) => `$${val}` } },
+ tooltip: { y: { formatter: (val: number) => `$${val}` } },
+ grid: { borderColor: '#e5e7eb', strokeDashArray: 4 }
+}))
+
+const chartSeries = computed(() => [{
+ name: t('catalogProductHubs.chart.price'),
+ data: priceHistory.value
+}])
+
// Transform sources for CatalogPage
const sources = computed(() => {
return rawSources.value.map(source => ({
diff --git a/app/pages/catalog/suppliers/[supplierId]/[productId]/[hubId].vue b/app/pages/catalog/suppliers/[supplierId]/[productId]/[hubId].vue
index b92ba86..c227060 100644
--- a/app/pages/catalog/suppliers/[supplierId]/[productId]/[hubId].vue
+++ b/app/pages/catalog/suppliers/[supplierId]/[productId]/[hubId].vue
@@ -16,6 +16,20 @@
Данные не найдены
+
+
+
+
+
@@ -193,6 +207,53 @@ const getTransportIcon = (type?: string | null) => {
}
}
+// Mock price history generator
+const getMockPriceHistory = (uuid: string): number[] => {
+ const seed = uuid.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
+ const basePrice = 100 + (seed % 200)
+ return Array.from({ length: 30 }, (_, i) => {
+ const variation = Math.sin(seed + i * 0.3) * 30 + Math.cos(seed * 0.2 + i) * 15
+ return Math.round(basePrice + variation)
+ })
+}
+
+const priceHistory = computed(() => product.value ? getMockPriceHistory(product.value.uuid) : [])
+
+const trend = computed(() => {
+ if (priceHistory.value.length < 2) return 0
+ const first = priceHistory.value[0]
+ const last = priceHistory.value[priceHistory.value.length - 1]
+ if (!first || first === 0) return 0
+ return Math.round(((last - first) / first) * 100)
+})
+
+const chartOptions = computed(() => ({
+ chart: {
+ type: 'area',
+ toolbar: { show: false },
+ animations: { enabled: true }
+ },
+ stroke: { curve: 'smooth', width: 2 },
+ fill: {
+ type: 'gradient',
+ gradient: { shadeIntensity: 1, opacityFrom: 0.4, opacityTo: 0.1 }
+ },
+ colors: [trend.value >= 0 ? '#22c55e' : '#ef4444'],
+ dataLabels: { enabled: false },
+ xaxis: {
+ categories: priceHistory.value.map((_, i) => `${i + 1}`),
+ labels: { show: false }
+ },
+ yaxis: { labels: { formatter: (val: number) => `$${val}` } },
+ tooltip: { y: { formatter: (val: number) => `$${val}` } },
+ grid: { borderColor: '#e5e7eb', strokeDashArray: 4 }
+}))
+
+const chartSeries = computed(() => [{
+ name: t('catalogSupplierCalculation.chart.price'),
+ data: priceHistory.value
+}])
+
// Load route using delivery to hub
const loadRoute = async (offerUuid: string) => {
if (!offerUuid || !hubId.value) {
diff --git a/app/pages/catalog/suppliers/[supplierId]/[productId]/index.vue b/app/pages/catalog/suppliers/[supplierId]/[productId]/index.vue
index 45f8d03..b7adb28 100644
--- a/app/pages/catalog/suppliers/[supplierId]/[productId]/index.vue
+++ b/app/pages/catalog/suppliers/[supplierId]/[productId]/index.vue
@@ -22,7 +22,20 @@
Товар не найден
- Выберите хаб
+
+
+
+
+
@@ -115,6 +128,47 @@ const onSelectHub = (hub: any) => {
navigateTo(localePath(`/catalog/suppliers/${supplierId.value}/${productId.value}/${hub.uuid}`))
}
+// Mock price history generator
+const getMockPriceHistory = (uuid: string): number[] => {
+ const seed = uuid.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
+ const basePrice = 100 + (seed % 200)
+ return Array.from({ length: 30 }, (_, i) => {
+ const variation = Math.sin(seed + i * 0.3) * 20 + Math.cos(seed * 0.2 + i) * 15
+ return Math.round(basePrice + variation)
+ })
+}
+
+const priceHistory = computed(() => product.value ? getMockPriceHistory(product.value.uuid) : [])
+
+// Chart configuration
+const chartOptions = computed(() => ({
+ chart: {
+ type: 'area',
+ sparkline: { enabled: false },
+ toolbar: { show: false },
+ animations: { enabled: false }
+ },
+ stroke: { curve: 'smooth', width: 2 },
+ fill: {
+ type: 'gradient',
+ gradient: { shadeIntensity: 1, opacityFrom: 0.4, opacityTo: 0.1 }
+ },
+ colors: ['#3b82f6'],
+ xaxis: {
+ labels: { show: false },
+ axisBorder: { show: false },
+ axisTicks: { show: false }
+ },
+ yaxis: { labels: { show: true } },
+ grid: { show: true, borderColor: '#e5e7eb', strokeDashArray: 4 },
+ tooltip: { enabled: true }
+}))
+
+const chartSeries = computed(() => [{
+ name: t('catalogSupplierProductHubs.chart.price'),
+ data: priceHistory.value
+}])
+
// Load data
try {
// Get supplier profile from exchange