fix
This commit is contained in:
@@ -266,39 +266,9 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 lg:col-span-5">
|
||||
<div class="rounded-2xl bg-white shadow-sm border border-slate-200/60 p-4 h-full">
|
||||
<div class="flex items-center gap-1.5 mb-3">
|
||||
<div class="text-[16px] font-semibold text-slate-800">Сегменты аудитории для рекламы</div>
|
||||
<i
|
||||
class="pi pi-question-circle text-[12px] text-slate-400 cursor-help"
|
||||
v-tooltip.top="'Массив ключевых групп потребителей с указанием их названия и процентной доли в общей массе. Помогает определить приоритетные сегменты для таргетинга.'"
|
||||
></i>
|
||||
</div>
|
||||
|
||||
<div class="overflow-hidden rounded-xl border border-slate-200/70">
|
||||
<div class="grid grid-cols-12 bg-slate-50 text-[12px] font-semibold text-slate-600">
|
||||
<div class="col-span-8 px-3 py-2">Сегмент</div>
|
||||
<div class="col-span-4 px-3 py-2 text-right">Доля</div>
|
||||
</div>
|
||||
<div class="divide-y divide-slate-200/70">
|
||||
<div v-for="seg in segmentRows" :key="seg.name" class="px-3 py-3">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="text-[14px] text-slate-800 truncate">{{ seg.name }}</div>
|
||||
<div class="text-[14px] font-semibold text-slate-800">{{ seg.value }}%</div>
|
||||
</div>
|
||||
<div class="mt-2 h-3 rounded-full bg-slate-200/70 overflow-hidden">
|
||||
<div class="h-full rounded-full" :style="{ width: `${seg.value}%`, background: `linear-gradient(90deg, ${PPT_BLUE}, rgba(91,137,255,0.25))` }"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 lg:col-span-7">
|
||||
<div class="col-span-12">
|
||||
<div class="grid grid-cols-12 gap-4">
|
||||
<div class="col-span-12">
|
||||
<div class="col-span-12 lg:col-span-6">
|
||||
<div class="rounded-2xl bg-white shadow-sm border border-slate-200/60 p-4">
|
||||
<div class="flex items-center gap-1.5 mb-2">
|
||||
<div class="text-[16px] font-semibold text-slate-800">Возрастная структура</div>
|
||||
@@ -312,7 +282,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12">
|
||||
<div class="col-span-12 lg:col-span-6">
|
||||
<div class="rounded-2xl bg-white shadow-sm border border-slate-200/60 p-4">
|
||||
<div class="flex items-center gap-1.5 mb-2">
|
||||
<div class="text-[16px] font-semibold text-slate-800">Доход и платёжеспособность</div>
|
||||
@@ -481,20 +451,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 pt-4 border-t border-slate-200/70">
|
||||
<div class="overflow-hidden rounded-xl border border-slate-200/70">
|
||||
<div class="grid grid-cols-12 bg-slate-50 text-[12px] font-semibold text-slate-600">
|
||||
<div class="col-span-8 px-3 py-2">Тип запроса</div>
|
||||
<div class="col-span-4 px-3 py-2 text-right">Доля</div>
|
||||
</div>
|
||||
<div class="divide-y divide-slate-200/70">
|
||||
<div v-for="row in queryTypesTableRows" :key="row.label" class="grid grid-cols-12 px-3 py-2.5">
|
||||
<div class="col-span-8 text-[13px] text-slate-800">{{ row.label }}</div>
|
||||
<div class="col-span-4 text-[13px] text-slate-800 text-right">{{ row.value }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-7">
|
||||
@@ -511,20 +467,6 @@
|
||||
<div class="h-[220px]">
|
||||
<Chart type="bar" :data="decisionFactorsBarData" :options="compactBarOptions" />
|
||||
</div>
|
||||
<div class="mt-4 pt-4 border-t border-slate-200/70">
|
||||
<div class="overflow-hidden rounded-xl border border-slate-200/70">
|
||||
<div class="grid grid-cols-12 bg-slate-50 text-[12px] font-semibold text-slate-600">
|
||||
<div class="col-span-8 px-3 py-2">Фактор</div>
|
||||
<div class="col-span-4 px-3 py-2 text-right">Доля</div>
|
||||
</div>
|
||||
<div class="divide-y divide-slate-200/70">
|
||||
<div v-for="row in decisionFactorsTableRows" :key="row.label" class="grid grid-cols-12 px-3 py-2.5">
|
||||
<div class="col-span-8 text-[13px] text-slate-800">{{ row.label }}</div>
|
||||
<div class="col-span-4 text-[13px] text-slate-800 text-right">{{ row.value }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12">
|
||||
@@ -539,20 +481,6 @@
|
||||
<div class="h-[200px]">
|
||||
<Chart type="bar" :data="refusalReasonsBarData" :options="compactBarOptions" />
|
||||
</div>
|
||||
<div class="mt-4 pt-4 border-t border-slate-200/70">
|
||||
<div class="overflow-hidden rounded-xl border border-slate-200/70">
|
||||
<div class="grid grid-cols-12 bg-slate-50 text-[12px] font-semibold text-slate-600">
|
||||
<div class="col-span-8 px-3 py-2">Причина</div>
|
||||
<div class="col-span-4 px-3 py-2 text-right">Доля</div>
|
||||
</div>
|
||||
<div class="divide-y divide-slate-200/70">
|
||||
<div v-for="row in refusalReasonsTableRows" :key="row.label" class="grid grid-cols-12 px-3 py-2.5">
|
||||
<div class="col-span-8 text-[13px] text-slate-800">{{ row.label }}</div>
|
||||
<div class="col-span-4 text-[13px] text-slate-800 text-right">{{ row.value }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -677,7 +605,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 lg:col-span-7">
|
||||
<div class="col-span-12">
|
||||
<div class="rounded-2xl bg-white shadow-sm border border-slate-200/60 p-4 h-full">
|
||||
<div class="flex items-center gap-1.5 mb-2">
|
||||
<div class="text-[16px] font-semibold text-slate-800">Доли каналов</div>
|
||||
@@ -691,31 +619,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-5">
|
||||
<div class="rounded-2xl bg-white shadow-sm border border-slate-200/60 p-4 h-full">
|
||||
<div class="flex items-center gap-1.5 mb-3">
|
||||
<div class="text-[16px] font-semibold text-slate-800">Стоимость привлечения</div>
|
||||
<i
|
||||
class="pi pi-question-circle text-[12px] text-slate-400 cursor-help"
|
||||
v-tooltip.top="'Детальная оценка каждого канала: стоимость привлечения (cost) и качественный статус (status: Эффективный, Средний, Низкий). Помогает оптимизировать распределение бюджета.'"
|
||||
></i>
|
||||
</div>
|
||||
<div class="overflow-hidden rounded-xl border border-slate-200/70">
|
||||
<div class="grid grid-cols-12 bg-slate-50 text-[12px] font-semibold text-slate-600">
|
||||
<div class="col-span-5 px-3 py-2">Канал</div>
|
||||
<div class="col-span-3 px-3 py-2 text-center">Стоимость</div>
|
||||
<div class="col-span-4 px-3 py-2">Эффективность</div>
|
||||
</div>
|
||||
<div class="divide-y divide-slate-200/70">
|
||||
<div v-for="row in channelEfficiencyRows" :key="row.key" class="grid grid-cols-12 px-3 py-3 items-center">
|
||||
<div class="col-span-5 text-[13px] text-slate-800">{{ row.label }}</div>
|
||||
<div class="col-span-3 text-[13px] text-slate-800 text-center">{{ row.cost }}</div>
|
||||
<div class="col-span-4 text-[13px]" :class="row.statusClass">{{ row.status }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12">
|
||||
<PptConclusionBox :text="report?.sections?.acquisition_channels?.conclusion" />
|
||||
@@ -1165,6 +1068,8 @@ function resetDashboard() {
|
||||
const PPT_BLUE = '#5B89FF';
|
||||
const PPT_ORANGE = '#FF8E4F';
|
||||
const PPT_GREEN = '#52C41A';
|
||||
const PPT_GRADIENT_BLUE_START = '#5B89FF';
|
||||
const PPT_GRADIENT_BLUE_END = '#82A7FF';
|
||||
|
||||
const roiValue = computed(() => report.value?.sections?.marketing_economics?.metrics?.roi ?? '—');
|
||||
const cacValue = computed(() => report.value?.sections?.marketing_economics?.metrics?.customer_acquisition_cost_cac ?? '—');
|
||||
@@ -1386,10 +1291,12 @@ const compactBarOptions = computed(() => ({
|
||||
const barWidth = Math.abs(bar.x - bar.base);
|
||||
if (barWidth > 40) {
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.font = 'bold 12px Inter, system-ui, sans-serif';
|
||||
ctx.textAlign = 'right';
|
||||
ctx.fillText(label, bar.x - 10, bar.y);
|
||||
ctx.fillText(label, bar.x - 12, bar.y);
|
||||
} else {
|
||||
ctx.fillStyle = '#64748b';
|
||||
ctx.font = 'bold 11px Inter, system-ui, sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText(label, bar.x + 10, bar.y);
|
||||
}
|
||||
@@ -1398,10 +1305,12 @@ const compactBarOptions = computed(() => ({
|
||||
ctx.textAlign = 'center';
|
||||
if (barHeight > 25) {
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fillText(label, bar.x, bar.y + 14);
|
||||
ctx.font = 'bold 14px Inter, system-ui, sans-serif';
|
||||
ctx.fillText(label, bar.x, bar.y + 16);
|
||||
} else {
|
||||
ctx.fillStyle = '#64748b';
|
||||
ctx.fillText(label, bar.x, bar.y - 10);
|
||||
ctx.font = 'bold 12px Inter, system-ui, sans-serif';
|
||||
ctx.fillText(label, bar.x, bar.y - 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1509,8 +1418,8 @@ const ageBarData = computed(() => ({
|
||||
backgroundColor: (context) => {
|
||||
const { chart } = context;
|
||||
const { ctx, chartArea } = chart;
|
||||
if (!chartArea) return 'rgba(91,137,255,0.55)';
|
||||
return makeVerticalGradient(ctx, chartArea, 'rgba(91,137,255,0.85)', 'rgba(91,137,255,0.25)');
|
||||
if (!chartArea) return PPT_BLUE;
|
||||
return makeVerticalGradient(ctx, chartArea, PPT_GRADIENT_BLUE_START, PPT_GRADIENT_BLUE_END);
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1576,8 +1485,8 @@ const incomeBarData = computed(() => ({
|
||||
backgroundColor: (context) => {
|
||||
const { chart } = context;
|
||||
const { ctx, chartArea } = chart;
|
||||
if (!chartArea) return 'rgba(82,196,26,0.55)';
|
||||
return makeVerticalGradient(ctx, chartArea, 'rgba(82,196,26,0.80)', 'rgba(82,196,26,0.25)');
|
||||
if (!chartArea) return PPT_GREEN;
|
||||
return makeVerticalGradient(ctx, chartArea, PPT_GREEN, '#73D13D');
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1832,8 +1741,8 @@ const decisionFactorsBarData = computed(() => {
|
||||
backgroundColor: (context) => {
|
||||
const { chart } = context;
|
||||
const { ctx, chartArea } = chart;
|
||||
if (!chartArea) return 'rgba(91,137,255,0.55)';
|
||||
return makeVerticalGradient(ctx, chartArea, 'rgba(91,137,255,0.85)', 'rgba(91,137,255,0.25)');
|
||||
if (!chartArea) return PPT_BLUE;
|
||||
return makeVerticalGradient(ctx, chartArea, PPT_GRADIENT_BLUE_START, PPT_GRADIENT_BLUE_END);
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1866,8 +1775,8 @@ const refusalReasonsBarData = computed(() => {
|
||||
backgroundColor: (context) => {
|
||||
const { chart } = context;
|
||||
const { ctx, chartArea } = chart;
|
||||
if (!chartArea) return 'rgba(255,142,79,0.55)';
|
||||
return makeVerticalGradient(ctx, chartArea, 'rgba(255,142,79,0.85)', 'rgba(255,142,79,0.25)');
|
||||
if (!chartArea) return PPT_ORANGE;
|
||||
return makeVerticalGradient(ctx, chartArea, PPT_ORANGE, '#FFBB96');
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2149,7 +2149,7 @@ const mapChartsDataToSegments = (chartsData) => {
|
||||
segments.push({
|
||||
type: 'chart',
|
||||
key: 'ageStructure',
|
||||
title: 'АРЫСТАНБЕК',
|
||||
title: 'Возрастная структура',
|
||||
chartType: 'bar',
|
||||
data: {
|
||||
labels,
|
||||
|
||||
Reference in New Issue
Block a user