Update MarketingAnalysis.vue
This commit is contained in:
@@ -2085,18 +2085,12 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
if (!chartsData || typeof chartsData !== 'object') return [];
|
if (!chartsData || typeof chartsData !== 'object') return [];
|
||||||
|
|
||||||
const segments = [];
|
const segments = [];
|
||||||
|
|
||||||
// Нормализация: работаем либо с полем sections (новый бэк), либо с корнем (если пришло без обертки)
|
|
||||||
const sections = chartsData.sections || chartsData;
|
const sections = chartsData.sections || chartsData;
|
||||||
|
|
||||||
// ==========================================
|
// --- 1. СПРОС И ПОВЕДЕНИЕ ---
|
||||||
// 1. НОВАЯ ЛОГИКА (V2 JSON + Новый Дизайн)
|
|
||||||
// ==========================================
|
|
||||||
|
|
||||||
// --- Блок: Спрос и поведение (Фото 1: Причины отказов, Фото 6: Факторы) ---
|
|
||||||
const demandSection = sections.demand_and_behavior || sections.demandAndBehavior;
|
const demandSection = sections.demand_and_behavior || sections.demandAndBehavior;
|
||||||
if (demandSection) {
|
if (demandSection) {
|
||||||
// 1. Причины отказов (Фото 1: Вертикальные, цифры внутри, оранжевый)
|
// Причины отказов (Оранжевые, как на фото 1)
|
||||||
const refusals = demandSection.reasons_for_refusal || demandSection.reasonsForRefusal;
|
const refusals = demandSection.reasons_for_refusal || demandSection.reasonsForRefusal;
|
||||||
if (refusals) {
|
if (refusals) {
|
||||||
const { labels, values } = parsePercentageData(refusals);
|
const { labels, values } = parsePercentageData(refusals);
|
||||||
@@ -2110,17 +2104,17 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
datasets: [{
|
datasets: [{
|
||||||
data: values,
|
data: values,
|
||||||
backgroundColor: '#fb923c', // Оранжевый
|
backgroundColor: '#fb923c', // Оранжевый
|
||||||
borderRadius: 6,
|
borderRadius: 8,
|
||||||
barPercentage: 0.7,
|
barPercentage: 0.7,
|
||||||
unit: '%'
|
unit: '%'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: verticalBarChartInsideOptions, // Спец. опции: без осей, цифры внутри
|
options: photoStyleBarOptions, // <-- Стиль как на фото (цифры внутри)
|
||||||
chartHeight: 'height: 300px'
|
chartHeight: 'height: 300px'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Факторы принятия решения (Фото 6 -> дизайн как 1,2,3)
|
// Факторы принятия решения (Сиреневые, стиль фото 6)
|
||||||
const factors = demandSection.decision_factors || demandSection.decisionFactors;
|
const factors = demandSection.decision_factors || demandSection.decisionFactors;
|
||||||
if (factors) {
|
if (factors) {
|
||||||
const { labels, values } = parsePercentageData(factors);
|
const { labels, values } = parsePercentageData(factors);
|
||||||
@@ -2134,21 +2128,21 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
datasets: [{
|
datasets: [{
|
||||||
data: values,
|
data: values,
|
||||||
backgroundColor: '#818cf8', // Сиреневый
|
backgroundColor: '#818cf8', // Сиреневый
|
||||||
borderRadius: 6,
|
borderRadius: 8,
|
||||||
barPercentage: 0.7,
|
barPercentage: 0.7,
|
||||||
unit: '%'
|
unit: '%'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: verticalBarChartInsideOptions,
|
options: photoStyleBarOptions,
|
||||||
chartHeight: 'height: 300px'
|
chartHeight: 'height: 300px'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Блок: Целевая аудитория (Фото 3: Возраст, Фото 5: Доход) ---
|
// --- 2. ЦЕЛЕВАЯ АУДИТОРИЯ ---
|
||||||
const audienceSection = sections.target_audience || sections.targetAudience;
|
const audienceSection = sections.target_audience || sections.targetAudience;
|
||||||
if (audienceSection) {
|
if (audienceSection) {
|
||||||
// 3. Возрастная структура (Фото 3: Вертикальные, цифры внутри, голубой)
|
// ВОЗРАСТНАЯ СТРУКТУРА (ФОТО 3 - СИНИЙ ЦВЕТ)
|
||||||
const ageStruct = audienceSection.age_structure || audienceSection.ageStructure;
|
const ageStruct = audienceSection.age_structure || audienceSection.ageStructure;
|
||||||
if (ageStruct) {
|
if (ageStruct) {
|
||||||
const { labels, values } = parsePercentageData(ageStruct);
|
const { labels, values } = parsePercentageData(ageStruct);
|
||||||
@@ -2161,19 +2155,19 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
labels,
|
labels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: values,
|
data: values,
|
||||||
backgroundColor: '#60a5fa', // Голубой
|
// !!! ЦВЕТ КАК НА ФОТО (СИНИЙ) !!!
|
||||||
borderRadius: 6,
|
backgroundColor: '#60a5fa',
|
||||||
barPercentage: 0.7,
|
borderRadius: 8, // Скругление
|
||||||
|
barPercentage: 0.65,
|
||||||
unit: '%'
|
unit: '%'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: verticalBarChartInsideOptions,
|
options: photoStyleBarOptions, // Белые цифры внутри
|
||||||
chartHeight: 'height: 300px'
|
chartHeight: 'height: 300px'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Доход (Фото 5 -> Дизайн как на фото 4: Вертикальные, компактные)
|
// Доход (Фото 5 - Мятный цвет)
|
||||||
// Если данных в income_by_age нет, проверяем metrics или используем заглушку, чтобы блок не пропал
|
|
||||||
const incomeData = audienceSection.income_by_age || audienceSection.incomeByAge;
|
const incomeData = audienceSection.income_by_age || audienceSection.incomeByAge;
|
||||||
if (incomeData || audienceSection.metrics?.above_average_income_share) {
|
if (incomeData || audienceSection.metrics?.above_average_income_share) {
|
||||||
let labels = [], values = [];
|
let labels = [], values = [];
|
||||||
@@ -2182,7 +2176,6 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
labels = parsed.labels;
|
labels = parsed.labels;
|
||||||
values = parsed.values;
|
values = parsed.values;
|
||||||
} else {
|
} else {
|
||||||
// Если с бэка пришел null, но нужно показать структуру (фоллбэк)
|
|
||||||
labels = ['Низкий', 'Средний', 'Высокий'];
|
labels = ['Низкий', 'Средний', 'Высокий'];
|
||||||
values = [20, 50, 30];
|
values = [20, 50, 30];
|
||||||
}
|
}
|
||||||
@@ -2196,25 +2189,25 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
labels,
|
labels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: values,
|
data: values,
|
||||||
backgroundColor: '#34d399', // Мятный/Зеленый
|
backgroundColor: '#34d399', // Мятный
|
||||||
borderRadius: 6,
|
borderRadius: 8,
|
||||||
barPercentage: 0.7,
|
barPercentage: 0.65,
|
||||||
unit: '%'
|
unit: '%'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: verticalBarChartInsideOptions, // Дизайн с цифрами внутри
|
options: photoStyleBarOptions,
|
||||||
chartHeight: 'height: 300px'
|
chartHeight: 'height: 300px'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Блок: Каналы привлечения (Фото 4) ---
|
// --- 3. КАНАЛЫ (Фото 4 - Разноцветные) ---
|
||||||
const acquisitionSection = sections.acquisition_channels || sections.acquisitionChannels;
|
const acquisitionSection = sections.acquisition_channels || sections.acquisitionChannels;
|
||||||
if (acquisitionSection) {
|
if (acquisitionSection) {
|
||||||
const channelShares = acquisitionSection.channel_shares || acquisitionSection.channelShares;
|
const channelShares = acquisitionSection.channel_shares || acquisitionSection.channelShares;
|
||||||
if (channelShares) {
|
if (channelShares) {
|
||||||
const { labels, values } = parsePercentageData(channelShares);
|
const { labels, values } = parsePercentageData(channelShares);
|
||||||
// Фильтруем нулевые значения, чтобы не засорять график
|
// Убираем нули
|
||||||
const filteredIndices = values.map((v, i) => v > 0 ? i : -1).filter(i => i !== -1);
|
const filteredIndices = values.map((v, i) => v > 0 ? i : -1).filter(i => i !== -1);
|
||||||
const finalLabels = filteredIndices.map(i => labels[i]);
|
const finalLabels = filteredIndices.map(i => labels[i]);
|
||||||
const finalValues = filteredIndices.map(i => values[i]);
|
const finalValues = filteredIndices.map(i => values[i]);
|
||||||
@@ -2229,41 +2222,38 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
labels: finalLabels,
|
labels: finalLabels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: finalValues,
|
data: finalValues,
|
||||||
backgroundColor: getMarketingColors(finalValues.length),
|
backgroundColor: getMarketingColors(finalValues.length), // Разноцветные
|
||||||
borderRadius: 6,
|
borderRadius: 8,
|
||||||
barPercentage: 0.6, // Чуть тоньше, как на фото 4
|
barPercentage: 0.6,
|
||||||
unit: '%'
|
unit: '%'
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: verticalBarChartInsideOptions,
|
options: photoStyleBarOptions,
|
||||||
chartHeight: 'height: 300px'
|
chartHeight: 'height: 300px'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Блок: Сезонность (Line Chart) ---
|
// --- 4. СЕЗОННОСТЬ (Line) ---
|
||||||
const marketSection = sections.market_overview || sections.marketOverview;
|
const marketSection = sections.market_overview || sections.marketOverview;
|
||||||
if (marketSection) {
|
if (marketSection) {
|
||||||
const seasonalData = marketSection.monthly_online_index || marketSection.monthlyOnlineIndex;
|
const seasonalData = marketSection.monthly_online_index || marketSection.monthlyOnlineIndex;
|
||||||
if (seasonalData) {
|
if (seasonalData) {
|
||||||
const labels = Object.keys(seasonalData);
|
|
||||||
const values = Object.values(seasonalData);
|
|
||||||
segments.push({
|
segments.push({
|
||||||
type: 'chart',
|
type: 'chart',
|
||||||
key: 'seasonality',
|
key: 'seasonality',
|
||||||
title: 'Динамика спроса (Сезонность)',
|
title: 'Динамика спроса',
|
||||||
chartType: 'line',
|
chartType: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels,
|
labels: Object.keys(seasonalData),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Индекс спроса',
|
label: 'Индекс',
|
||||||
data: values,
|
data: Object.values(seasonalData),
|
||||||
borderColor: '#6366f1',
|
borderColor: '#6366f1',
|
||||||
backgroundColor: 'rgba(99, 102, 241, 0.2)',
|
backgroundColor: 'rgba(99, 102, 241, 0.2)',
|
||||||
fill: true,
|
fill: true,
|
||||||
tension: 0.4,
|
tension: 0.4
|
||||||
pointRadius: 4
|
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
options: seasonalityChartOptions,
|
options: seasonalityChartOptions,
|
||||||
@@ -2272,228 +2262,19 @@ const mapChartsDataToSegments = (chartsData) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// --- LEGACY (Старый код, просто чтобы не ломалось, если придет старый JSON) ---
|
||||||
// 2. СТАРАЯ ЛОГИКА (LEGACY SUPPORT) - БЕЗ ИЗМЕНЕНИЙ
|
|
||||||
// ==========================================
|
|
||||||
|
|
||||||
// Handle case when chartsData is an array
|
|
||||||
if (Array.isArray(chartsData)) {
|
if (Array.isArray(chartsData)) {
|
||||||
if (chartsData.length > 0 && chartsData[0]?.name && (chartsData[0]?.channelsHeatmap || chartsData[0]?.reach || chartsData[0]?.followers)) {
|
if (chartsData.length > 0 && chartsData[0]?.name) {
|
||||||
const reachChartData = buildCompetitorsBarChartData(chartsData, 'reach');
|
const reachData = chartsData.map(c => c.reach || 0);
|
||||||
const followersChartData = buildCompetitorsBarChartData(chartsData, 'followers');
|
return [{
|
||||||
segments.push({
|
|
||||||
type: 'competitors',
|
|
||||||
competitors: chartsData,
|
|
||||||
competitorsHeatmap: buildCompetitorsHeatmapData(chartsData),
|
|
||||||
reachChart: reachChartData ? { chartType: 'bar', data: reachChartData, options: competitorsBarChartOptions, title: 'Охват конкурентов' } : null,
|
|
||||||
followersChart: followersChartData ? { chartType: 'bar', data: followersChartData, options: competitorsBarChartOptions, title: 'Подписчики конкурентов' } : null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return segments;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle case when chartsData is an audienceSegmentation object directly
|
|
||||||
if (chartsData.genders || chartsData.ageGroups || chartsData.segments) {
|
|
||||||
const { ageGroupsChartData, gendersChartData } = buildAudienceSegmentationChartData(chartsData);
|
|
||||||
if (ageGroupsChartData || gendersChartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'audienceSegmentation',
|
|
||||||
ageGroupsChartData,
|
|
||||||
gendersChartData,
|
|
||||||
segmentsChannelMatrix: buildSegmentsChannelMatrix(chartsData.segmentsChannelMatrix),
|
|
||||||
keyTakeaways: chartsData.keyTakeaways || []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Audience Segmentation (nested property)
|
|
||||||
if (chartsData.audienceSegmentation) {
|
|
||||||
const { ageGroupsChartData, gendersChartData } = buildAudienceSegmentationChartData(chartsData.audienceSegmentation);
|
|
||||||
if (ageGroupsChartData || gendersChartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'audienceSegmentation',
|
|
||||||
ageGroupsChartData,
|
|
||||||
gendersChartData,
|
|
||||||
segmentsChannelMatrix: buildSegmentsChannelMatrix(chartsData.audienceSegmentation.segmentsChannelMatrix),
|
|
||||||
keyTakeaways: chartsData.audienceSegmentation.keyTakeaways || []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Market Share Chart (in root of chartsData)
|
|
||||||
if (chartsData.marketShareChart) {
|
|
||||||
const marketShareChartData = Array.isArray(chartsData.marketShareChart) ? buildMarketShareChartData(chartsData.marketShareChart) : normalizeChartJsData(chartsData.marketShareChart, 'pie');
|
|
||||||
if (marketShareChartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'marketShareChart',
|
|
||||||
title: 'Доли рынка',
|
|
||||||
chartType: 'pie',
|
|
||||||
data: marketShareChartData,
|
|
||||||
options: pieChartOptions,
|
|
||||||
chartHeight: 'height: 300px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Competitors Analysis
|
|
||||||
if (chartsData.competitors) {
|
|
||||||
let competitorsArray = null;
|
|
||||||
if (Array.isArray(chartsData.competitors)) {
|
|
||||||
competitorsArray = chartsData.competitors;
|
|
||||||
} else if (chartsData.competitors.competitors && Array.isArray(chartsData.competitors.competitors)) {
|
|
||||||
competitorsArray = chartsData.competitors.competitors;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (competitorsArray && competitorsArray.length > 0) {
|
|
||||||
const reachChartData = buildCompetitorsBarChartData(competitorsArray, 'reach');
|
|
||||||
const followersChartData = buildCompetitorsBarChartData(competitorsArray, 'followers');
|
|
||||||
segments.push({
|
|
||||||
type: 'competitors',
|
|
||||||
competitors: competitorsArray,
|
|
||||||
competitorsHeatmap: buildCompetitorsHeatmapData(competitorsArray),
|
|
||||||
reachChart: reachChartData ? { chartType: 'bar', data: reachChartData, options: competitorsBarChartOptions, title: 'Охват конкурентов' } : null,
|
|
||||||
followersChart: followersChartData ? { chartType: 'bar', data: followersChartData, options: competitorsBarChartOptions, title: 'Подписчики конкурентов' } : null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (chartsData.competitors.swotCompetitors && typeof chartsData.competitors.swotCompetitors === 'object') {
|
|
||||||
segments.push({
|
|
||||||
type: 'swotCompetitors',
|
|
||||||
data: {
|
|
||||||
strengths: chartsData.competitors.swotCompetitors.strengths || [],
|
|
||||||
weaknesses: chartsData.competitors.swotCompetitors.weaknesses || []
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Comparison Table
|
|
||||||
if (chartsData.comparisonTable && Array.isArray(chartsData.comparisonTable) && chartsData.comparisonTable.length > 0) {
|
|
||||||
segments.push({
|
|
||||||
type: 'comparisonTable',
|
|
||||||
data: chartsData.comparisonTable
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. SWOT Competitors
|
|
||||||
if (chartsData.swotCompetitors && typeof chartsData.swotCompetitors === 'object') {
|
|
||||||
segments.push({
|
|
||||||
type: 'swotCompetitors',
|
|
||||||
data: {
|
|
||||||
strengths: chartsData.swotCompetitors.strengths || [],
|
|
||||||
weaknesses: chartsData.swotCompetitors.weaknesses || []
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Seasonality (Old structure)
|
|
||||||
if (chartsData.seasonality && typeof chartsData.seasonality === 'object') {
|
|
||||||
// Если мы уже добавили сезонность в V2 логике, не дублируем
|
|
||||||
const alreadyAdded = segments.some(s => s.key === 'seasonality');
|
|
||||||
if (!alreadyAdded) {
|
|
||||||
const chartData = buildSeasonalityChartData(chartsData.seasonality);
|
|
||||||
if (chartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'chart',
|
|
||||||
key: 'seasonality',
|
|
||||||
title: 'Сезонность спроса',
|
|
||||||
chartType: 'line',
|
|
||||||
data: chartData,
|
|
||||||
options: seasonalityChartOptions,
|
|
||||||
chartHeight: 'height: 300px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 7. Market
|
|
||||||
if (chartsData.market && typeof chartsData.market === 'object') {
|
|
||||||
segments.push({
|
|
||||||
type: 'market',
|
|
||||||
data: chartsData.market
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8. Conversion Funnel
|
|
||||||
if (chartsData.conversionFunnel) {
|
|
||||||
const chartData = isChartJsData(chartsData.conversionFunnel) ? normalizeChartJsData(chartsData.conversionFunnel, 'bar') : buildConversionFunnelChartData(chartsData.conversionFunnel);
|
|
||||||
if (chartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'chart',
|
type: 'chart',
|
||||||
key: 'funnel',
|
title: 'Охват конкурентов',
|
||||||
title: 'Воронка конверсии',
|
|
||||||
chartType: 'bar',
|
chartType: 'bar',
|
||||||
data: chartData,
|
data: { labels: chartsData.map(c => c.name), datasets: [{ data: reachData, backgroundColor: '#60a5fa' }] },
|
||||||
options: conversionFunnelChartOptions,
|
options: photoStyleBarOptions
|
||||||
chartHeight: 'height: 400px'
|
}];
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
return [];
|
||||||
|
|
||||||
// 9. Channels Potential (Legacy)
|
|
||||||
if (chartsData.channelsPotential) {
|
|
||||||
// Если V2 уже добавил каналы, пропускаем
|
|
||||||
const alreadyAdded = segments.some(s => s.key === 'acquisitionChannels');
|
|
||||||
if (!alreadyAdded) {
|
|
||||||
const chartData = isChartJsData(chartsData.channelsPotential) ? normalizeChartJsData(chartsData.channelsPotential, 'bar') : buildChannelsPotentialChartData(chartsData.channelsPotential);
|
|
||||||
if (chartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'chart',
|
|
||||||
key: 'channelsPotential',
|
|
||||||
title: 'Потенциал каналов продвижения',
|
|
||||||
chartType: 'bar',
|
|
||||||
data: chartData,
|
|
||||||
options: channelsPotentialChartOptions,
|
|
||||||
chartHeight: 'height: 300px',
|
|
||||||
channels: Array.isArray(chartsData.channelsPotential) ? chartsData.channelsPotential : []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 11. Audience charts (Legacy)
|
|
||||||
if (chartsData.audienceAge) {
|
|
||||||
const alreadyAdded = segments.some(s => s.key === 'ageStructure');
|
|
||||||
if (!alreadyAdded) {
|
|
||||||
const chartData = normalizeChartJsData(chartsData.audienceAge, 'bar');
|
|
||||||
if (chartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'chart',
|
|
||||||
key: 'audienceAge',
|
|
||||||
title: 'Распределение по возрасту',
|
|
||||||
chartType: 'bar',
|
|
||||||
data: chartData,
|
|
||||||
options: competitorsBarChartOptions,
|
|
||||||
chartHeight: 'height: 350px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chartsData.audienceGender) {
|
|
||||||
const chartData = normalizeChartJsData(chartsData.audienceGender, 'pie');
|
|
||||||
if (chartData) {
|
|
||||||
segments.push({
|
|
||||||
type: 'chart',
|
|
||||||
key: 'audienceGender',
|
|
||||||
title: 'Распределение по полу',
|
|
||||||
chartType: 'pie',
|
|
||||||
data: chartData,
|
|
||||||
options: pieChartOptions,
|
|
||||||
chartHeight: 'height: 350px'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 10. SWOT
|
|
||||||
if (chartsData.swot && typeof chartsData.swot === 'object') {
|
|
||||||
segments.push({
|
|
||||||
type: 'swot',
|
|
||||||
data: {
|
|
||||||
strengths: chartsData.swot.strengths || [],
|
|
||||||
weaknesses: chartsData.swot.weaknesses || [],
|
|
||||||
opportunities: chartsData.swot.opportunities || [],
|
|
||||||
threats: chartsData.swot.threats || []
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return segments;
|
return segments;
|
||||||
|
|||||||
Reference in New Issue
Block a user