Skip to content

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.blueprintproject.meta.strategy_meta.blueprint

结果:前端无法找到后端已保存的蓝图数据,错误地认为项目没有30天计划。

解决方案

修复策略

采用兼容性方案,同时支持两种路径:

  1. project.meta.strategy - 标准路径(后端使用)
  2. 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": { ... }
  }
}

测试验证

测试场景

  1. 标准路径项目

    • 蓝图存储在 meta.strategy.blueprint
    • ✅ 应能正确识别并显示30天计划
  2. 历史遗留路径项目

    • 蓝图存储在 meta.strategy_meta.blueprint
    • ✅ 应能正确识别并显示30天计划
  3. 进度数据

    • 进度存储在 meta.strategy.strategy_progress
    • ✅ 应能正确显示完成进度
  4. 诊断数据

    • 诊断存储在 project.diagnosismeta.strategy.onboarding.answers
    • ✅ 应能正确读取

验证步骤

  1. 打开项目控制台页面
  2. 检查30天计划概览卡片
  3. 验证显示状态:
    • ✅ 有蓝图时,显示"本周任务"和进度
    • ✅ 无蓝图时,显示"还没有执行计划"引导
  4. 点击"查看完整计划"
  5. 验证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 中查看:

  1. 打开 Vue DevTools
  2. 选择 Components 标签
  3. 找到 StrategyOverview 组件
  4. 查看 props 中的 project 数据
  5. 展开 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;
}

影响范围

修改的功能模块

  1. ✅ 项目控制台 - 30天计划概览显示
  2. ✅ 30天计划详情页 - 数据加载
  3. ✅ 项目进度追踪 - 完成状态显示
  4. ✅ 诊断数据读取 - 多路径兼容

不影响的功能

  • ❌ 蓝图生成逻辑(后端)
  • ❌ 数据保存逻辑(后端)
  • ❌ 其他项目功能

相关文件

  • frontend/src/stores/project.js - 项目状态管理
  • frontend/src/components/project/StrategyOverview.vue - 30天计划概览组件
  • backend/src/services/strategyService.js - 策略服务(数据存储)

版本历史

日期版本描述
2025-12-13v1.0初始修复,添加路径兼容性

修复日期:2025-12-13
影响范围:前端数据读取逻辑
优先级:高(影响核心功能显示)
状态:✅ 已完成

© 2024-2025 趣美丽 QuMeiLi · Powered by 刻流星引擎 KeLiuXing