geo/frontend/lib/dashboard-health.ts

281 lines
6.5 KiB
TypeScript

/**
* 健康状态Dashboard工具函数
*/
import {
HealthLevel,
HealthLevelConfig,
HEALTH_LEVEL_CONFIG,
PlatformScoreWithCompetitor,
ActionSuggestion,
} from "@/types/dashboard-health";
/**
* 根据评分获取健康等级
*/
export function getHealthLevel(score: number): HealthLevel {
if (score >= 80) return "excellent";
if (score >= 60) return "good";
if (score >= 40) return "pass";
return "danger";
}
/**
* 获取健康等级配置
*/
export function getHealthLevelConfig(level: HealthLevel): HealthLevelConfig {
return HEALTH_LEVEL_CONFIG[level];
}
/**
* 获取健康等级的CSS类名
*/
export function getHealthLevelClassName(level: HealthLevel): {
bg: string;
text: string;
border: string;
badge: string;
} {
const config = HEALTH_LEVEL_CONFIG[level];
return {
bg: config.color.bg,
text: config.color.text,
border: config.color.border,
badge: `inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium ${config.color.bg} ${config.color.text}`,
};
}
/**
* 计算平台评分与竞品的差距
*/
export function calculateCompetitorGap(
platformScore: number,
competitorScore?: number,
): {
ahead: boolean;
behind: boolean;
equal: boolean;
gap: number;
text: string;
} {
if (competitorScore === undefined || competitorScore === null) {
return {
ahead: false,
behind: false,
equal: true,
gap: 0,
text: "暂无竞品数据",
};
}
const gap = platformScore - competitorScore;
if (gap > 0) {
return {
ahead: true,
behind: false,
equal: false,
gap,
text: `领先${gap}`,
};
} else if (gap < 0) {
return {
ahead: false,
behind: true,
equal: false,
gap: Math.abs(gap),
text: `落后${Math.abs(gap)}`,
};
} else {
return {
ahead: false,
behind: false,
equal: true,
gap: 0,
text: "持平",
};
}
}
/**
* 获取趋势图标和颜色
*/
export function getTrendStyle(change: number): {
icon: "up" | "down" | "neutral";
color: string;
bgColor: string;
text: string;
} {
if (change > 0) {
return {
icon: "up",
color: "text-emerald-600",
bgColor: "bg-emerald-50",
text: `+${change.toFixed(1)}%`,
};
} else if (change < 0) {
return {
icon: "down",
color: "text-red-600",
bgColor: "bg-red-50",
text: `${change.toFixed(1)}%`,
};
} else {
return {
icon: "neutral",
color: "text-gray-500",
bgColor: "bg-gray-50",
text: "0%",
};
}
}
/**
* 获取竞品地位信息
*/
export function getCompetitorStatus(
ahead: number,
behind: number,
): {
label: string;
color: string;
status: "leading" | "trailing" | "mixed";
} {
if (ahead > 0 && behind === 0) {
return {
label: `领先${ahead}竞品`,
color: "text-emerald-600",
status: "leading",
};
} else if (behind > 0 && ahead === 0) {
return {
label: `落后${behind}竞品`,
color: "text-red-600",
status: "trailing",
};
} else if (ahead > 0 && behind > 0) {
return {
label: `领先${ahead} / 落后${behind}`,
color: "text-yellow-600",
status: "mixed",
};
} else {
return {
label: "暂无竞品数据",
color: "text-gray-500",
status: "mixed",
};
}
}
/**
* 生成行动建议
*/
export function generateActionSuggestions(stats: {
platformScores: PlatformScoreWithCompetitor[];
overallScore: number;
hasQueries: boolean;
}): ActionSuggestion[] {
const suggestions: ActionSuggestion[] = [];
// 找出落后最多的平台
const behindPlatforms = stats.platformScores
.filter((p) => {
const compScore = p.competitor_score ?? p.competitorScore;
const gap = calculateCompetitorGap(p.score, compScore);
return gap.behind;
})
.sort((a, b) => {
const gapA = calculateCompetitorGap(
a.score,
a.competitor_score ?? a.competitorScore,
);
const gapB = calculateCompetitorGap(
b.score,
b.competitor_score ?? b.competitorScore,
);
return (gapB.gap || 0) - (gapA.gap || 0);
});
if (behindPlatforms.length > 0) {
const worst = behindPlatforms[0];
const compScore = worst.competitor_score ?? worst.competitorScore;
const gap = calculateCompetitorGap(worst.score, compScore);
const platformName = worst.platform;
suggestions.push({
id: "competitor-gap",
type: "primary",
title: `您的品牌在${platformName}平台落后竞品${gap.gap}`,
description: "点击查看差距分析,制定提升策略",
icon: "⚠️",
href: `/compare?platform=${worst.platform}`,
priority: 1,
});
}
// 检查是否有危险等级的平台
const dangerPlatforms = stats.platformScores.filter(
(p) => getHealthLevel(p.score) === "danger",
);
if (dangerPlatforms.length > 0) {
const platformName = dangerPlatforms[0].platform;
suggestions.push({
id: "danger-platform",
type: "primary",
title: `${platformName}平台评分危险(${dangerPlatforms[0].score}分)`,
description: "立即查看原因并采取行动",
icon: "🚨",
href: `/dashboard/queries?platform=${dangerPlatforms[0].platform}`,
priority: 0,
});
}
// 如果没有查询词
if (!stats.hasQueries) {
suggestions.push({
id: "add-query",
type: "secondary",
title: "添加查询词以获得更完整的分析",
description: "创建第一个查询词,系统将自动开始收集引用数据",
icon: "💡",
href: "/dashboard/queries",
priority: 10,
});
}
// 如果综合评分低于良好
if (stats.overallScore < 60) {
suggestions.push({
id: "improve-score",
type: "secondary",
title: "品牌综合评分需要提升",
description: "查看高分品牌的优化策略",
icon: "📈",
href: "/compare",
priority: 11,
});
}
// 可选行动
suggestions.push({
id: "set-alert",
type: "optional",
title: "设置竞品超越预警",
description: "当竞品评分超过您时,第一时间收到通知",
icon: "🔔",
href: "/dashboard/settings",
priority: 20,
});
return suggestions.sort((a, b) => a.priority - b.priority);
}
/**
* 获取危险平台列表
*/
export function getDangerPlatforms(
platformScores: PlatformScoreWithCompetitor[],
): PlatformScoreWithCompetitor[] {
return platformScores.filter((p) => getHealthLevel(p.score) === "danger");
}