Files
zclaw_openfang/docs/knowledge-base/team-feature-notes.md
iven 6f72442531 docs(guide): rewrite CLAUDE.md with ZCLAW-first perspective
Major changes:
- Shift from "OpenFang desktop client" to "independent AI Agent desktop app"
- Add decision principle: "Is this useful for ZCLAW? Does it affect ZCLAW?"
- Simplify project structure and tech stack sections
- Replace OpenClaw vs OpenFang comparison with unified backend approach
- Consolidate troubleshooting from scattered sections into organized FAQ
- Update Hands system documentation with 8 capabilities and status
- Stream
2026-03-20 19:30:09 +08:00

3.9 KiB
Raw Blame History

团队功能开发笔记

完成日期: 2026-03-19 任务: 修复团队功能页面空白问题


一、问题描述

点击"团队"导航后,页面显示空白,控制台报错 teams.map is not a function

二、根因分析

2.1 数据格式冲突

Zustand 的 persist 中间件存储格式为:

{
  "state": { "teams": [...], "activeTeam": ... },
  "version": 0
}

loadTeams 函数期望的是直接的数组格式 Team[]

2.2 类型安全问题

TeamList 组件中的 availableAgents 变量使用了条件表达式,返回类型不一致:

  • clonesClone[] 类型
  • agents.map(...) 返回的是 { id, name, role }[] 类型

TypeScript 无法推断统一类型,运行时可能导致错误。

三、解决方案

3.1 修复 loadTeams 函数

loadTeams: async () => {
  set({ isLoading: true, error: null });
  try {
    const stored = localStorage.getItem('zclaw-teams');
    let teams: Team[] = [];

    if (stored) {
      const parsed = JSON.parse(stored);
      // 处理 persist 中间件格式
      if (parsed?.state?.teams && Array.isArray(parsed.state.teams)) {
        teams = parsed.state.teams;
      } else if (Array.isArray(parsed)) {
        teams = parsed;
      }
    }

    set({ teams, isLoading: false });
  } catch (error) {
    set({ teams: [], isLoading: false });
  }
},

3.2 修复 availableAgents 类型

const availableAgents: Array<{ id: string; name: string; role?: string }> =
  (clones && clones.length > 0)
    ? clones.map(c => ({ id: c.id, name: c.name, role: c.role }))
    : (agents && agents.length > 0)
      ? agents.map(a => ({ id: a.id, name: a.name, role: '默认助手' }))
      : [];

3.3 添加防御性检查

// TeamList.tsx
{!Array.isArray(teams) || teams.length === 0 ? (
  <EmptyState ... />
) : (
  teams.map(...)
)}

四、相关文件

文件 修改内容
store/teamStore.ts loadTeams 函数处理 persist 格式
components/TeamList.tsx 类型修复、防御性检查、中文化
components/ui/EmptyState.tsx CSS 修复 (flex-1 → h-full)
App.tsx motion.main 添加 flex flex-col

五、经验教训

  1. persist 中间件存储格式: Zustand persist 存储的是 { state, version } 结构,不是直接的状态值
  2. 条件表达式类型一致性: 三元表达式的两个分支必须返回相同类型
  3. 防御性编程: 对从 store 获取的数据进行 Array.isArray 检查

文档创建: 2026-03-19


六、协作功能修复 (2026-03-19)

6.1 问题描述

  1. UI 颜色不一致: SwarmDashboard 使用蓝色(blue-500)作为主色调,与系统的橙色/灰色风格不匹配
  2. 内容重复渲染: 左侧边栏和主内容区同时渲染 SwarmDashboard导致内容重复

6.2 解决方案

问题 1: 内容重复

  • Sidebar.tsx 移除 {activeTab === 'swarm' && <SwarmDashboard />} 渲染
  • 只保留 App.tsx 中的主内容区渲染
  • 移除未使用的 import { SwarmDashboard } 语句

问题 2: 颜色一致性 修改 SwarmDashboard.tsx 中的配色:

  • 主色调: blue-500orange-500
  • 按钮背景: bg-blue-500bg-orange-500
  • Filter tabs: bg-blue-100bg-orange-100
  • 选中边框: border-blue-500border-orange-500
  • Focus ring: ring-blue-500ring-orange-500
  • 保留执行状态(executing/running)的蓝色作为状态指示色

6.3 相关文件

文件 修改内容
components/Sidebar.tsx 移除 SwarmDashboard 渲染和 import
components/SwarmDashboard.tsx 配色从蓝色改为橙色

6.4 设计原则

  1. 单一渲染原则: 每个视图组件只在唯一位置渲染,避免多处同时显示
  2. 颜色一致性: 交互元素使用系统主色调(橙色),状态指示可保留语义色(蓝色=执行中,绿色=完成,红色=失败)