diff --git a/.umirc.ts b/.umirc.ts index 1caa088..ae19b4f 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -14,9 +14,9 @@ export default defineConfig({ }, proxy: { '/api/': { - target: 'http://10.39.13.78:8001/', + // target: 'http://10.39.13.78:8002/', // target: 'https://test-admin.linyikj.com.cn/', - // target: 'https://admin.linyikj.com.cn/', + target: 'https://admin.linyikj.com.cn/', changeOrigin: true, pathRewrite: { '^': '' }, }, diff --git a/docs/superpowers/plans/2026-03-30-layout-redesign.md b/docs/superpowers/plans/2026-03-30-layout-redesign.md new file mode 100644 index 0000000..c8ea482 --- /dev/null +++ b/docs/superpowers/plans/2026-03-30-layout-redesign.md @@ -0,0 +1,969 @@ +# 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: () => , + }, + 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 = ({ collapsed }) => { + return ( +
+
+ +
+ {!collapsed && ( +
+ {collapsed ? '' : '物业管理系统'} +
+ )} +
+ ); +}; +``` + +- [ ] **Step 2: 添加组件样式** + +在文件末尾添加样式: + +```typescript +export const CustomLogo: React.FC = ({ 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 = ({ collapsed, toggle }) => { + const { snap } = useMyState(); + + const menuItems: MenuProps['items'] = [ + { + key: 'profile', + label: '个人资料', + icon: 👤, + }, + { + key: 'password', + label: '修改密码', + icon: 🔒, + }, + { + type: 'divider', + }, + { + key: 'logout', + label: '退出登录', + icon: 🚪, + danger: true, + onClick: () => { + // 添加退出登录逻辑 + localStorage.removeItem('token'); + window.location.href = '/login'; + }, + }, + ]; + + return ( +
+ {/* 左侧区域 */} +
+ {/* 可以添加面包屑导航或其他内容 */} +
+ + {/* 右侧用户信息区域 */} +
+ +
+ +
+
+
+
+ ); +}; +``` + +- [ ] **Step 2: 添加Header样式** + +在文件末尾添加样式定义: + +```typescript +export const CustomHeader: React.FC = ({ 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 ; + }, + + // 新增:自定义Logo渲染 + logoRenderer: (collapsed: boolean) => { + return ; + }, + + avatarProps: { + render: () => , + }, + 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) => {dom}, + + 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:
unAccessible
, + }; +}; +``` + +- [ ] **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逐步完善,配置一致 + +**完整性检查:** +- ✅ 每个任务都是独立的可执行单元 +- ✅ 每个步骤都有明确的验证标准 +- ✅ 包含备份、开发、测试、提交的完整流程 +- ✅ 涵盖设计文档的所有需求 diff --git a/docs/superpowers/specs/2026-03-30-layout-redesign-design.md b/docs/superpowers/specs/2026-03-30-layout-redesign-design.md new file mode 100644 index 0000000..7769de5 --- /dev/null +++ b/docs/superpowers/specs/2026-03-30-layout-redesign-design.md @@ -0,0 +1,465 @@ +# Layout结构优化设计文档 + +**日期**: 2026-03-30 +**项目**: 物业缴费管理系统后台 +**目标**: 优化现有layout布局,改为左右结构,白色主题风格 + +## 1. 项目背景 + +当前系统使用UmiJS + Ant Design Pro Layout,采用`mix`混合布局模式。需要优化为更现代、清晰的左右分栏布局,以白色为主色调,提升用户体验。 + +## 2. 需求概述 + +### 2.1 布局结构要求 +- **左侧区域**(垂直分割): + - 上方:Logo区域(Logo + 项目名称) + - 下方:导航菜单 + +- **右侧区域**(垂直分割): + - 上方:Header(用户信息、操作按钮) + - 下方:页面内容区域 + +### 2.2 功能要求 +- 侧边栏固定宽度220px,支持折叠收起(折叠至64px) +- Logo区域智能显示:展开时显示Logo+文字,折叠时仅显示Logo +- 白色为主色调,整体风格干净整洁 +- 保持现有菜单权限系统不变 +- 响应式设计支持 + +## 3. 设计方案 + +### 3.1 整体架构 + +``` +┌─────────────────────────────────────────────────────┐ +│ Layout (side mode) │ +│ ┌──────────┬─────────────────────────────────────┐ │ +│ │ │ Header (64px, white background) │ │ +│ │ Left │ ┌───────────────────────────────┐ │ │ +│ │ Sidebar │ │ 用户信息区 + 操作按钮 │ │ │ +│ │ │ └───────────────────────────────┘ │ │ +│ │ ┌──────┐│ ┌───────────────────────────────┐ │ │ +│ │ │ Logo ││ │ │ │ │ +│ │ │+Text ││ │ 页面内容区域 │ │ │ +│ │ │64px ││ │ (children渲染) │ │ │ +│ │ ├──────┤│ │ padding: 24px │ │ │ +│ │ │ Menu ││ │ │ │ │ +│ │ │ ││ │ │ │ │ +│ │ └──────┘│ └───────────────────────────────┘ │ │ +│ └──────────┴─────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────┘ +``` + +### 3.2 侧边栏设计(左侧) + +#### Logo区域 +- **高度**: 64px +- **背景色**: `#ffffff` +- **边框**: 底部 1px solid `#f0f0f0` +- **展开状态**: Logo图标(32px) + 项目名称文字 +- **折叠状态**: 仅显示Logo图标,居中显示 +- **动画**: 平滑过渡 200ms + +#### 菜单区域 +- **背景色**: `#ffffff` +- **菜单项高度**: 40px +- **菜单文字颜色**: + - 默认: `#595959` + - 悬停: `#1890ff` + - 激活: `#1890ff` (背景 `#e6f7ff`) +- **图标颜色**: 跟随文字颜色 +- **层级缩进**: 每级 20px +- **激活指示器**: 左侧蓝色竖线 3px宽 + +#### 配置参数 +```typescript +siderWidth: 220, +collapsedWidth: 64, +breakpoint: 'lg', +collapsible: true +``` + +### 3.3 Header设计(右侧上方) + +#### 布局规格 +- **高度**: 64px +- **背景色**: `#ffffff` +- **边框**: 底部 1px solid `#f0f0f0` +- **内边距**: 0 24px +- **布局**: flex左右分布 + +#### 内容区域 + +**左侧区域**(可选): +- 面包屑导航或页面标题 + +**右侧区域**: +- 用户头像(32px圆形) +- 用户名(悬停显示下拉菜单) +- 下拉菜单项: + - 个人资料 + - 修改密码 + - 退出登录 + +### 3.4 内容区域设计(右侧下方) + +#### 容器规格 +- **背景色**: `#f5f5f5` +- **内边距**: 24px +- **最小高度**: `calc(100vh - 64px)` + +#### 页面内容(可选包裹) +如果需要卡片包裹: +- **背景色**: `#ffffff` +- **圆角**: 8px +- **阴影**: `0 1px 2px 0 rgba(0, 0, 0, 0.03)` +- **内边距**: 24px + +### 3.5 颜色主题规范 + +#### 主色调 +- 主色: `#1890ff` +- 成功: `#52c41a` +- 警告: `#faad14` +- 错误: `#ff4d4f` +- 信息: `#1890ff` + +#### 中性色 +- 标题文字: `#262626` +- 正文文字: `#595959` +- 次要文字: `#8c8c8c` +- 禁用文字: `#bfbfbf` +- 边框: `#d9d9d9` +- 分割线: `#f0f0f0` + +#### 背景色 +- 布局背景: `#f5f5f5` +- 侧边栏: `#ffffff` +- Header: `#ffffff` +- 内容卡片: `#ffffff` + +### 3.6 字体规范 +- **字号**: 14px(基准) +- **行高**: 1.5715 +- **字体族**: `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial` + +### 3.7 交互和动画 + +#### 侧边栏折叠 +- **动画时长**: 200ms +- **动画曲线**: `cubic-bezier(0.645, 0.045, 0.355, 1.000)` +- **折叠时**: + - Logo文字淡出 + - 菜单文字隐藏,图标居中 + - Tooltip显示完整菜单项文字 +- **展开时**: + - Logo文字淡入 + - 菜单文字从左侧滑入 + +#### 菜单交互 +- 悬停效果:背景色变化 0.2s +- 子菜单展开:平滑动画 +- 激活状态:左侧蓝色竖线指示器 + +#### Header交互 +- 下拉菜单:淡入动画 +- 按钮悬停:背景色变化 + +## 4. 技术实现 + +### 4.1 核心配置修改 + +修改 `src/common/libs/umi/layoutConfig.tsx`: + +```typescript +export const LayoutConfig: RuntimeConfig['layout'] = () => { + return { + // 从 'mix' 改为 'side' + layout: 'side', + + title: '物业管理系统', + logo: false, // 禁用默认logo,使用自定义 + + // 侧边栏配置 + siderWidth: 220, + collapsedWidth: 64, + breakpoint: 'lg', + + // 主题token配置 + token: { + bgLayout: '#f5f5f5', + header: { + colorBgHeader: '#ffffff', + colorHeaderTitle: '#262626', + colorTextRightActionsItem: '#595959', + heightLayoutHeader: 64, + }, + sider: { + colorMenuBackground: '#ffffff', + colorMenuText: '#595959', + colorMenuTextSelected: '#1890ff', + colorMenuItemBgSelected: '#e6f7ff', + colorMenuDivider: '#f0f0f0', + }, + }, + + // 自定义Header渲染 + headerRender: (props) => { + return ; + }, + + // 自定义Logo渲染 + logoRenderer: (collapsed) => { + return ; + }, + + // 菜单配置保持不变 + menu: { + params: snap.session.permissions, + request: async () => { + // 现有菜单权限逻辑 + }, + }, + + // 其他配置保持不变 + avatarProps: { + render: () => , + }, + }; +}; +``` + +### 4.2 新增组件 + +#### CustomHeader.tsx +```typescript +import { Layout, Dropdown, Avatar } from 'antd'; +import type { MenuProps } from 'antd'; + +const { Header } = Layout; + +export const CustomHeader = (props: any) => { + const menuItems: MenuProps['items'] = [ + { key: 'profile', label: '个人资料' }, + { key: 'password', label: '修改密码' }, + { type: 'divider' }, + { key: 'logout', label: '退出登录' }, + ]; + + return ( +
+ {/* 左侧:面包屑或页面标题 */} +
+ {/* 可选:面包屑导航 */} +
+ + {/* 右侧:用户信息 */} +
+ + + +
+
+ ); +}; +``` + +#### CustomLogo.tsx +```typescript +import { MyIcons } from '@/common'; + +export const CustomLogo = ({ collapsed }: { collapsed: boolean }) => { + return ( +
+
+ {/* Logo图标或图片 */} + +
+ {!collapsed && ( +
+ 物业管理系统 +
+ )} +
+ ); +}; +``` + +### 4.3 样式文件 + +在 `src/global.less` 或组件内部添加: + +```less +.custom-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 24px; + background: #ffffff; + border-bottom: 1px solid #f0f0f0; + + .header-left { + flex: 1; + } + + .header-right { + display: flex; + align-items: center; + gap: 16px; + } +} + +.custom-logo { + display: flex; + align-items: center; + height: 64px; + padding: 0 16px; + border-bottom: 1px solid #f0f0f0; + transition: all 0.2s; + + .logo-icon { + font-size: 32px; + min-width: 32px; + } + + .logo-text { + margin-left: 12px; + font-size: 16px; + font-weight: 600; + color: #262626; + white-space: nowrap; + opacity: 1; + transition: opacity 0.2s; + } +} +``` + +## 5. 实施计划 + +### 5.1 实施步骤 +1. 备份当前 `layoutConfig.tsx` 文件 +2. 修改 layout 模式:`'mix'` → `'side'` +3. 更新 token 配置为白色主题 +4. 创建 `CustomHeader.tsx` 组件 +5. 创建 `CustomLogo.tsx` 组件 +6. 在 `layoutConfig.tsx` 中集成自定义组件 +7. 测试侧边栏折叠/展开功能 +8. 测试菜单导航和权限控制 +9. 测试响应式布局 +10. 调整细节样式和动画 + +### 5.2 文件修改清单 + +**需要修改**: +- `src/common/libs/umi/layoutConfig.tsx` - 主要配置修改 + +**需要新建**: +- `src/common/components/layout/CustomHeader.tsx` +- `src/common/components/layout/CustomLogo.tsx` + +**可能修改**: +- `src/global.less` - 全局样式调整 + +**无需修改**: +- 菜单权限逻辑(`loopMenu` 函数) +- 用户信息组件(`AvatarProps`) +- 页面路由和业务组件 +- `src/app.tsx` 配置 + +### 5.3 兼容性保证 + +**保持不变的功能**: +- ✅ 菜单权限系统 +- ✅ 用户登录状态 +- ✅ 路由跳转逻辑 +- ✅ 页面内容渲染 +- ✅ 现有业务组件 + +**优化改进的功能**: +- 🎨 布局结构和视觉风格 +- 🎨 主题色和配色方案 +- 🎨 交互体验和动画效果 + +## 6. 测试要点 + +### 6.1 功能测试 +- [ ] 侧边栏折叠/展开正常工作 +- [ ] 菜单项点击导航正确 +- [ ] 菜单激活状态正确显示 +- [ ] 用户信息下拉菜单功能正常 +- [ ] 所有页面路由可正常访问 + +### 6.2 样式测试 +- [ ] 白色主题在所有页面正常显示 +- [ ] Logo展开/折叠切换流畅 +- [ ] 菜单悬停和激活状态样式正确 +- [ ] Header样式和布局正确 +- [ ] 内容区域内边距和背景正确 + +### 6.3 响应式测试 +- [ ] 桌面端(>1024px)显示正常 +- [ ] 平板端(768px-1024px)显示正常 +- [ ] 移动端(<768px)侧边栏自动收起 +- [ ] 各断点下布局无错位 + +### 6.4 兼容性测试 +- [ ] 表单页面显示正常 +- [ ] 表格页面显示正常 +- [ ] 弹窗和抽屉组件正常 +- [ ] 现有业务功能无异常 + +## 7. 风险和注意事项 + +### 7.1 潜在风险 +- **样式冲突**: Ant Design版本升级可能导致样式变化 +- **浏览器兼容**: CSS动画在旧浏览器可能不支持 +- **性能影响**: 过多动画可能影响低端设备性能 + +### 7.2 缓解措施 +- 在主流浏览器中测试(Chrome, Firefox, Safari, Edge) +- 使用CSS `@supports`检测动画支持 +- 优化动画性能,使用 `transform` 和 `opacity` +- 提供关闭动画的选项(如果需要) + +### 7.3 回滚方案 +- 保留原 `layoutConfig.tsx` 备份 +- 使用git版本控制,可随时回退 +- 分阶段发布,先在测试环境验证 + +## 8. 后续优化建议 + +### 8.1 短期优化 +- 添加暗色模式切换(可选) +- 优化移动端触摸体验 +- 添加快捷键支持 + +### 8.2 长期优化 +- 考虑使用ProLayout替代UmiJS Layout(如需要更多功能) +- 添加主题定制功能 +- 实现布局配置持久化(记住用户的折叠状态等) + +## 9. 验收标准 + +项目完成需满足以下标准: + +1. ✅ 布局结构符合设计要求(左右分栏) +2. ✅ 侧边栏可正常折叠和展开 +3. ✅ 白色主题在所有页面正确显示 +4. ✅ 菜单权限系统正常工作 +5. ✅ 所有页面路由和功能无异常 +6. ✅ 响应式布局在不同设备正常 +7. ✅ 交互动画流畅自然 +8. ✅ 通过所有测试要点 + +## 10. 附录 + +### 10.1 参考文档 +- [UmiJS Layout配置](https://umijs.org/docs/max/layout-menu) +- [Ant Design Layout组件](https://ant.design/components/layout-cn) +- [Ant Design 主题定制](https://ant.design/docs/react/customize-theme-cn) + +### 10.2 设计原则 +- **简洁**: 去除不必要的装饰和元素 +- **一致**: 保持整体风格统一 +- **高效**: 快速加载和响应 +- **易用**: 直观的交互和导航 diff --git a/src/common/components/layout/CustomHeader.tsx b/src/common/components/layout/CustomHeader.tsx new file mode 100644 index 0000000..16f3f37 --- /dev/null +++ b/src/common/components/layout/CustomHeader.tsx @@ -0,0 +1,71 @@ +import React from 'react'; +import { Layout, Dropdown } 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 = ({ collapsed, toggle }) => { + const { snap } = useMyState(); + + // 在登录页面不显示header + if (typeof window !== 'undefined' && window.location.pathname === '/login') { + return null; + } + + const menuItems: MenuProps['items'] = [ + { + key: 'profile', + label: '个人资料', + icon: 👤, + }, + { + key: 'password', + label: '修改密码', + icon: 🔒, + }, + { + type: 'divider', + }, + { + key: 'logout', + label: '退出登录', + icon: 🚪, + danger: true, + onClick: () => { + // 添加退出登录逻辑 + localStorage.removeItem('token'); + window.location.href = '/login'; + }, + }, + ]; + + return ( +
+ {/* 左侧区域 */} +
+ {/* 可以添加面包屑导航或其他内容 */} +
+ + {/* 右侧用户信息区域 */} +
+ +
+ +
+
+
+
+ ); +}; + +// Styles will be defined in global.less: +// .custom-header { display: flex; justify-content: space-between; ... } +// .custom-header .header-left { flex: 1; } +// .custom-header .header-right { display: flex; gap: 16px; } diff --git a/src/common/components/layout/CustomLogo.tsx b/src/common/components/layout/CustomLogo.tsx new file mode 100644 index 0000000..8fdac93 --- /dev/null +++ b/src/common/components/layout/CustomLogo.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { MyIcons } from '@/common'; + +interface CustomLogoProps { + collapsed: boolean; +} + +export const CustomLogo: React.FC = ({ collapsed }) => { + return ( +
+
+ +
+ {!collapsed && ( +
+ 物业管理系统 +
+ )} +
+ ); +}; + +// Styles will be defined in global.less: +// .custom-logo { display: flex; align-items: center; height: 64px; ... } +// .custom-logo .logo-icon { font-size: 32px; min-width: 32px; ... } +// .custom-logo .logo-text { margin-left: 12px; font-size: 16px; ... } +// .ant-layout-sider-collapsed .custom-logo .logo-text { display: none; } diff --git a/src/common/components/layout/MyPageContainer.tsx b/src/common/components/layout/MyPageContainer.tsx index d14142b..a3a47b9 100644 --- a/src/common/components/layout/MyPageContainer.tsx +++ b/src/common/components/layout/MyPageContainer.tsx @@ -1,3 +1,4 @@ +import { useMyState } from '@/common'; import { CloseOutlined, ReloadOutlined } from '@ant-design/icons'; import { PageContainer, PageContainerProps } from '@ant-design/pro-components'; import { history, useLocation } from '@umijs/max'; @@ -198,6 +199,7 @@ export function MyPageContainer({ ...rest }: MyPageContainerProps) { const location = useLocation(); + const { snap } = useMyState(); const [tabs, setTabs] = useState([]); const [activeKey, setActiveKey] = useState(''); const contextMenuRef = useRef<{ @@ -206,6 +208,33 @@ export function MyPageContainer({ targetKey: string; } | null>(null); + // 用户下拉菜单配置 + const userMenuItems: MenuProps['items'] = [ + { + key: 'profile', + label: '个人资料', + icon: 👤, + }, + { + key: 'password', + label: '修改密码', + icon: 🔒, + }, + { + type: 'divider', + }, + { + key: 'logout', + label: '退出登录', + icon: 🚪, + danger: true, + onClick: () => { + localStorage.removeItem('token'); + window.location.href = '/login'; + }, + }, + ]; + // 订阅标签页状态变化 useEffect(() => { const unsubscribe = tabsManager.subscribe(() => { @@ -332,52 +361,62 @@ export function MyPageContainer({ ); }; - if (!enableTabs || tabs.length === 0) { - return ( - - - {children} - - - ); - } + // if (!enableTabs || tabs.length === 0) { + // return ( + // + // + // {children} + // + // + // ); + // } return ( ({ - key: tab.key, - label: tab.label, - closable: tab.closable, - }))} +
+ > + {/* 左侧:Tabs标签页 */} +
+ ({ + key: tab.key, + label: tab.label, + closable: tab.closable, + }))} + style={{ + marginTop: 6, + marginBottom: 0, + }} + /> +
+
), style: { backgroundColor: '#FFF' }, }} diff --git a/src/common/components/layout/index.ts b/src/common/components/layout/index.ts new file mode 100644 index 0000000..d242772 --- /dev/null +++ b/src/common/components/layout/index.ts @@ -0,0 +1,3 @@ +export { CustomLogo } from './CustomLogo'; +export { CustomHeader } from './CustomHeader'; +export { default as AvatarProps } from './AvatarProps'; diff --git a/src/common/libs/umi/layoutConfig.tsx b/src/common/libs/umi/layoutConfig.tsx index acda85b..1917b05 100644 --- a/src/common/libs/umi/layoutConfig.tsx +++ b/src/common/libs/umi/layoutConfig.tsx @@ -1,7 +1,8 @@ // import Logo from '@/assets/bitcoin.webp'; import { MyIcons, MyIconsType, PermissionsType, useMyState } from '@/common'; +import { AvatarProps, CustomLogo } from '@/common/components/layout'; import { Link, RuntimeConfig, history } from '@umijs/max'; -import AvatarProps from '../../components/layout/AvatarProps'; +import MyLoGo from './logo.jpeg'; const loopMenu = (permissions: PermissionsType[] | undefined) => { let tree: PermissionsType[] = []; @@ -32,31 +33,93 @@ export const LayoutConfig: RuntimeConfig['layout'] = () => { const { snap } = useMyState(); return { - title: snap.session.campus?.name ?? '总后台', - // logo: , - logo: <>, - layout: 'mix', + title: '物业管理平台', + logo: MyLoGo, // 禁用默认logo,使用自定义 + layout: 'mix', // 从 'mix' 改为 'side' colorPrimary: '#1890ff', siderWidth: 220, + prefixCls: 'my-prefix', pure: history.location.pathname === '/login', + // 禁用顶部导航栏的菜单 + // 确保header显示 - 强制始终显示header,禁用响应式隐藏 + header: true, + // 禁用响应式侧边栏,确保header始终显示 + responsive: false, + // siderMenuType: 'inline', + // 隐藏面包屑导航 + breadcrumb: { props: { style: { display: 'none' } } }, avatarProps: { - render: () => , + // src: 'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg', + // size: 'small', + // title: snap?.session?.user?.username ?? '-', + render: (props, dom) => { + return ; + // return ( + // , + // label: '退出登录', + // }, + // ], + // }} + // > + // {dom} + // + // ); + }, + }, + // 自定义Header渲染 - 右侧显示用户信息 + // headerRender: (props, defaultDom) => { + // return ( + //
+ // {/* 左侧可以为空 */} + //
+ // {/* 右侧添加用户信息 */} + //
+ // + //
+ //
+ // ); + // }, + + // 新增:自定义Logo渲染 + logoRenderer: (collapsed: boolean) => { + return ; }, //水印设置 // waterMarkProps: { // content: snap.session.user?.username, // }, collapsedButtonRender: false, + // 禁用底部的版权信息等 + footerRender: false, token: { - bgLayout: '#eef0f3', + bgLayout: '#f5f5f5', // 浅灰布局背景 header: { - colorBgHeader: '#001529', - colorHeaderTitle: '#FFF', - colorTextRightActionsItem: '#FFF', - heightLayoutHeader: 50, + colorBgHeader: '#ffffff', // 白色header背景 + colorHeaderTitle: '#262626', // 深色标题文字 + colorTextRightActionsItem: '#595959', // 深色操作文字 + heightLayoutHeader: 64, // Header高度64px }, sider: { - colorMenuBackground: '#FFF', + colorMenuBackground: '#ffffff', // 白色菜单背景 + colorMenuText: '#595959', // 深色菜单文字 + colorMenuTextSelected: '#1890ff', // 激活菜单文字蓝色 + colorMenuItemBgSelected: '#e6f7ff', // 激活菜单背景浅蓝 + colorMenuDivider: '#f0f0f0', // 分割线颜色 }, }, menuItemRender: (item, dom) => {dom}, diff --git a/src/common/libs/umi/layoutConfig.tsx.backup b/src/common/libs/umi/layoutConfig.tsx.backup new file mode 100644 index 0000000..acda85b --- /dev/null +++ b/src/common/libs/umi/layoutConfig.tsx.backup @@ -0,0 +1,79 @@ +// 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'; + +const loopMenu = (permissions: PermissionsType[] | undefined) => { + let tree: PermissionsType[] = []; + let map: Record = {}; + permissions?.forEach((permission) => { + map[permission.id] = { + path: permission.type === 'Button' ? 'null' : permission.path, + name: permission.name, + icon: permission.icon && MyIcons[permission.icon as MyIconsType], + children: [], + hideInMenu: permission.type === 'Button', + }; + }); + + permissions?.forEach((permission) => { + let node = map[permission.id]; + if (permission.parent_id !== null) { + map[permission.parent_id].children.push(node); + } else { + tree.push(node); + } + }); + + return tree?.[0]?.children; +}; + +export const LayoutConfig: RuntimeConfig['layout'] = () => { + const { snap } = useMyState(); + + return { + title: snap.session.campus?.name ?? '总后台', + // logo: , + logo: <>, + layout: 'mix', + colorPrimary: '#1890ff', + siderWidth: 220, + pure: history.location.pathname === '/login', + avatarProps: { + render: () => , + }, + //水印设置 + // waterMarkProps: { + // content: snap.session.user?.username, + // }, + collapsedButtonRender: false, + token: { + bgLayout: '#eef0f3', + header: { + colorBgHeader: '#001529', + colorHeaderTitle: '#FFF', + colorTextRightActionsItem: '#FFF', + heightLayoutHeader: 50, + }, + sider: { + colorMenuBackground: '#FFF', + }, + }, + menuItemRender: (item, dom) => {dom}, + 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:
unAccessible
, + }; +}; diff --git a/src/common/libs/umi/logo.jpeg b/src/common/libs/umi/logo.jpeg new file mode 100644 index 0000000..ec10a03 Binary files /dev/null and b/src/common/libs/umi/logo.jpeg differ diff --git a/src/common/pages/MyLoginPage1.tsx b/src/common/pages/MyLoginPage1.tsx index 8365b17..627d044 100644 --- a/src/common/pages/MyLoginPage1.tsx +++ b/src/common/pages/MyLoginPage1.tsx @@ -12,6 +12,7 @@ import { import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { stateActions } from '..'; +import loginBgImg from './loginBgImg.jpg'; export function MyLoginPage1() { const navigate = useNavigate(); @@ -37,8 +38,9 @@ export function MyLoginPage1() { > title="欢迎使用后台管理系统" - backgroundVideoUrl="https://gw.alipayobjects.com/v/huamei_gcee1x/afts/video/jXRBRK_VAwoAAAAAAAAAAAAAK4eUAQBr" - subTitle="Admin management system" + // backgroundVideoUrl="https://gw.alipayobjects.com/v/huamei_gcee1x/afts/video/jXRBRK_VAwoAAAAAAAAAAAAAK4eUAQBr" + backgroundImageUrl={loginBgImg} + subTitle="物业管理平台" onFinish={async (values: any) => { Apis.Common.Auth.Login({ ...values, diff --git a/src/common/pages/loginBgImg.jpg b/src/common/pages/loginBgImg.jpg new file mode 100644 index 0000000..7493aea Binary files /dev/null and b/src/common/pages/loginBgImg.jpg differ diff --git a/src/global.less b/src/global.less new file mode 100644 index 0000000..04587d2 --- /dev/null +++ b/src/global.less @@ -0,0 +1,274 @@ +@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); +// 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; +// } + +// // PageContainer Header样式 - 固定悬浮在UmiJS Header下方 +// div[class*='page-container-header'], +// .ant-pro-page-container > div[class*='page-container-header'], +// .ant-pro-page-container-header { +// position: fixed !important; +// top: 64px !important; /* UmiJS Header的高度 */ +// right: 0 !important; +// left: 220px !important; /* 侧边栏宽度 */ +// z-index: 999 !important; +// margin: 0 !important; +// padding: 8px 24px !important; /* 增加padding */ +// background: #ffffff !important; +// border-bottom: 1px solid #f0f0f0 !important; +// box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05) !important; +// height: auto !important; +// min-height: 40px !important; +// max-height: 52px !important; +// display: flex !important; +// align-items: center !important; +// } + +// // 当侧边栏折叠时,调整tabs header的left值 +// .ant-layout-sider-collapsed ~ .ant-layout .ant-pro-page-container-header { +// left: 64px !important; +// } + +// // 强制PageContainer header样式 +// .ant-pro-page-container .ant-pro-page-container-header { +// position: fixed !important; +// top: 64px !important; +// right: 0 !important; +// left: 220px !important; +// z-index: 999 !important; +// margin: 0 !important; +// padding: 8px 24px !important; +// min-height: 40px !important; +// max-height: 52px !important; +// display: flex !important; +// align-items: center !important; +// } + +// // 确保UmiJS Header固定在顶部 +// .ant-pro-header, +// .ant-layout-header { +// position: fixed !important; +// top: 0 !important; +// right: 0 !important; +// left: 220px !important; +// z-index: 1000 !important; +// width: auto !important; +// background: #ffffff !important; +// border-bottom: 1px solid #f0f0f0 !important; +// } + +// .ant-layout-sider-collapsed ~ .ant-layout .ant-pro-header, +// .ant-layout-sider-collapsed + .ant-layout .ant-pro-header { +// left: 64px !important; +// } + +// // Tabs样式优化 - 减小高度 +// .ant-pro-page-container-header .tabs-header-only, +// div[class*='page-container-header'] .tabs-header-only { +// margin: 0 !important; +// line-height: 1 !important; +// height: auto !important; +// display: flex !important; +// align-items: center !important; +// } + +// .ant-pro-page-container-header .ant-tabs, +// div[class*='page-container-header'] .ant-tabs { +// margin: 0 !important; +// height: auto !important; +// } + +// .ant-pro-page-container-header .ant-tabs-nav, +// div[class*='page-container-header'] .ant-tabs-nav { +// margin-bottom: 0 !important; +// height: auto !important; +// } + +// .ant-pro-page-container-header .ant-tabs-nav-list, +// div[class*='page-container-header'] .ant-tabs-nav-list { +// margin-bottom: 0 !important; +// height: auto !important; +// display: flex !important; +// align-items: center !important; +// } + +// .ant-pro-page-container-header .ant-tabs-tab, +// div[class*='page-container-header'] .ant-tabs-tab { +// padding: 4px 10px !important; +// background: #f5f5f5; +// border-radius: 4px; +// margin-right: 4px; +// transition: all 0.2s; +// height: 26px !important; +// line-height: 26px !important; +// font-size: 13px; +// display: inline-flex !important; +// align-items: center !important; +// } + +// .ant-pro-page-container-header .ant-tabs-tab-active, +// div[class*='page-container-header'] .ant-tabs-tab-active { +// background: #ffffff; +// font-weight: 500; +// } + +// .ant-pro-page-container-header .ant-tabs-ink-bar, +// div[class*='page-container-header'] .ant-tabs-ink-bar { +// display: none !important; +// } + +// // 内容区域 - 调整padding以适应固定的header +.ant-pro-grid-content { + padding: 15px; + // padding-top: 20px; /* 64px UmiJS Header + 48px tabs header + 8px */ +} +.ant-page-header { + padding: 0 15px !important; +} +// .ant-pro-page-container { +// padding-top: 0 !important; +// } + +// .ant-pro-page-container-warp { +// padding: 0 !important; +// } + +// .ant-pro-page-container-children-content { +// padding: 24px !important; +// padding-top: 0 !important; +// } + +// // 确保主内容区域正确的padding +// .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; +// } + +// // 内容区域 - 添加顶部padding避免被固定header遮挡 +// .ant-pro-grid-content { +// padding: 24px; +// padding-top: 24px; /* 恢复正常padding */ +// } + +// .ant-pro-page-container { +// padding-top: 0 !important; +// } + +// .ant-pro-page-container-children-content { +// padding-top: 0 !important; +// padding: 24px !important; +// } + +// // 页面容器卡片 +// .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; +// } + +// // 隐藏侧边栏底部的用户信息区域 +.ant-pro-sider .ant-pro-sider-actions { + display: none !important; +} + +.ant-pro-sider-collapsed .ant-pro-sider-actions { + display: none !important; +} +.my-prefix-sider-actions { + // display: none !important; +} + +// 确保顶部Header始终显示,不受响应式影响 +// .ant-pro-header { +// display: flex !important; +// width: 100% !important; +// } + +// 确保在所有屏幕尺寸下header都显示 +// @media (min-width: 0px) { +// .ant-pro-header { +// display: flex !important; +// } +// } + +// .ant-layout-header { +// display: flex !important; +// } + +// // 确保顶部Header显示 +// .ant-pro-header { +// display: flex !important; +// } + +// // 确保PageContainer的affix header显示 +// .ant-pro-page-container-affix { +// display: block !important; +// }