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

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

---

## 🚀 快速修复脚本

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

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

---

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

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

(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）

如果上面的脚本报错，试试这个简化版：

```javascript
(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('完成！请刷新页面');
})();
```

---

## 🔍 验证脚本

执行更新后，运行这个脚本验证结果：

```javascript
(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`

**解决方法**：
```javascript
// 先初始化FmodeParse
const { FmodeParse } = await import('fmode-ng/parse');
// 然后继续执行脚本
```

### 错误2: `company is null`

**解决方法**：
```javascript
// 手动设置公司ID
localStorage.setItem('company', 'cDL6R1hgSi'); // 替换为你的公司ID
```

### 错误3: 权限错误

**解决方法**：
- 确保已登录管理员账号
- 检查Parse ACL权限配置

---

## 🎯 执行后检查

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

---

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


