{
  "name": "screen-report",
  "type": "registry:page",
  "dependencies": [
    "@lucide/vue",
    "@unovis/vue"
  ],
  "registryDependencies": [
    "badge",
    "breadcrumb",
    "button",
    "card",
    "chart",
    "https://ui.dvizh.website/r/screen-shell.json",
    "progress",
    "separator",
    "sidebar",
    "tabs"
  ],
  "files": [
    {
      "path": "screens/report/ReportScreen.vue",
      "type": "registry:file",
      "target": "screens/report/ReportScreen.vue",
      "content": "<script setup lang=\"ts\">\n/**\n * Отчёт по воронке.\n *\n * Сценарий: конец месяца, руководитель готовит цифры к встрече с собственником. Ему нужно\n * четыре числа наверху, помесячная динамика против плана и распределение сделок по стадиям.\n * Всё остальное — лишнее: отчёт читают минуту и уходят.\n */\nimport type { ChartConfig } from '@/components/ui/chart'\nimport { VisAxis, VisGroupedBar, VisLine, VisXYContainer } from '@unovis/vue'\nimport { DownloadIcon, TrendingDownIcon, TrendingUpIcon } from '@lucide/vue'\nimport { Badge } from '@/components/ui/badge'\nimport {\n  Breadcrumb,\n  BreadcrumbItem,\n  BreadcrumbList,\n  BreadcrumbPage,\n} from '@/components/ui/breadcrumb'\nimport { Button } from '@/components/ui/button'\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from '@/components/ui/card'\nimport {\n  ChartContainer,\n  ChartCrosshair,\n  ChartTooltip,\n  ChartTooltipContent,\n  componentToString,\n} from '@/components/ui/chart'\nimport { Progress } from '@/components/ui/progress'\nimport { Separator } from '@/components/ui/separator'\nimport { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'\nimport { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'\nimport CrmSidebar from '../CrmSidebar.vue'\nimport { funnel, monthly, reportMetrics } from '../data'\n\ntype Month = (typeof monthly)[number]\n\nconst chartConfig = {\n  closed: { label: 'Закрыто, млн ₽', color: 'var(--chart-1)' },\n  plan: { label: 'План, млн ₽', color: 'var(--chart-2)' },\n} satisfies ChartConfig\n\n/** Ширина полосы стадии считается от самой массовой, иначе мелкие стадии не видно. */\nconst widest = Math.max(...funnel.map((step) => step.count))\n</script>\n\n<template>\n  <SidebarProvider>\n    <CrmSidebar section=\"Отчёты\" />\n    <SidebarInset>\n      <header class=\"flex h-16 shrink-0 items-center gap-2 border-b px-4\">\n        <SidebarTrigger class=\"-ml-1\" />\n        <Separator orientation=\"vertical\" class=\"mr-2 data-[orientation=vertical]:h-4\" />\n        <Breadcrumb>\n          <BreadcrumbList>\n            <BreadcrumbItem><BreadcrumbPage>Отчёт по воронке</BreadcrumbPage></BreadcrumbItem>\n          </BreadcrumbList>\n        </Breadcrumb>\n        <div class=\"ml-auto flex items-center gap-2\">\n          <Tabs default-value=\"quarter\">\n            <TabsList>\n              <TabsTrigger value=\"month\">Месяц</TabsTrigger>\n              <TabsTrigger value=\"quarter\">Квартал</TabsTrigger>\n              <TabsTrigger value=\"year\">Год</TabsTrigger>\n            </TabsList>\n          </Tabs>\n          <Button variant=\"outline\" size=\"sm\">\n            <DownloadIcon />\n            Выгрузить\n          </Button>\n        </div>\n      </header>\n\n      <div class=\"flex flex-1 flex-col gap-4 p-4 lg:p-6\">\n        <div class=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n          <Card v-for=\"metric in reportMetrics\" :key=\"metric.title\">\n            <CardHeader>\n              <CardDescription>{{ metric.title }}</CardDescription>\n              <CardTitle class=\"font-heading text-2xl\">{{ metric.value }}</CardTitle>\n            </CardHeader>\n            <CardFooter class=\"flex-col items-start gap-1 text-sm\">\n              <span class=\"flex items-center gap-1 font-medium\">\n                <component\n                  :is=\"metric.delta.startsWith('−') ? TrendingDownIcon : TrendingUpIcon\"\n                  class=\"size-4\"\n                />\n                {{ metric.delta }}\n              </span>\n              <span class=\"text-muted-foreground\">{{ metric.hint }}</span>\n            </CardFooter>\n          </Card>\n        </div>\n\n        <div class=\"grid gap-4 xl:grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)]\">\n          <Card>\n            <CardHeader>\n              <CardTitle>Закрытая выручка против плана</CardTitle>\n              <CardDescription>Апрель — сентябрь 2026, млн ₽</CardDescription>\n            </CardHeader>\n            <CardContent>\n              <ChartContainer :config=\"chartConfig\" class=\"h-64 w-full\">\n                <VisXYContainer :data=\"monthly\" :margin=\"{ left: -16 }\" :y-domain=\"[0, undefined]\">\n                  <VisGroupedBar\n                    :x=\"(d: Month, i: number) => i\"\n                    :y=\"(d: Month) => d.closed\"\n                    :color=\"chartConfig.closed.color\"\n                    :rounded-corners=\"8\"\n                  />\n                  <VisLine\n                    :x=\"(d: Month, i: number) => i\"\n                    :y=\"(d: Month) => d.plan\"\n                    :color=\"chartConfig.plan.color\"\n                  />\n                  <VisAxis\n                    type=\"x\"\n                    :tick-line=\"false\"\n                    :domain-line=\"false\"\n                    :grid-line=\"false\"\n                    :num-ticks=\"monthly.length\"\n                    :tick-format=\"(i: number) => monthly[i]?.month ?? ''\"\n                  />\n                  <VisAxis type=\"y\" :num-ticks=\"4\" :tick-line=\"false\" :domain-line=\"false\" />\n                  <ChartTooltip />\n                  <ChartCrosshair\n                    :template=\"componentToString(chartConfig, ChartTooltipContent, {})\"\n                    color=\"#0000\"\n                  />\n                </VisXYContainer>\n              </ChartContainer>\n            </CardContent>\n            <CardFooter class=\"text-muted-foreground text-sm\">\n              План не выполнен в апреле и июне; июль вытянул квартал.\n            </CardFooter>\n          </Card>\n\n          <Card>\n            <CardHeader>\n              <CardTitle>Сделки по стадиям</CardTitle>\n              <CardDescription>Сколько сейчас в работе</CardDescription>\n            </CardHeader>\n            <CardContent class=\"space-y-4\">\n              <div v-for=\"step in funnel\" :key=\"step.stage\" class=\"space-y-1.5\">\n                <div class=\"flex items-baseline justify-between gap-2 text-sm\">\n                  <span class=\"font-medium\">{{ step.stage }}</span>\n                  <span class=\"text-muted-foreground tabular-nums\">\n                    {{ step.count }} шт · {{ step.amount }} млн ₽\n                  </span>\n                </div>\n                <Progress :model-value=\"(step.count / widest) * 100\" />\n              </div>\n            </CardContent>\n            <CardFooter class=\"flex-wrap gap-2\">\n              <Badge variant=\"secondary\">Конверсия в оплату 17 %</Badge>\n              <Badge variant=\"outline\">Узкое место: коммерческое</Badge>\n            </CardFooter>\n          </Card>\n        </div>\n      </div>\n    </SidebarInset>\n  </SidebarProvider>\n</template>\n"
    }
  ]
}
