2025102221-console-migration-script.md 8.6 KB

浏览器控制台快速修复脚本

使用说明:复制下面的脚本,粘贴到浏览器控制台执行


🚀 快速修复脚本

步骤1: 打开浏览器控制台

  1. 访问:http://localhost:4200/admin/project-management
  2. F12 打开开发者工具
  3. 切换到 Console 标签

步骤2: 复制并执行以下脚本

// ================================
// 项目负责人批量更新脚本
// ================================

(async function() {
  console.log('🚀 开始批量更新项目负责人...');
  
  try {
    // 获取Parse实例
    const FmodeParse = (window as any).FmodeParse || await import('fmode-ng/parse').then(m => m.FmodeParse);
    const Parse = FmodeParse.with('nova');
    
    // 获取公司ID
    const company = localStorage.getItem('company');
    if (!company) {
      console.error('❌ 未找到公司ID,请先登录');
      return;
    }
    console.log('✅ 公司ID:', company);
    
    // 查询所有项目
    const projectQuery = new Parse.Query('Project');
    projectQuery.equalTo('company', company);
    projectQuery.notEqualTo('isDeleted', true);
    projectQuery.include(['assignee', 'department', 'department.leader']);
    projectQuery.limit(1000);
    
    const projects = await projectQuery.find();
    console.log(`📊 找到 ${projects.length} 个项目`);
    
    // 统计
    let updated = 0;
    let skipped = 0;
    let failed = 0;
    
    // 遍历每个项目
    for (let i = 0; i < projects.length; i++) {
      const project = projects[i];
      const title = project.get('title') || '未命名项目';
      const existingAssignee = project.get('assignee');
      
      try {
        // 如果已有负责人,跳过
        if (existingAssignee) {
          console.log(`⏭️  [${i+1}/${projects.length}] "${title}" 已有负责人: ${existingAssignee.get('name')}`);
          skipped++;
          continue;
        }
        
        // 检查是否有项目组
        let department = project.get('department');
        
        // 如果没有项目组,查找默认项目组
        if (!department) {
          console.log(`🔍 [${i+1}/${projects.length}] "${title}" 没有项目组,查找默认项目组...`);
          
          const deptQuery = new Parse.Query('Department');
          deptQuery.equalTo('company', company);
          deptQuery.equalTo('type', 'project');
          deptQuery.notEqualTo('isDeleted', true);
          deptQuery.include('leader');
          deptQuery.ascending('createdAt');
          deptQuery.limit(1);
          
          department = await deptQuery.first();
        } else {
          // 如果有项目组,确保加载了leader
          await department.fetch({ include: ['leader'] });
        }
        
        if (!department) {
          console.warn(`⚠️  [${i+1}/${projects.length}] "${title}" 没有可用的项目组`);
          failed++;
          continue;
        }
        
        // 获取组长
        const leader = department.get('leader');
        if (!leader) {
          console.warn(`⚠️  [${i+1}/${projects.length}] "${title}" 的项目组没有组长`);
          failed++;
          continue;
        }
        
        // 更新项目
        project.set('assignee', leader);
        project.set('department', department);
        await project.save();
        
        updated++;
        console.log(`✅ [${i+1}/${projects.length}] "${title}" 已设置负责人: ${leader.get('name')}`);
        
      } catch (error) {
        console.error(`❌ [${i+1}/${projects.length}] 更新 "${title}" 失败:`, error);
        failed++;
      }
    }
    
    // 输出结果
    console.log('');
    console.log('='.repeat(60));
    console.log('🎉 批量更新完成!');
    console.log('='.repeat(60));
    console.log(`📊 总计: ${projects.length} 个项目`);
    console.log(`✅ 成功更新: ${updated} 个`);
    console.log(`⏭️  跳过(已有负责人): ${skipped} 个`);
    console.log(`❌ 失败: ${failed} 个`);
    console.log('='.repeat(60));
    console.log('');
    console.log('💡 请刷新页面查看结果(Ctrl+Shift+R)');
    
  } catch (error) {
    console.error('❌ 执行失败:', error);
  }
})();

步骤3: 等待执行完成

控制台会输出类似信息:

🚀 开始批量更新项目负责人...
✅ 公司ID: cDL6R1hgSi
📊 找到 11 个项目
⏭️  [1/11] "未命名案例组三期项目" 已有负责人: 汪奥
✅ [2/11] "张家界凤凰城三期项目" 已设置负责人: 汪奥
✅ [3/11] "日式10.6" 已设置负责人: 汪奥
...
============================================================
🎉 批量更新完成!
============================================================
📊 总计: 11 个项目
✅ 成功更新: 10 个
⏭️  跳过(已有负责人): 1 个
❌ 失败: 0 个
============================================================
💡 请刷新页面查看结果(Ctrl+Shift+R)

步骤4: 刷新页面

Ctrl+Shift+R 强制刷新页面,查看项目列表中的"负责人"列。

预期结果:所有项目的"负责人"列应显示组长名字(如"汪奥"),而不是"未分配"。


📝 简化版脚本(如果上面的不work)

如果上面的脚本报错,试试这个简化版:

(async function() {
  const Parse = window.FmodeParse.with('nova');
  const company = localStorage.getItem('company');
  
  const query = new Parse.Query('Project');
  query.equalTo('company', company);
  query.notEqualTo('isDeleted', true);
  query.doesNotExist('assignee');
  query.limit(100);
  
  const projects = await query.find();
  console.log('需要更新的项目数:', projects.length);
  
  // 获取第一个项目组
  const deptQuery = new Parse.Query('Department');
  deptQuery.equalTo('company', company);
  deptQuery.include('leader');
  const dept = await deptQuery.first();
  
  if (!dept) {
    console.error('没有找到项目组');
    return;
  }
  
  const leader = dept.get('leader');
  console.log('使用组长:', leader.get('name'));
  
  // 批量更新
  for (const p of projects) {
    p.set('assignee', leader);
    p.set('department', dept);
    await p.save();
    console.log('✅', p.get('title'));
  }
  
  console.log('完成!请刷新页面');
})();

🔍 验证脚本

执行更新后,运行这个脚本验证结果:

(async function() {
  const Parse = window.FmodeParse.with('nova');
  const company = localStorage.getItem('company');
  
  const query = new Parse.Query('Project');
  query.equalTo('company', company);
  query.notEqualTo('isDeleted', true);
  query.include(['assignee', 'department']);
  query.limit(20);
  
  const projects = await query.find();
  
  console.table(projects.map(p => ({
    '项目名称': p.get('title'),
    '负责人': p.get('assignee')?.get('name') || '未分配',
    '项目组': p.get('department')?.get('name') || '无'
  })));
})();

预期输出表格:

┌─────────┬────────────────────────┬──────────┬──────────┐
│ (index) │      项目名称          │  负责人  │  项目组  │
├─────────┼────────────────────────┼──────────┼──────────┤
│    0    │  '未命名案例组三期'     │  '汪奥'  │  '汪奥组'│
│    1    │  '张家界凤凰城三期'     │  '汪奥'  │  '汪奥组'│
│    2    │  '日式10.6'            │  '汪奥'  │  '汪奥组'│
│   ...   │         ...            │   ...    │   ...    │
└─────────┴────────────────────────┴──────────┴──────────┘

⚠️ 故障排查

错误1: FmodeParse is not defined

解决方法

// 先初始化FmodeParse
const { FmodeParse } = await import('fmode-ng/parse');
// 然后继续执行脚本

错误2: company is null

解决方法

// 手动设置公司ID
localStorage.setItem('company', 'cDL6R1hgSi'); // 替换为你的公司ID

错误3: 权限错误

解决方法

  • 确保已登录管理员账号
  • 检查Parse ACL权限配置

🎯 执行后检查

  1. 控制台日志:确认所有项目都成功更新
  2. 项目列表:刷新页面,检查"负责人"列
  3. Parse Dashboard:查看Project表的assignee字段
  4. 项目详情页:点击任意项目,查看负责人信息

现在就执行脚本,一键修复所有项目的负责人! 🚀