30天计划蓝图路径兼容性修复
问题描述
用户反馈:
- 该项目已经生成过30天计划
- 30天计划入口可以看到
- 但是提示"还没有执行计划",并给出开始定制账号入口
问题根因
数据存储路径不一致
后端存储路径(backend/src/services/strategyService.js):
javascript
// getStrategyMeta 返回 project.meta.strategy
function getStrategyMeta(project) {
const meta = ensureObject(project.meta);
return ensureObject(meta.strategy);
}
// 所以蓝图保存在:project.meta.strategy.blueprint前端检查路径(修复前的 frontend/src/stores/project.js):
javascript
function hasBlueprint(project = currentProject.value) {
// 错误:检查的是 strategy_meta 而不是 strategy
return !!project?.meta?.strategy_meta?.blueprint?.calendar?.length
}路径对比
| 位置 | 预期路径 | 实际路径 |
|---|---|---|
| 后端存储 | project.meta.strategy.blueprint | ✅ 正确 |
| 前端检查 | project.meta.strategy.blueprint | ❌ project.meta.strategy_meta.blueprint |
结果:前端无法找到后端已保存的蓝图数据,错误地认为项目没有30天计划。
解决方案
修复策略
采用兼容性方案,同时支持两种路径:
project.meta.strategy- 标准路径(后端使用)project.meta.strategy_meta- 可能的历史遗留路径
这样可以:
- ✅ 修复当前问题
- ✅ 兼容可能存在的历史数据
- ✅ 不破坏现有功能
修改的文件
1. frontend/src/stores/project.js
修改 hasBlueprint 函数
修改前:
javascript
function hasBlueprint(project = currentProject.value) {
return !!project?.meta?.strategy_meta?.blueprint?.calendar?.length
}修改后:
javascript
function hasBlueprint(project = currentProject.value) {
// 兼容两种存储路径:strategy 和 strategy_meta
const strategyBlueprint = project?.meta?.strategy?.blueprint
const strategyMetaBlueprint = project?.meta?.strategy_meta?.blueprint
return !!(
strategyBlueprint?.calendar?.length ||
strategyMetaBlueprint?.calendar?.length
)
}修改 getBlueprint 函数
修改前:
javascript
function getBlueprint(project = currentProject.value) {
return project?.meta?.strategy_meta?.blueprint || null
}修改后:
javascript
function getBlueprint(project = currentProject.value) {
// 兼容两种存储路径:优先使用 strategy,回退到 strategy_meta
return project?.meta?.strategy?.blueprint ||
project?.meta?.strategy_meta?.blueprint ||
null
}修改 getUnifiedDiagnosis 函数
修改前:
javascript
function getUnifiedDiagnosis(project = currentProject.value) {
if (!project) return null
// 优先从主表读取
if (project.diagnosis && Object.keys(project.diagnosis).length > 0) {
return project.diagnosis
}
// 回退到 meta.strategy_meta.onboarding.answers
const strategyMeta = project.meta?.strategy_meta
if (strategyMeta?.onboarding?.answers && Object.keys(strategyMeta.onboarding.answers).length > 0) {
return strategyMeta.onboarding.answers
}
return null
}修改后:
javascript
function getUnifiedDiagnosis(project = currentProject.value) {
if (!project) return null
// 优先从主表读取
if (project.diagnosis && Object.keys(project.diagnosis).length > 0) {
return project.diagnosis
}
// 尝试从 meta.strategy.onboarding.answers 读取
const strategyOnboarding = project.meta?.strategy?.onboarding?.answers
if (strategyOnboarding && Object.keys(strategyOnboarding).length > 0) {
return strategyOnboarding
}
// 回退到 meta.strategy_meta.onboarding.answers
const strategyMeta = project.meta?.strategy_meta
if (strategyMeta?.onboarding?.answers && Object.keys(strategyMeta.onboarding.answers).length > 0) {
return strategyMeta.onboarding.answers
}
return null
}修改 getCurrentWeekTasks 函数
修改前:
javascript
function getCurrentWeekTasks(project = currentProject.value) {
const blueprint = getBlueprint(project)
if (!blueprint?.calendar?.length) return []
// 获取进度数据
const progress = project?.meta?.strategy_progress || {}
const completedIds = new Set(progress.completed_task_ids || [])
// ...
}修改后:
javascript
function getCurrentWeekTasks(project = currentProject.value) {
const blueprint = getBlueprint(project)
if (!blueprint?.calendar?.length) return []
// 获取进度数据(兼容多种存储位置)
const strategyProgress = project?.meta?.strategy?.strategy_progress
const metaProgress = project?.meta?.strategy_progress
const progress = strategyProgress || metaProgress || {}
const completedIds = new Set(progress.completed_task_ids || [])
// ...
}2. frontend/src/components/project/StrategyOverview.vue
修改 completedCount 计算属性
修改前:
javascript
const completedCount = computed(() => {
const progress = props.project?.meta?.strategy_progress || {}
return (progress.completed_task_ids || []).length
})修改后:
javascript
const completedCount = computed(() => {
// 兼容多种存储位置
const strategyProgress = props.project?.meta?.strategy?.strategy_progress
const metaProgress = props.project?.meta?.strategy_progress
const progress = strategyProgress || metaProgress || {}
return (progress.completed_task_ids || []).length
})数据结构说明
标准数据结构(后端使用)
json
{
"id": "project-123",
"meta": {
"strategy": {
"onboarding": {
"answers": { ... },
"updated_at": "2025-12-13T10:00:00.000Z"
},
"account_profile": {
"nicknames": [...],
"bios": [...],
"generated_at": "2025-12-13T10:05:00.000Z"
},
"blueprint": {
"id": "blueprint-abc",
"version": "v1",
"directions": [...],
"selected_direction": "direction-1",
"topic_pool": [...],
"calendar": [
{
"day": 1,
"tasks": [...]
}
],
"generated_at": "2025-12-13T10:10:00.000Z"
},
"strategy_progress": {
"completed_task_ids": ["task-1", "task-2"],
"last_updated": "2025-12-13T12:00:00.000Z"
}
}
}
}可能的历史遗留结构
json
{
"id": "project-456",
"meta": {
"strategy_meta": {
"onboarding": { ... },
"blueprint": { ... }
},
"strategy_progress": { ... }
}
}测试验证
测试场景
标准路径项目
- 蓝图存储在
meta.strategy.blueprint - ✅ 应能正确识别并显示30天计划
- 蓝图存储在
历史遗留路径项目
- 蓝图存储在
meta.strategy_meta.blueprint - ✅ 应能正确识别并显示30天计划
- 蓝图存储在
进度数据
- 进度存储在
meta.strategy.strategy_progress - ✅ 应能正确显示完成进度
- 进度存储在
诊断数据
- 诊断存储在
project.diagnosis或meta.strategy.onboarding.answers - ✅ 应能正确读取
- 诊断存储在
验证步骤
- 打开项目控制台页面
- 检查30天计划概览卡片
- 验证显示状态:
- ✅ 有蓝图时,显示"本周任务"和进度
- ✅ 无蓝图时,显示"还没有执行计划"引导
- 点击"查看完整计划"
- 验证30天计划详情页正常显示
调试方法
如果仍然遇到问题,可以在浏览器控制台执行以下命令查看数据结构:
javascript
// 1. 获取当前项目数据
const project = window.__VUE_DEVTOOLS_GLOBAL_HOOK__.stores.get('project').currentProject
// 2. 检查蓝图存储位置
console.log('Strategy Blueprint:', project?.meta?.strategy?.blueprint)
console.log('Strategy Meta Blueprint:', project?.meta?.strategy_meta?.blueprint)
// 3. 检查进度数据
console.log('Strategy Progress:', project?.meta?.strategy?.strategy_progress)
console.log('Meta Progress:', project?.meta?.strategy_progress)
// 4. 检查日历数据
console.log('Calendar Days:',
project?.meta?.strategy?.blueprint?.calendar?.length ||
project?.meta?.strategy_meta?.blueprint?.calendar?.length ||
0
)或者在 Vue DevTools 中查看:
- 打开 Vue DevTools
- 选择 Components 标签
- 找到
StrategyOverview组件 - 查看 props 中的
project数据 - 展开
meta对象,检查数据结构
后续优化建议
1. 统一数据结构
建议在后端进行一次数据迁移,将所有历史项目的 strategy_meta 数据迁移到 strategy:
javascript
// 迁移脚本示例
async function migrateStrategyData() {
const projects = await Project.findAll({
where: {
'meta.strategy_meta': { [Op.ne]: null }
}
});
for (const project of projects) {
if (project.meta?.strategy_meta && !project.meta?.strategy) {
project.meta.strategy = project.meta.strategy_meta;
delete project.meta.strategy_meta;
await project.save();
console.log(`Migrated project ${project.id}`);
}
}
}2. 添加数据验证
在项目加载时验证数据结构完整性:
javascript
function validateProjectData(project) {
const issues = [];
if (!project.meta?.strategy?.blueprint && project.meta?.strategy_meta?.blueprint) {
issues.push('Blueprint in legacy path (strategy_meta)');
}
if (issues.length > 0) {
console.warn(`Project ${project.id} data validation:`, issues);
}
return issues;
}3. 添加监控
记录蓝图数据读取来源,便于追踪:
javascript
function getBlueprint(project) {
const strategyBlueprint = project?.meta?.strategy?.blueprint;
const strategyMetaBlueprint = project?.meta?.strategy_meta?.blueprint;
if (strategyBlueprint) {
console.debug('Blueprint loaded from strategy path');
return strategyBlueprint;
}
if (strategyMetaBlueprint) {
console.warn('Blueprint loaded from legacy strategy_meta path');
return strategyMetaBlueprint;
}
return null;
}影响范围
修改的功能模块
- ✅ 项目控制台 - 30天计划概览显示
- ✅ 30天计划详情页 - 数据加载
- ✅ 项目进度追踪 - 完成状态显示
- ✅ 诊断数据读取 - 多路径兼容
不影响的功能
- ❌ 蓝图生成逻辑(后端)
- ❌ 数据保存逻辑(后端)
- ❌ 其他项目功能
相关文件
frontend/src/stores/project.js- 项目状态管理frontend/src/components/project/StrategyOverview.vue- 30天计划概览组件backend/src/services/strategyService.js- 策略服务(数据存储)
版本历史
| 日期 | 版本 | 描述 |
|---|---|---|
| 2025-12-13 | v1.0 | 初始修复,添加路径兼容性 |
修复日期:2025-12-13
影响范围:前端数据读取逻辑
优先级:高(影响核心功能显示)
状态:✅ 已完成