4.9 KiB
4.9 KiB
Документация для фронтенда: как отображать графики из маркетингового анализа
Сервис возвращает данные для графиков в двух местах:
report.chartsData(объект-словарь ключ → данные графика/таблицы)report.fullAnalysis(markdown-текст), где данные вставлены инлайн как fenced-блоки:- формат:
json:<key> …
- формат:
Фронтенд может рендерить графики либо по chartsData (проще), либо инлайн — парся fullAnalysis и заменяя ```json:<key> на React-компоненты.
Ключи json:<key>, которые нужно поддержать
Chart.js config (рендерить через Chart.js / react-chartjs-2)
seasonality: сезонность (Chart.js config)audienceAge: возрастное распределение (Chart.js config)audienceGender: гендерное распределение (Chart.js config)marketShareChart: доли рынка (Chart.js config)channelsPotential: потенциал каналов (Chart.js config)funnel: воронка (Chart.js config)
Примечание: вchartsDataключ может бытьconversionFunnel, но в текстеfullAnalysisблок идёт какjson:funnel.
Таблица (рендерить табличным компонентом)
comparisonTable: сравнительная таблица конкурентов (обычноArray<Object>)
Формат данных для графиков (Chart.js config)
Ваш пример — это валидный Chart.js config (минимально нужные поля: labels, datasets[]):
{
"datasets": [
{
"data": [25, 30, 20, 25],
"label": "Возрастные группы"
}
],
"labels": ["18-24", "25-34", "35-44", "45+"]
}
Рендеринг (пример для Bar):
<Bar data={chartJson} />
Инлайн-рендеринг из fullAnalysis (React + react-markdown)
Идея: перехватить code-блоки, найти json:<key>, распарсить JSON и заменить на компонент.
import React from "react";
import ReactMarkdown from "react-markdown";
function parseInfoString(className?: string) {
// react-markdown обычно кладёт info string как className вида:
// "language-json:audienceAge" или "language-json:marketShareChart"
const m = /language-([^ ]+)/.exec(className || "");
if (!m) return null;
const raw = m[1]; // "json:audienceAge"
const idx = raw.indexOf(":");
if (idx === -1) return { lang: raw, key: null };
return { lang: raw.slice(0, idx), key: raw.slice(idx + 1) };
}
export function ReportMarkdown({ markdown }: { markdown: string }) {
return (
<ReactMarkdown
components={{
code({ inline, className, children, ...props }) {
if (inline) return <code className={className} {...props}>{children}</code>;
const info = parseInfoString(className);
if (!info || info.lang !== "json" || !info.key) {
return <pre><code className={className} {...props}>{children}</code></pre>;
}
const raw = String(children).replace(/\n$/, "");
let data: any;
try {
data = JSON.parse(raw);
} catch {
return <pre><code className={className} {...props}>{children}</code></pre>;
}
switch (info.key) {
case "seasonality":
return <SeasonalityChart data={data} />;
case "audienceAge":
return <AudienceAgeChart data={data} />;
case "audienceGender":
return <AudienceGenderChart data={data} />;
case "marketShareChart":
return <MarketShareChart data={data} />;
case "channelsPotential":
return <ChannelsPotentialChart data={data} />;
case "funnel":
return <FunnelChart data={data} />;
case "comparisonTable":
return <ComparisonTable data={data} />;
default:
return <pre><code className={className} {...props}>{children}</code></pre>;
}
},
}}
>
{markdown}
</ReactMarkdown>
);
}
Рекомендации по устойчивости
- JSON.parse: всегда
trim/убирайте trailing newline (replace(/\n$/, "")). - Fallback: для неизвестных ключей оставляйте
<pre>(чтобы ничего не “ломалось”). - Таблицы:
comparisonTableлучше рендерить как таблицу, а не Chart.js.