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

139 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 团队功能开发笔记
**完成日期**: 2026-03-19
**任务**: 修复团队功能页面空白问题
---
## 一、问题描述
点击"团队"导航后,页面显示空白,控制台报错 `teams.map is not a function`
## 二、根因分析
### 2.1 数据格式冲突
Zustand 的 `persist` 中间件存储格式为:
```json
{
"state": { "teams": [...], "activeTeam": ... },
"version": 0
}
```
`loadTeams` 函数期望的是直接的数组格式 `Team[]`
### 2.2 类型安全问题
TeamList 组件中的 `availableAgents` 变量使用了条件表达式,返回类型不一致:
- `clones``Clone[]` 类型
- `agents.map(...)` 返回的是 `{ id, name, role }[]` 类型
TypeScript 无法推断统一类型,运行时可能导致错误。
## 三、解决方案
### 3.1 修复 loadTeams 函数
```typescript
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 类型
```typescript
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 添加防御性检查
```typescript
// 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-500``orange-500`
- 按钮背景: `bg-blue-500``bg-orange-500`
- Filter tabs: `bg-blue-100``bg-orange-100`
- 选中边框: `border-blue-500``border-orange-500`
- Focus ring: `ring-blue-500``ring-orange-500`
- 保留执行状态(`executing`/`running`)的蓝色作为状态指示色
### 6.3 相关文件
| 文件 | 修改内容 |
|------|----------|
| `components/Sidebar.tsx` | 移除 SwarmDashboard 渲染和 import |
| `components/SwarmDashboard.tsx` | 配色从蓝色改为橙色 |
### 6.4 设计原则
1. **单一渲染原则**: 每个视图组件只在唯一位置渲染,避免多处同时显示
2. **颜色一致性**: 交互元素使用系统主色调(橙色),状态指示可保留语义色(蓝色=执行中,绿色=完成,红色=失败)