geo/frontend/lib/next-action.ts

261 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 下一步行动建议生成逻辑
*/
import type {
ActionContext,
ActionRule,
NextAction,
} from "@/types/next-action";
// 行动定义类型(与 ActionRule 中的 action 类型一致)
type ActionDefinition = Omit<NextAction, "id" | "priority" | "href">;
// 生成唯一ID
function generateActionId(): string {
return `action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// 创建行动项
function createAction(
base: ActionDefinition,
priority: NextAction["priority"],
): NextAction {
return {
...base,
href: base.actionUrl, // href 与 actionUrl 保持一致
id: generateActionId(),
priority,
};
}
// 默认行动规则 - 新用户无数据
const newUserRules: ActionRule[] = [
{
condition: (ctx) => !ctx.hasBrands || ctx.brandCount === 0,
primaryAction: {
title: "创建第一个品牌",
description:
"开始您的品牌分析之旅创建第一个品牌后即可获得详细的AI认知度评分。",
actionText: "创建品牌",
actionUrl: "/brands",
icon: "🎯",
},
secondaryAction: null,
optionalAction: {
title: "了解GEO",
description: "了解GEO平台如何帮助您监控品牌在AI平台的表现。",
actionText: "了解更多",
actionUrl: "/dashboard/reports",
icon: "📚",
},
},
];
// 有数据但评分低的规则
const lowScoreRules: ActionRule[] = [
{
condition: (ctx) =>
ctx.hasData &&
ctx.overallScore > 0 &&
ctx.overallScore < 60 &&
ctx.competitorCount > 0,
primaryAction: {
title: "查看差距分析",
description: "您的品牌在多个平台落后于竞品,点击查看详细差距分析。",
actionText: "查看差距分析",
actionUrl: "/compare",
icon: "📊",
},
secondaryAction: {
title: "添加更多竞品",
description: "添加更多竞品可以获得更完整的对比分析。",
actionText: "添加竞品",
actionUrl: "/brands",
icon: "👥",
},
optionalAction: {
title: "设置预警",
description: "设置竞品超越预警,第一时间获知竞争对手的动态变化。",
actionText: "立即设置",
actionUrl: "/dashboard/settings",
icon: "🔔",
},
},
];
// 评分高但无增长的规则
const highScoreNoGrowthRules: ActionRule[] = [
{
condition: (ctx) =>
ctx.hasData && ctx.overallScore >= 60 && ctx.scoreChange <= 0,
primaryAction: {
title: "设置涨粉预警",
description: "您的品牌评分较高但增长停滞,设置预警监控潜在风险。",
actionText: "设置预警",
actionUrl: "/dashboard/settings",
icon: "📈",
},
secondaryAction: {
title: "对比历史趋势",
description: "查看品牌评分的历史变化趋势,分析增长机会。",
actionText: "查看趋势",
actionUrl: "/dashboard/reports",
icon: "📉",
},
optionalAction: {
title: "导出报告",
description: "导出详细的分析报告,用于内部汇报或战略制定。",
actionText: "导出报告",
actionUrl: "/dashboard/reports",
icon: "📄",
},
},
];
// 竞品威胁规则
const competitorThreatRules: ActionRule[] = [
{
condition: (ctx) => ctx.competitorCount > 0 && ctx.hasData,
primaryAction: {
title: "查看差距分析",
description:
"竞品正在逼近或超越您的品牌,点击查看详细分析并制定应对策略。",
actionText: "查看差距分析",
actionUrl: "/compare",
icon: "⚠️",
},
secondaryAction: {
title: "设置预警",
description: "设置竞品超越预警,第一时间获知竞争对手的动态变化。",
actionText: "设置预警",
actionUrl: "/dashboard/settings",
icon: "🔔",
},
optionalAction: {
title: "添加查询词",
description: "添加更多查询词以获得更完整的品牌分析。",
actionText: "添加查询词",
actionUrl: "/dashboard/queries",
icon: "🔍",
},
},
];
// 正常数据状态规则
const normalDataRules: ActionRule[] = [
{
condition: (ctx) => ctx.hasData && ctx.hasQueryHistory,
primaryAction: {
title: "继续优化",
description: "您的品牌表现良好,继续保持并关注最新动态。",
actionText: "查看详情",
actionUrl: "/dashboard",
icon: "✨",
},
secondaryAction: {
title: "对比分析",
description: "与竞品进行对比分析,发现更多优化机会。",
actionText: "查看对比",
actionUrl: "/compare",
icon: "📊",
},
optionalAction: {
title: "导出报告",
description: "导出分析报告用于内部汇报。",
actionText: "导出报告",
actionUrl: "/dashboard/reports",
icon: "📄",
},
},
];
// 所有规则按优先级排序
const allRules: ActionRule[] = [
...newUserRules,
...lowScoreRules,
...highScoreNoGrowthRules,
...competitorThreatRules,
...normalDataRules,
];
/**
* 根据上下文生成行动建议
*/
export function generateNextActions(context: ActionContext): NextAction[] {
const actions: NextAction[] = [];
// 遍历规则,找到第一个匹配的
for (const rule of allRules) {
if (rule.condition(context)) {
// 添加主要行动
actions.push(createAction(rule.primaryAction, "primary"));
// 添加次要行动
if (rule.secondaryAction) {
actions.push(createAction(rule.secondaryAction, "secondary"));
}
// 添加可选行动
if (rule.optionalAction) {
actions.push(createAction(rule.optionalAction, "optional"));
}
break; // 找到第一个匹配规则后停止
}
}
// 如果没有任何规则匹配,返回默认行动
if (actions.length === 0) {
actions.push(
createAction(
{
title: "开始分析",
description: "创建您的第一个品牌开始GEO品牌健康分析。",
actionText: "立即创建",
actionUrl: "/brands",
icon: "🚀",
},
"primary",
),
);
actions.push(
createAction(
{
title: "查看教程",
description: "了解如何使用GEO平台监控您的品牌。",
actionText: "查看教程",
actionUrl: "/dashboard/reports",
icon: "📚",
},
"secondary",
),
);
}
return actions;
}
/**
* 获取行动建议的缓存key
*/
export function getCacheKey(context: ActionContext): string {
return `next_actions_${context.currentPage}_${context.brandId || "global"}_${context.overallScore}`;
}
/**
* 判断是否可以使用缓存
*/
export function canUseCache(
cachedActions: NextAction[] | undefined,
_context: ActionContext,
): boolean {
if (!cachedActions || cachedActions.length === 0) {
return false;
}
// 简单缓存策略1分钟内不需要重新生成
// 这里可以通过localStorage存储时间戳来更精确控制
return true;
}