6536c19c96
Экран «Лиды» (/admin/leads): серверный список с фильтрами (дата/канал/поставщик/
статус/поиск) + пагинация (масштаб 10⁴+ лидов). Карточка лида (/admin/leads/{id}):
полная цепочка — ОТКУДА (поставщик B1/B2/B3 + канал + источник + регион) → КОМУ
(сделки клиентов через deals.source_crm_id = supplier_leads.vid). Дашборд: drill
Лиды +топ-10 последних + «Открыть все лиды →». Nav-пункт «Лиды». ПДн-телефон
маскируется (152-ФЗ). Тесты: backend 3 + FE 5 (38 FE всего зелёные).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
import { apiClient } from './client';
|
|
|
|
/**
|
|
* SaaS-admin «Лиды» (L3) — сквозная вложенность дашборда до источника.
|
|
* Серверная пагинация/фильтры. Backend: AdminLeadsController.
|
|
* Spec: docs/superpowers/specs/2026-06-28-dashboard-drilldown-scale-design.md
|
|
*/
|
|
|
|
export type LeadStatus = 'delivered' | 'no_match' | 'pending' | 'stuck' | 'error';
|
|
|
|
export interface LeadRow {
|
|
id: number;
|
|
received_at: string;
|
|
platform: string;
|
|
channel: string | null;
|
|
source: string | null;
|
|
region_code: number | null;
|
|
phone_masked: string;
|
|
deals_created_count: number;
|
|
status: string;
|
|
}
|
|
|
|
export interface LeadsPage {
|
|
data: LeadRow[];
|
|
total: number;
|
|
page: number;
|
|
per_page: number;
|
|
}
|
|
|
|
export interface LeadsFilters {
|
|
page?: number;
|
|
per_page?: number;
|
|
date_from?: string;
|
|
date_to?: string;
|
|
channel?: string;
|
|
platform?: string;
|
|
status?: string;
|
|
tenant_id?: number;
|
|
search?: string;
|
|
}
|
|
|
|
export interface LeadDetail {
|
|
lead: {
|
|
id: number;
|
|
platform: string;
|
|
phone_masked: string;
|
|
received_at: string;
|
|
processed_at: string | null;
|
|
error: string | null;
|
|
region_code: number | null;
|
|
region_source: string | null;
|
|
phone_operator: string | null;
|
|
deals_created_count: number;
|
|
status: string;
|
|
};
|
|
source: {
|
|
platform: string;
|
|
channel: string | null;
|
|
identifier: string | null;
|
|
supplier_project_id: number | null;
|
|
};
|
|
deals: Array<{
|
|
id: number;
|
|
tenant_id: number;
|
|
tenant_name: string;
|
|
subdomain: string;
|
|
status: string;
|
|
project_id: number | null;
|
|
received_at: string;
|
|
}>;
|
|
}
|
|
|
|
export async function getLeads(filters: LeadsFilters): Promise<LeadsPage> {
|
|
const { data } = await apiClient.get<LeadsPage>('/api/admin/leads', { params: filters });
|
|
return data;
|
|
}
|
|
|
|
export async function getLead(id: number | string): Promise<LeadDetail> {
|
|
const { data } = await apiClient.get<LeadDetail>(`/api/admin/leads/${id}`);
|
|
return data;
|
|
}
|