Files
portal/app/resources/js/components/billing/TierPricesPanel.vue
T
Дмитрий 3cedf28f33
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
feat/ui: подсказки вопросик по карте — дашборд, мастер проекта, биллинг
Дашборд: вопросик у KPI Получено/Конверсия/Активные, у воронки и у прогноза хватит на N дней; pp на п.п.
Мастер проекта: подпись лимита заявок в день + вопросик у выбора источника Сайт/Звонок/СМС.
Биллинг: вопросик у Цены за лид 7 ступеней.
Тест FunnelChart 8/8, type-check чистый, затронутые спеки 58/60.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 13:41:27 +03:00

112 lines
3.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
/**
* TierPricesPanel — свёрнутый по умолчанию блок с ценами 7 ступеней.
* Подсвечивает текущую ступень чипом «вы здесь». Источник данных —
* GET /api/billing/wallet → tiers_preview + current_tier.no.
*
* Billing v2 Spec A §3.4.8.
*/
interface TierPreview {
tier_no: number;
leads_in_tier: number | null;
price_rub: string;
}
const props = defineProps<{
tiers: TierPreview[];
currentTierNo: number | null;
}>();
function rangeText(idx: number): string {
let start = 1;
for (let i = 0; i < idx; i++) {
const cap = props.tiers[i].leads_in_tier;
if (cap !== null) start += cap;
}
const cap = props.tiers[idx].leads_in_tier;
if (cap === null) return `${start}+`;
return `${start}${start + cap - 1}`;
}
</script>
<template>
<v-expansion-panels class="mt-4 tier-prices">
<v-expansion-panel eager>
<template #title>
<span>Цены за лид (7 ступеней)</span>
<v-tooltip
text="Чем больше заявок в месяц — тем дешевле каждая. Ступень определяется по объёму, «вы здесь» — ваша текущая."
location="top"
max-width="280"
>
<template #activator="{ props: tip }">
<v-icon
v-bind="tip"
size="14"
class="tier-hint ml-1"
icon="mdi-help-circle-outline"
aria-label="Как считаются цены за лид"
tabindex="0"
@click.stop
/>
</template>
</v-tooltip>
</template>
<template #text>
<ul class="tier-list">
<li
v-for="(t, i) in tiers"
:key="t.tier_no"
data-test="tier-row"
:data-test-row="`tier-row-${t.tier_no}`"
class="tier-row"
:class="{ 'tier-row--current': t.tier_no === currentTierNo }"
>
<span class="tier-no num">{{ t.tier_no }}</span>
<span class="tier-range">{{ rangeText(i) }} лидов</span>
<span class="tier-price num">{{ t.price_rub }} </span>
<v-chip v-if="t.tier_no === currentTierNo" size="x-small" color="primary" variant="elevated"
>вы здесь</v-chip
>
</li>
</ul>
</template>
</v-expansion-panel>
</v-expansion-panels>
</template>
<style scoped>
.tier-hint {
color: #9b9484;
cursor: help;
vertical-align: middle;
}
.tier-hint:hover {
color: #0f6e56;
}
.tier-list {
list-style: none;
padding: 0;
margin: 0;
}
.tier-row {
display: grid;
grid-template-columns: 60px 1fr auto auto;
gap: 12px;
align-items: center;
padding: 8px 12px;
}
.tier-row--current {
background: rgba(15, 110, 86, 0.07);
border-left: 3px solid #0f6e56;
}
.num {
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-feature-settings: 'tnum';
}
.tier-price {
color: #0f6e56;
font-weight: 600;
}
</style>