# Layout结构优化实施计划

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 将UmiJS layout从mix模式优化为side模式，实现左右分栏布局，白色主题风格，侧边栏可折叠。

**Architecture:**
1. 修改UmiJS layout配置，从'mix'改为'side'模式
2. 自定义Header渲染组件，保持用户信息功能
3. 自定义Logo渲染组件，实现展开/折叠智能显示
4. 更新token配置实现白色主题

**Tech Stack:** UmiJS Max, Ant Design Pro Layout, React, TypeScript

---

## 文件结构

**修改的文件：**
- `src/common/libs/umi/layoutConfig.tsx` - 核心layout配置

**新建的文件：**
- `src/common/components/layout/CustomHeader.tsx` - 自定义Header组件
- `src/common/components/layout/CustomLogo.tsx` - 自定义Logo组件
- `src/common/components/layout/index.ts` - 导出新组件

---

### Task 1: 备份现有layout配置

**Files:**
- Copy: `src/common/libs/umi/layoutConfig.tsx` → `src/common/libs/umi/layoutConfig.tsx.backup`

- [ ] **Step 1: 创建备份文件**

```bash
cp src/common/libs/umi/layoutConfig.tsx src/common/libs/umi/layoutConfig.tsx.backup
```

- [ ] **Step 2: 验证备份成功**

```bash
ls -lh src/common/libs/umi/layoutConfig.tsx.backup
```

Expected: 输出文件大小和日期

- [ ] **Step 3: 提交备份**

```bash
git add src/common/libs/umi/layoutConfig.tsx.backup
git commit -m "chore: backup layoutConfig before refactoring"
```

---

### Task 2: 修改layout基础配置

**Files:**
- Modify: `src/common/libs/umi/layoutConfig.tsx:31-78`

- [ ] **Step 1: 修改layout模式和基础配置**

将 `layout: 'mix'` 改为 `layout: 'side'`，移除logo配置（稍后自定义）：

```typescript
export const LayoutConfig: RuntimeConfig['layout'] = () => {
  const { snap } = useMyState();

  return {
    title: snap.session.campus?.name ?? '物业管理系统',
    logo: false, // 禁用默认logo，使用自定义
    layout: 'side', // 从 'mix' 改为 'side'
    colorPrimary: '#1890ff',
    siderWidth: 220,
    pure: history.location.pathname === '/login',
    avatarProps: {
      render: () => <AvatarProps user={snap.session.user} />,
    },
    collapsedButtonRender: false,
    // 保持其他配置不变...
  };
};
```

- [ ] **Step 2: 运行应用查看变化**

```bash
npm run dev
```

Expected: 应用启动，layout已切换为side模式

- [ ] **Step 3: 提交配置修改**

```bash
git add src/common/libs/umi/layoutConfig.tsx
git commit -m "refactor: change layout mode from mix to side"
```

---

### Task 3: 更新主题token为白色主题

**Files:**
- Modify: `src/common/libs/umi/layoutConfig.tsx:50-61`

- [ ] **Step 1: 替换token配置**

将现有的深色主题token替换为白色主题：

```typescript
export const LayoutConfig: RuntimeConfig['layout'] = () => {
  const { snap } = useMyState();

  return {
    // ... 前面的配置保持不变

    token: {
      bgLayout: '#f5f5f5', // 浅灰布局背景
      header: {
        colorBgHeader: '#ffffff', // 白色header背景
        colorHeaderTitle: '#262626', // 深色标题文字
        colorTextRightActionsItem: '#595959', // 深色操作文字
        heightLayoutHeader: 64, // Header高度64px
      },
      sider: {
        colorMenuBackground: '#ffffff', // 白色菜单背景
        colorMenuText: '#595959', // 深色菜单文字
        colorMenuTextSelected: '#1890ff', // 激活菜单文字蓝色
        colorMenuItemBgSelected: '#e6f7ff', // 激活菜单背景浅蓝
        colorMenuDivider: '#f0f0f0', // 分割线颜色
      },
    },

    // ... 后面的配置保持不变
  };
};
```

- [ ] **Step 2: 检查样式变化**

在浏览器中查看header和侧边栏背景是否已变为白色

Expected: Header和侧边栏背景为白色

- [ ] **Step 3: 提交token配置**

```bash
git add src/common/libs/umi/layoutConfig.tsx
git commit -m "style: update theme tokens to white color scheme"
```

---

### Task 4: 创建CustomLogo组件

**Files:**
- Create: `src/common/components/layout/CustomLogo.tsx`

- [ ] **Step 1: 创建CustomLogo组件文件**

```typescript
import React from 'react';
import { MyIcons, MyIconsType } from '@/common';

interface CustomLogoProps {
  collapsed: boolean;
}

export const CustomLogo: React.FC<CustomLogoProps> = ({ collapsed }) => {
  return (
    <div className="custom-logo">
      <div className="logo-icon">
        <MyIcons.HomeOutlined style={{ fontSize: '32px', color: '#1890ff' }} />
      </div>
      {!collapsed && (
        <div className="logo-text">
          {collapsed ? '' : '物业管理系统'}
        </div>
      )}
    </div>
  );
};
```

- [ ] **Step 2: 添加组件样式**

在文件末尾添加样式：

```typescript
export const CustomLogo: React.FC<CustomLogoProps> = ({ collapsed }) => {
  // ... 组件代码保持不变
};

// 添加样式定义
export const customLogoStyles = `
  .custom-logo {
    display: flex;
    align-items: center;
    height: 64px;
    padding: 0 16px;
    border-bottom: 1px solid #f0f0f0;
    transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1.000);
  }

  .custom-logo .logo-icon {
    font-size: 32px;
    min-width: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .custom-logo .logo-text {
    margin-left: 12px;
    font-size: 16px;
    font-weight: 600;
    color: #262626;
    white-space: nowrap;
    opacity: 1;
    transition: opacity 0.2s;
  }

  /* 折叠状态下的样式调整 */
  .ant-layout-sider-collapsed .custom-logo {
    padding: 0;
    justify-content: center;
  }

  .ant-layout-sider-collapsed .custom-logo .logo-text {
    display: none;
  }
`;
```

- [ ] **Step 3: 提交CustomLogo组件**

```bash
git add src/common/components/layout/CustomLogo.tsx
git commit -m "feat: add CustomLogo component with collapse support"
```

---

### Task 5: 创建CustomHeader组件

**Files:**
- Create: `src/common/components/layout/CustomHeader.tsx`

- [ ] **Step 1: 创建CustomHeader组件文件**

```typescript
import React from 'react';
import { Layout, Dropdown, Avatar, Space } from 'antd';
import type { MenuProps } from 'antd';
import { AvatarProps } from './AvatarProps';
import { useMyState } from '@/common';

const { Header } = Layout;

interface CustomHeaderProps {
  collapsed?: boolean;
  toggle?: () => void;
}

export const CustomHeader: React.FC<CustomHeaderProps> = ({ collapsed, toggle }) => {
  const { snap } = useMyState();

  const menuItems: MenuProps['items'] = [
    {
      key: 'profile',
      label: '个人资料',
      icon: <span>👤</span>,
    },
    {
      key: 'password',
      label: '修改密码',
      icon: <span>🔒</span>,
    },
    {
      type: 'divider',
    },
    {
      key: 'logout',
      label: '退出登录',
      icon: <span>🚪</span>,
      danger: true,
      onClick: () => {
        // 添加退出登录逻辑
        localStorage.removeItem('token');
        window.location.href = '/login';
      },
    },
  ];

  return (
    <Header className="custom-header">
      {/* 左侧区域 */}
      <div className="header-left">
        {/* 可以添加面包屑导航或其他内容 */}
      </div>

      {/* 右侧用户信息区域 */}
      <div className="header-right">
        <Dropdown menu={{ items: menuItems }} placement="bottomRight">
          <div style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}>
            <AvatarProps user={snap.session.user} />
          </div>
        </Dropdown>
      </div>
    </Header>
  );
};
```

- [ ] **Step 2: 添加Header样式**

在文件末尾添加样式定义：

```typescript
export const CustomHeader: React.FC<CustomHeaderProps> = ({ collapsed, toggle }) => {
  // ... 组件代码保持不变
};

// 添加样式定义
export const customHeaderStyles = `
  .custom-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 24px;
    background: #ffffff !important;
    border-bottom: 1px solid #f0f0f0;
    line-height: 64px;
  }

  .custom-header .header-left {
    flex: 1;
  }

  .custom-header .header-right {
    display: flex;
    align-items: center;
    gap: 16px;
  }

  .custom-header .header-right > div {
    display: flex;
    align-items: center;
    transition: opacity 0.2s;
  }

  .custom-header .header-right > div:hover {
    opacity: 0.8;
  }
`;
```

- [ ] **Step 3: 提交CustomHeader组件**

```bash
git add src/common/components/layout/CustomHeader.tsx
git commit -m "feat: add CustomHeader component with user dropdown"
```

---

### Task 6: 创建组件导出索引

**Files:**
- Create: `src/common/components/layout/index.ts`

- [ ] **Step 1: 创建index导出文件**

```typescript
export { CustomLogo } from './CustomLogo';
export { CustomHeader } from './CustomHeader';
export { default as AvatarProps } from './AvatarProps';
```

- [ ] **Step 2: 验证导出正确**

```bash
npm run build
```

Expected: 构建成功，无TypeScript错误

- [ ] **Step 3: 提交导出文件**

```bash
git add src/common/components/layout/index.ts
git commit -m "chore: add layout components export index"
```

---

### Task 7: 在layoutConfig中集成自定义组件

**Files:**
- Modify: `src/common/libs/umi/layoutConfig.tsx:1-80`

- [ ] **Step 1: 导入自定义组件**

在文件顶部添加导入：

```typescript
// import Logo from '@/assets/bitcoin.webp';
import { MyIcons, MyIconsType, PermissionsType, useMyState } from '@/common';
import { Link, RuntimeConfig, history } from '@umijs/max';
import AvatarProps from '../../components/layout/AvatarProps';
import { CustomHeader, CustomLogo } from '@/common/components/layout'; // 新增
```

- [ ] **Step 2: 添加自定义渲染函数**

在LayoutConfig函数返回对象中添加headerRender和logoRenderer：

```typescript
export const LayoutConfig: RuntimeConfig['layout'] = () => {
  const { snap } = useMyState();

  return {
    title: snap.session.campus?.name ?? '物业管理系统',
    logo: false,
    layout: 'side',
    colorPrimary: '#1890ff',
    siderWidth: 220,
    pure: history.location.pathname === '/login',

    // 新增：自定义Header渲染
    headerRender: () => {
      return <CustomHeader />;
    },

    // 新增：自定义Logo渲染
    logoRenderer: (collapsed: boolean) => {
      return <CustomLogo collapsed={collapsed} />;
    },

    avatarProps: {
      render: () => <AvatarProps user={snap.session.user} />,
    },
    collapsedButtonRender: false,

    token: {
      bgLayout: '#f5f5f5',
      header: {
        colorBgHeader: '#ffffff',
        colorHeaderTitle: '#262626',
        colorTextRightActionsItem: '#595959',
        heightLayoutHeader: 64,
      },
      sider: {
        colorMenuBackground: '#ffffff',
        colorMenuText: '#595959',
        colorMenuTextSelected: '#1890ff',
        colorMenuItemBgSelected: '#e6f7ff',
        colorMenuDivider: '#f0f0f0',
      },
    },

    menuItemRender: (item, dom) => <Link to={item.path || '/'}>{dom}</Link>,

    menu: {
      params: snap.session.permissions,
      request: async () => {
        let objjs: any = [];
        snap.session.permissions?.forEach((res: any) => {
          objjs.push(res);
        });
        let data = objjs.sort((a: any, b: any) => {
          return a._lft - b._lft;
        });
        const menus = loopMenu(data);
        return Promise.resolve(menus);
      },
    },

    unAccessible: <div>unAccessible</div>,
  };
};
```

- [ ] **Step 3: 测试自定义组件渲染**

```bash
npm run dev
```

Expected: 应用启动，自定义Logo和Header正确显示

- [ ] **Step 4: 提交集成修改**

```bash
git add src/common/libs/umi/layoutConfig.tsx
git commit -m "feat: integrate CustomHeader and CustomLogo into layout"
```

---

### Task 8: 添加全局样式

**Files:**
- Create: `src/global.less` (如果不存在) 或 Modify: `src/global.less`

- [ ] **Step 1: 检查global.less是否存在**

```bash
ls -la src/global.less
```

如果文件存在，跳过此步。如果不存在，创建文件。

- [ ] **Step 2: 创建或修改global.less**

如果文件不存在，创建它：

```less
@import '~antd/es/style/reset.css';

// 全局样式
body {
  margin: 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
    sans-serif;
  font-size: 14px;
  line-height: 1.5715;
  color: #262626;
  background-color: #f5f5f5;
}

// 自定义Logo样式
.custom-logo {
  display: flex;
  align-items: center;
  height: 64px;
  padding: 0 16px;
  border-bottom: 1px solid #f0f0f0;
  transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1.000);
  background: #ffffff;
}

.custom-logo .logo-icon {
  font-size: 32px;
  min-width: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.custom-logo .logo-text {
  margin-left: 12px;
  font-size: 16px;
  font-weight: 600;
  color: #262626;
  white-space: nowrap;
  opacity: 1;
  transition: opacity 0.2s;
}

// 折叠状态
.ant-layout-sider-collapsed .custom-logo {
  padding: 0;
  justify-content: center;
}

.ant-layout-sider-collapsed .custom-logo .logo-text {
  display: none;
}

// 自定义Header样式
.custom-header {
  display: flex !important;
  justify-content: space-between;
  align-items: center;
  padding: 0 24px !important;
  background: #ffffff !important;
  border-bottom: 1px solid #f0f0f0;
  line-height: 64px;
}

.custom-header .header-left {
  flex: 1;
}

.custom-header .header-right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.custom-header .header-right > div {
  display: flex;
  align-items: center;
  transition: opacity 0.2s;
}

.custom-header .header-right > div:hover {
  opacity: 0.8;
}

// 内容区域
.ant-pro-grid-content {
  padding: 24px;
}

// 页面容器卡片
.ant-pro-page-container {
  background: transparent;
}

.ant-pro-page-container .ant-pro-page-container-warp {
  background: #ffffff;
  border-radius: 8px;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
  padding: 24px;
}
```

如果文件已存在，在文件末尾添加上述样式。

- [ ] **Step 3: 验证样式加载**

```bash
npm run dev
```

Expected: 样式正确应用，布局显示正常

- [ ] **Step 4: 提交全局样式**

```bash
git add src/global.less
git commit -m "style: add global styles for custom layout components"
```

---

### Task 9: 测试侧边栏折叠功能

**Files:**
- Test: Manual testing in browser

- [ ] **Step 1: 启动应用**

```bash
npm run dev
```

- [ ] **Step 2: 测试侧边栏折叠**

在浏览器中：
1. 点击侧边栏折叠按钮（如果可见）
2. 或者修改layoutConfig临时添加折叠按钮用于测试

Expected:
- 侧边栏宽度从220px变为64px
- Logo文字消失，仅显示图标
- 菜单文字隐藏，图标居中

- [ ] **Step 3: 测试侧边栏展开**

再次点击折叠按钮

Expected:
- 侧边栏宽度从64px恢复为220px
- Logo文字显示
- 菜单文字显示

- [ ] **Step 4: 测试Tooltip**

折叠状态下，鼠标悬停在菜单图标上

Expected: 显示完整菜单项文字的Tooltip

- [ ] **Step 5: 提交测试结果（如果有问题需修复）**

如果有问题需要修复，创建新的task。如果测试通过，继续下一步。

---

### Task 10: 测试菜单导航和权限

**Files:**
- Test: Manual testing in browser

- [ ] **Step 1: 测试菜单点击导航**

点击各个菜单项

Expected:
- 页面正确跳转
- 菜单项激活状态正确显示（蓝色文字+浅蓝背景）
- 左侧蓝色指示器显示

- [ ] **Step 2: 测试子菜单展开**

点击有子菜单的项

Expected:
- 子菜单平滑展开
- 层级缩进正确（每级20px）

- [ ] **Step 3: 测试权限控制**

使用不同权限的账户登录

Expected:
- 菜单根据权限正确显示/隐藏
- 无权限的菜单项不显示

- [ ] **Step 4: 提交测试结果（如果有问题需修复）**

如果有问题需要修复，创建新的task。如果测试通过，继续下一步。

---

### Task 11: 测试Header功能

**Files:**
- Test: Manual testing in browser

- [ ] **Step 1: 测试用户信息显示**

Expected:
- 头像正确显示
- 用户名正确显示

- [ ] **Step 2: 测试下拉菜单**

点击用户信息区域

Expected:
- 下拉菜单淡入显示
- 菜单项：个人资料、修改密码、退出登录

- [ ] **Step 3: 测试退出登录**

点击"退出登录"

Expected:
- 清除token
- 跳转到登录页面

- [ ] **Step 4: 提交测试结果（如果有问题需修复）**

如果有问题需要修复，创建新的task。如果测试通过，继续下一步。

---

### Task 12: 响应式测试

**Files:**
- Test: Manual testing in browser DevTools

- [ ] **Step 1: 测试桌面端（>1024px）**

Expected: 侧边栏宽度220px，完整显示

- [ ] **Step 2: 测试平板端（768px-1024px）**

使用浏览器DevTools切换到平板视图

Expected: 布局正常，侧边栏可能自动收起

- [ ] **Step 3: 测试移动端（<768px）**

使用浏览器DevTools切换到移动视图

Expected:
- 侧边栏自动收起
- 内容区域内边距适应

- [ ] **Step 4: 提交测试结果（如果有问题需修复）**

如果有问题需要修复，创建新的task。如果测试通过，继续下一步。

---

### Task 13: 浏览器兼容性测试

**Files:**
- Test: Manual testing in different browsers

- [ ] **Step 1: Chrome浏览器测试**

打开Chrome浏览器测试所有功能

Expected: 所有功能正常

- [ ] **Step 2: Firefox浏览器测试**

打开Firefox浏览器测试所有功能

Expected: 所有功能正常

- [ ] **Step 3: Safari浏览器测试（如果有Mac）**

打开Safari浏览器测试所有功能

Expected: 所有功能正常

- [ ] **Step 4: Edge浏览器测试**

打开Edge浏览器测试所有功能

Expected: 所有功能正常

- [ ] **Step 5: 提交测试结果（如果有问题需修复）**

如果有问题需要修复，创建新的task。如果测试通过，继续下一步。

---

### Task 14: 性能检查

**Files:**
- Test: Performance testing

- [ ] **Step 1: 检查折叠动画性能**

使用浏览器DevTools Performance面板录制折叠动画

Expected: 动画流畅，FPS > 30

- [ ] **Step 2: 检查首次渲染性能**

刷新页面，查看DevTools Network和Performance

Expected: 首次渲染时间 < 2秒

- [ ] **Step 3: 检查内存泄漏**

打开应用，使用一段时间，查看DevTools Memory

Expected: 无明显内存泄漏

- [ ] **Step 4: 提交性能检查结果（如果有问题需优化）**

如果有问题需要优化，创建新的task。如果性能良好，继续下一步。

---

### Task 15: 最终验收和文档

**Files:**
- Update: `docs/superpowers/specs/2026-03-30-layout-redesign-design.md`

- [ ] **Step 1: 对照设计文档验收**

检查以下验收标准：
- [ ] 布局结构符合设计要求（左右分栏）
- [ ] 侧边栏可正常折叠和展开
- [ ] 白色主题在所有页面正确显示
- [ ] 菜单权限系统正常工作
- [ ] 所有页面路由和功能无异常
- [ ] 响应式布局在不同设备正常
- [ ] 交互动画流畅自然
- [ ] 通过所有测试要点

- [ ] **Step 2: 更新设计文档状态**

在设计文档末尾添加：

```markdown
## 实施状态

- [x] 设计完成
- [x] 实施计划完成
- [x] 实施完成
- [x] 测试通过
- [x] 验收通过

**完成日期**: 2026-03-30
**提交记录**: [commit hash]
```

- [ ] **Step 3: 创建实施总结**

创建 `docs/superpowers/summaries/2026-03-30-layout-redesign-summary.md`:

```markdown
# Layout结构优化实施总结

**日期**: 2026-03-30
**状态**: 已完成

## 实施内容

1. 将layout从mix模式优化为side模式
2. 创建CustomLogo组件，支持折叠时智能显示
3. 创建CustomHeader组件，保持用户信息功能
4. 更新主题为白色系，提升视觉体验
5. 添加全局样式和响应式支持

## 修改文件清单

- 新建: `src/common/components/layout/CustomHeader.tsx`
- 新建: `src/common/components/layout/CustomLogo.tsx`
- 新建: `src/common/components/layout/index.ts`
- 修改: `src/common/libs/umi/layoutConfig.tsx`
- 修改: `src/global.less`

## 测试结果

- [x] 侧边栏折叠/展开功能正常
- [x] 菜单导航和权限系统正常
- [x] Header用户信息功能正常
- [x] 响应式布局正常
- [x] 浏览器兼容性良好
- [x] 性能满足要求

## 备注

所有功能按设计文档实现，测试通过，可以上线使用。
```

- [ ] **Step 4: 最终提交**

```bash
git add docs/superpowers/specs/2026-03-30-layout-redesign-design.md
git add docs/superpowers/summaries/2026-03-30-layout-redesign-summary.md
git commit -m "docs: update design document and add implementation summary"
```

- [ ] **Step 5: 合并到主分支（如果需要）**

```bash
git checkout main
git merge develop
git push origin main
```

或者根据项目流程创建PR。

---

## 计划自审查

**Spec覆盖检查：**
- ✅ 布局从mix改为side - Task 2
- ✅ 白色主题 - Task 3
- ✅ Logo组件（折叠智能显示） - Task 4
- ✅ Header组件（用户信息） - Task 5
- ✅ 侧边栏折叠功能 - Task 9
- ✅ 菜单权限系统 - Task 10
- ✅ 响应式设计 - Task 12
- ✅ 样式和动画 - Task 8
- ✅ 测试验收 - Task 15

**占位符扫描：**
- ✅ 无TBD、TODO
- ✅ 所有步骤包含具体代码/命令
- ✅ 文件路径完整明确
- ✅ 无"类似Task X"引用

**类型一致性检查：**
- ✅ CustomLogo组件在Task 4定义，Task 7导入使用
- ✅ CustomHeader组件在Task 5定义，Task 7导入使用
- ✅ layoutConfig配置在Task 2、3、7逐步完善，配置一致

**完整性检查：**
- ✅ 每个任务都是独立的可执行单元
- ✅ 每个步骤都有明确的验证标准
- ✅ 包含备份、开发、测试、提交的完整流程
- ✅ 涵盖设计文档的所有需求
