生产管理系统前端-上边栏搭建与侧边栏搭建

This commit is contained in:
2025-10-20 10:07:45 +08:00
parent ec58562661
commit b63716d002
39 changed files with 9097 additions and 6668 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,135 @@
# 用户故事:多级菜单布局系统重构
## 故事标题
**多级菜单布局系统重构 - Brownfield Addition**
## 用户故事
作为系统用户,
我需要一个新的多级菜单布局系统,
以便更好地组织和访问系统的各个功能模块。
## 故事上下文
### 现有系统集成
- **集成与**: 现有 `Navigation.tsx``Sidebar.tsx` 组件
- **技术**: React + TypeScript + Tailwind CSS
- **遵循模式**: 现有 shadcn/ui 组件库和项目架构
- **接触点**: `src/App.tsx`, 路由系统, 菜单配置
## 验收标准
### 功能需求
#### 1. 顶部菜单栏 (占15%视口高度)
- **左侧**: Logo + "智慧农业生产管理系统"标题
- 显示绿色拖拉机图标和系统名称
- 包含英文副标题 "Smart Agriculture Management System"
- **中间**: 7大子系统菜单项与图标
- 智能农机管理系统 (Tractor图标)
- 地块信息管理系统 (Map图标)
- 农事操作管理系统 (Clipboard图标)
- 农业资产管理系统 (Package图标)
- AI作物模型精准决策系统 (Brain图标)
- 水肥一体化控制系统 (Droplets图标)
- 中心配置管理系统 (Settings图标)
- **右侧**: 用户功能区域
- 消息铃铛图标(显示未读消息数量)
- 系统管理员用户信息(头像+用户名)
- 用户下拉菜单(个人中心、退出登录等选项)
#### 2. 左侧二级菜单
- 根据选中的一级菜单动态显示对应的二级菜单项
- 支持多级展开/折叠功能
- 当前选中页面高亮显示(绿色背景)
- 菜单项层次清晰,缩进合理
#### 3. 右侧内容区域
- 根据路由对应显示具体页面内容
- 无路由对应时显示空页面状态
- 内容区域自适应高度和宽度
- 保持现有页面组件的功能不变
### 集成需求
4. **现有导航功能继续正常工作**: 保持与 `src/App.tsx` 中现有路由逻辑的兼容性
5. **新布局遵循现有的设计模式和样式**: 使用 shadcn/ui 组件库,保持绿色主题
6. **与现有认证系统和路由系统无缝集成**: 保持 `AuthContext` 和路径状态管理
### 质量需求
7. **响应式设计**: 适配不同屏幕尺寸(桌面、平板、移动端)
8. **保持现有功能不回退**: 所有现有页面和功能必须正常工作
9. **代码符合现有项目规范**: 遵循 TypeScript 严格模式,使用现有工具函数
## 技术说明
### 集成方法
- **目录结构**: 在 `src/components/layouts/` 目录创建新的布局组件系统
- **文件组织**:
- `MainLayout.tsx` - 主布局容器
- `TopNavigation.tsx` - 顶部导航栏
- `SideNavigation.tsx` - 侧边栏导航
- `ContentArea.tsx` - 内容区域组件
### 现有模式参考
- **组件样式**: 参考现有的 `Navigation.tsx` 实现模式
- **菜单数据处理**: 保持与 `types/navigation.ts` 中菜单结构的一致性
- **状态管理**: 使用现有的 `useState` 和路径状态管理模式
- **UI组件**: 使用现有的 shadcn/ui 组件Button, Popover, Badge等
### 关键约束
- **保持现有菜单结构**: 7个子系统的菜单配置和层级结构不能改变
- **保持路由逻辑**: 现有的路径导航和页面渲染逻辑必须保持兼容
- **保持认证集成**: 用户认证状态和权限控制逻辑保持不变
- **保持主题风格**: 绿色主题和整体视觉风格保持一致
## 风险和兼容性检查
### 最小风险评估
- **主要风险**: 布局重构可能影响现有页面的显示和交互
- **缓解措施**: 渐进式重构,保持现有组件接口不变
- **回滚方案**: 可快速回退到现有的 Navigation + Sidebar 布局
### 兼容性验证
- [x] 无对现有API的破坏性更改
- [x] 无数据库变更(纯前端重构)
- [x] UI更改遵循现有设计模式
- [x] 对性能的影响可忽略不计
## 验证清单
### 范围验证
- [x] 故事可在一次开发会话内完成预计2-4小时
- [x] 集成方法直接明了
- [x] 完全遵循现有模式
- [x] 无需设计或架构工作
### 清晰度检查
- [x] 故事要求明确无误
- [x] 集成点明确指定
- [x] 成功标准可测试
- [x] 回滚计划简单
## 完成标准
- [ ] 顶部菜单栏正确显示占15%视口高度
- [ ] 7大子系统菜单项正确显示并可点击
- [ ] 消息铃铛和用户下拉菜单功能正常
- [ ] 左侧二级菜单根据一级菜单选择动态更新
- [ ] 右侧内容区域正确显示对应页面内容
- [ ] 响应式设计在不同屏幕尺寸下正常工作
- [ ] 现有功能回归测试通过
- [ ] 代码遵循现有模式和标准
- [ ] 与现有认证系统正常集成
- [ ] 无浏览器控制台错误或警告
## 重要的注意事项
- 这个故事主要涉及UI结构调整不需要复杂的后端集成
- 重构过程中应保持所有现有页面的功能和数据流
- 重点关注用户体验的一致性和导航的流畅性
- 如果复杂度超出预期,考虑拆分为多个较小的故事
- 预计开发时间2-4小时的专注开发工作
---
**故事创建时间**: 2025-10-17
**创建人**: PM Agent (John)
**预计工作量**: 0.5 story points (小型重构任务)

View File

@@ -218,7 +218,9 @@ interface User {
- ✅ React Hook Form + Zod
#### 新增核心技术
- 🆕 **React Router v6**: 专业路由管理
- 🆕 **Next.js 14**: 现代化 React 全栈框架支持动态路由和SSR
- 🆕 **Next.js App Router**: 基于文件系统的动态路由
- 🆕 **React Server Components**: 服务端组件渲染优化
- 🆕 **Zustand**: 轻量级状态管理
- 🆕 **TanStack Query**: 服务端状态管理
- 🆕 **MSW**: Mock Service Worker
@@ -231,8 +233,48 @@ interface User {
crop-x/
├── public/ # 静态资源
│ ├── favicon.ico
│ └── index.html
│ └── next-env.d.ts # Next.js 类型声明
├── src/
│ ├── app/ # Next.js App Router 目录
│ │ ├── layout.tsx # 根布局
│ │ ├── page.tsx # 首页
│ │ ├── globals.css # 全局样式
│ │ ├── (auth)/ # 认证相关路由组
│ │ │ ├── login/
│ │ │ │ └── page.tsx
│ │ │ └── register/
│ │ │ └── page.tsx
│ │ ├── machinery/ # 农机管理动态路由
│ │ │ ├── layout.tsx # 农机模块布局
│ │ │ ├── page.tsx # 农机默认页面
│ │ │ ├── archive/
│ │ │ │ ├── entry/
│ │ │ │ │ └── page.tsx
│ │ │ │ └── [id]/
│ │ │ │ └── page.tsx # 动态路由详情页
│ │ │ ├── driver/
│ │ │ │ └── page.tsx
│ │ │ └── monitoring/
│ │ │ └── realtime/
│ │ │ └── page.tsx
│ │ ├── field/ # 地块管理动态路由
│ │ │ ├── layout.tsx
│ │ │ ├── page.tsx
│ │ │ └── [category]/
│ │ │ └── page.tsx
│ │ ├── operation/ # 农事操作动态路由
│ │ ├── asset/ # 资产管理动态路由
│ │ ├── ai-model/ # AI模型动态路由
│ │ ├── irrigation/ # 灌溉控制动态路由
│ │ ├── config/ # 配置管理动态路由
│ │ │ ├── layout.tsx
│ │ │ ├── page.tsx
│ │ │ └── tenant/
│ │ │ ├── enterprise-audit/
│ │ │ │ └── page.tsx
│ │ │ └── [enterpriseId]/
│ │ │ └── page.tsx # 企业详情动态路由
│ │ └── loading.tsx # 全局加载组件
│ ├── components/ # 可复用组件
│ │ ├── ui/ # shadcn/ui 基础组件
│ │ │ ├── button/
@@ -247,178 +289,307 @@ crop-x/
│ │ ├── Header/
│ │ ├── Sidebar/
│ │ └── Layout/
│ ├── pages/ # 页面组件(按业务模块)
│ │ ├── auth/ # 认证相关页面
│ │ │ ├── LoginPage.tsx
│ │ │ ── RegisterPage.tsx
│ │ ├── machinery/ # 农机管理页面
│ │ │ ├── MachineryListPage.tsx
│ │ │ ├── MachineryDetailPage.tsx
│ │ │ ├── DriverListPage.tsx
│ ├── lib/ # Next.js 库目录
│ │ ├── stores/ # Zustand 状态管理
│ │ │ ├── authStore.ts
│ │ │ ── machineryStore.ts
│ │ │ └── ...
│ │ ├── field/ # 地块管理页面
│ │ ├── operation/ # 农事操作页面
│ │ ├── asset/ # 资产管理页面
│ │ ├── ai-model/ # AI模型页面
│ │ ├── irrigation/ # 灌溉控制页面
│ │ └── config/ # 配置管理页面
├── stores/ # Zustand 状态管理
│ │ ├── authStore.ts # 认证状态
│ │ ├── machineryStore.ts # 农机状态
│ │ ├── fieldStore.ts # 地块状态
│ │ ├── operationStore.ts # 农事状态
│ │ ├── assetStore.ts # 资产状态
│ │ ├── aiModelStore.ts # AI模型状态
│ │ ├── irrigationStore.ts # 灌溉状态
│ │ └── configStore.ts # 配置状态
│ ├── services/ # API 服务层
│ │ ├── api/ # API 配置和请求
│ │ │ ── client.ts # Axios 配置
│ │ │ ├── machineryApi.ts
│ │ ├── fieldApi.ts
│ │ └── ...
│ │ ├── mock/ # Mock 数据管理
│ │ │ ├── handlers/ # MSW 处理器
│ │ │ ├── data/ # Mock 数据
│ │ │ └── browser.ts # MSW 配置
│ │ └── types/ # API 类型定义
│ │ ├── machinery.ts
│ │ ├── field.ts
│ │ └── ...
│ ├── hooks/ # 自定义 Hooks
│ │ ├── useAuth.ts
│ │ ├── useMachinery.ts
│ │ └── ...
│ ├── utils/ # 工具函数
│ │ ├── date.ts
│ │ ├── format.ts
│ │ └── ...
│ ├── constants/ # 常量定义
│ │ ├── routes.ts
│ │ ├── permissions.ts
│ │ └── ...
│ ├── router/ # 路由配置
│ │ ├── index.ts # 路由器配置
│ │ ├── authRoutes.ts # 认证路由
│ │ ├── machineryRoutes.ts # 农机路由
│ │ └── ...
│ ├── styles/ # 样式文件
│ │ ├── globals.css
│ │ └── components.css
│ │ ├── services/ # API 服务层
│ │ │ ├── api/ # API 配置和请求
│ │ │ │ ├── client.ts
│ │ ├── machineryApi.ts
│ │ └── ...
│ │ │ ├── mock/ # Mock 数据管理
├── handlers/
│ │ ├── data/
│ │ │ │ └── browser.ts
│ │ │ └── types/
│ │ │ ├── machinery.ts
│ │ │ └── ...
│ │ ├── hooks/ # 自定义 Hooks
│ │ │ ├── useAuth.ts
│ │ │ └── useMachinery.ts
│ ├── utils/ # 工具函数
│ │ │ ├── date.ts
│ │ │ ── format.ts
│ │ └── constants/ # 常量定义
│ │ ├── routes.ts
│ │ └── permissions.ts
│ ├── types/ # 全局类型定义
│ │ ├── auth.ts
│ │ ├── machinery.ts
│ │ ── navigation.ts
│ └── ...
├── App.tsx # 根组件
│ └── main.tsx # 应用入口
│ │ ── navigation.ts
│ └── styles/ # 样式文件
└── globals.css
├── tests/ # 测试文件
│ ├── __mocks__/ # 全局 Mock
│ ├── fixtures/ # 测试数据
│ ├── unit/ # 单元测试
│ ├── integration/ # 集成测试
│ └── setup.ts # 测试配置
│ ├── __mocks__/
│ ├── fixtures/
│ ├── unit/
│ ├── integration/
│ └── setup.ts
├── docs/ # 项目文档
├── .eslintrc.js # ESLint 配置
├── .prettierrc # Prettier 配置
├── next.config.js # Next.js 配置
├── package.json
├── vite.config.ts
├── tsconfig.json
├── tailwind.config.js
└── README.md
```
### 路由系统设计
### Next.js 动态路由系统设计
#### App Router 架构
Next.js App Router 提供了基于文件系统的路由,支持动态路由、嵌套路由和路由组。
#### 路由架构
```typescript
// router/index.ts
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { ProtectedRoute } from '../components/ProtectedRoute'
import { Layout } from '../components/layout/Layout'
import { authRoutes } from './authRoutes'
import { machineryRoutes } from './machineryRoutes'
// ... 其他路由
// src/app/layout.tsx - 根布局
import { AuthProvider } from '@/lib/providers/AuthProvider'
import { ThemeProvider } from '@/lib/providers/ThemeProvider'
import './globals.css'
export const router = createBrowserRouter([
// 公开路由
...authRoutes,
// 受保护的主路由
{
path: '/',
element: (
<ProtectedRoute>
<Layout />
</ProtectedRoute>
),
children: [
// 7大业务系统路由
...machineryRoutes,
...fieldRoutes,
...operationRoutes,
...assetRoutes,
...aiModelRoutes,
...irrigationRoutes,
...configRoutes,
// 默认路由
{
index: true,
element: <Navigate to="/machinery/archive/entry" replace />
}
]
},
// 404页面
{ path: '*', element: <NotFoundPage /> }
])
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="zh-CN">
<body>
<ThemeProvider>
<AuthProvider>
{children}
</AuthProvider>
</ThemeProvider>
</body>
</html>
)
}
```
#### 业务路由示例
#### 动态路由示例
##### 1. 农机管理模块路由结构
```
src/app/machinery/
├── layout.tsx # 农机模块专属布局
├── page.tsx # /machinery - 农机管理首页
├── archive/
│ ├── page.tsx # /machinery/archive - 档案管理
│ ├── entry/
│ │ └── page.tsx # /machinery/archive/entry - 档案录入
│ └── [id]/
│ └── page.tsx # /machinery/archive/[id] - 动态详情页
├── driver/
│ ├── page.tsx # /machinery/driver - 驾驶员管理
│ └── [driverId]/
│ └── page.tsx # /machinery/driver/[driverId] - 驾驶员详情
└── monitoring/
└── realtime/
└── page.tsx # /machinery/monitoring/realtime - 实时监控
```
##### 2. 动态路由组件实现
```typescript
// router/machineryRoutes.ts
import { lazy } from 'react'
// src/app/machinery/archive/[id]/page.tsx
import { notFound } from 'next/navigation'
import { MachineryDetailPage } from '@/components/pages/machinery/MachineryDetailPage'
import { getMachineryById } from '@/lib/services/api/machineryApi'
// 懒加载页面组件
const MachineryListPage = lazy(() => import('../pages/machinery/MachineryListPage'))
const MachineryDetailPage = lazy(() => import('../pages/machinery/MachineryDetailPage'))
const DriverListPage = lazy(() => import('../pages/machinery/DriverListPage'))
interface Props {
params: { id: string }
}
export const machineryRoutes = [
{
path: 'machinery/*',
children: [
// 农机档案管理
{
path: 'archive/entry',
element: <MachineryListPage />
},
{
path: 'archive/detail/:id',
element: <MachineryDetailPage />
},
export default async function MachineryDetail({ params }: Props) {
const machinery = await getMachineryById(params.id)
// 驾驶员管理
{
path: 'driver/list',
element: <DriverListPage />
},
// 实时监控
{
path: 'monitoring/realtime',
element: lazy(() => import('../pages/machinery/MonitoringPage'))
},
// 任务调度
{
path: 'scheduling/task',
element: lazy(() => import('../pages/machinery/SchedulingPage'))
}
]
if (!machinery) {
notFound()
}
]
return (
<div className="container mx-auto p-6">
<MachineryDetailPage machinery={machinery} />
</div>
)
}
// 生成静态路径可选用于SSG
export async function generateStaticParams() {
// 预生成一些常见的农机详情页
return [
{ id: 'machinery-001' },
{ id: 'machinery-002' },
{ id: 'machinery-003' },
]
}
```
##### 3. 路由组的使用
```
src/app/
├── (auth)/ # 路由组不影响URL路径
│ ├── layout.tsx # 认证页面专属布局
│ ├── login/
│ │ └── page.tsx # /login
│ └── register/
│ └── page.tsx # /register
├── (dashboard)/ # 路由组:受保护的管理区域
│ ├── layout.tsx # 仪表板布局
│ ├── machinery/
│ ├── field/
│ └── config/
```
##### 4. 路由布局系统
```typescript
// src/app/(dashboard)/layout.tsx
import { SidebarProvider } from '@/lib/providers/SidebarProvider'
import { MainLayout } from '@/components/layout/MainLayout'
import { auth } from '@/lib/auth'
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
// 服务端认证检查
const session = await auth()
if (!session) {
redirect('/login')
}
return (
<SidebarProvider>
<MainLayout>
{children}
</MainLayout>
</SidebarProvider>
)
}
```
#### 动态路由特性
##### 1. 路由参数处理
```typescript
// src/app/config/tenant/[enterpriseId]/page.tsx
interface PageProps {
params: { enterpriseId: string }
searchParams: { [key: string]: string | string[] | undefined }
}
export default async function EnterpriseDetail({
params,
searchParams,
}: PageProps) {
const enterpriseId = params.enterpriseId
const tab = searchParams.tab as string || 'basic'
// 根据查询参数显示不同tab
return (
<div>
<h1>企业详情:{enterpriseId}</h1>
<EnterpriseDetailTab activeTab={tab} enterpriseId={enterpriseId} />
</div>
)
}
```
##### 2. 平行路由和插槽
```typescript
// src/app/machinery/layout.tsx
export default function MachineryLayout({
children,
analytics,
monitoring, // 插槽
}: {
children: React.ReactNode
analytics?: React.ReactNode
monitoring?: React.ReactNode
}) {
return (
<div className="flex h-full">
<div className="flex-1">{children}</div>
{analytics && (
<div className="w-80 border-l">{analytics}</div>
)}
{monitoring && (
<div className="w-80 border-l">{monitoring}</div>
)}
</div>
)
}
```
##### 3. 路由中间件
```typescript
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { auth } from './lib/auth'
export async function middleware(request: NextRequest) {
const session = await auth()
const { pathname } = request.nextUrl
// 未登录用户重定向到登录页
if (!session && pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
// 已登录用户访问登录页重定向到仪表板
if (session && pathname === '/login') {
return NextResponse.redirect(new URL('/dashboard', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/login', '/register']
}
```
#### 服务端组件优势
##### 1. 数据获取
```typescript
// src/app/machinery/page.tsx - 服务端组件
import { getMachineryList } from '@/lib/services/api/machineryApi'
import { MachineryGrid } from '@/components/business/machinery/MachineryGrid'
export default async function MachineryPage() {
// 服务端直接获取数据
const machineryData = await getMachineryList()
return (
<div>
<h1>农机管理系统</h1>
<MachineryGrid initialData={machineryData} />
</div>
)
}
```
##### 2. 缓存和重新验证
```typescript
// src/lib/services/api/machineryApi.ts
export async function getMachineryList() {
const res = await fetch('/api/machinery', {
next: {
tags: ['machinery'], // 缓存标签
revalidate: 60, // 60秒重新验证
}
})
if (!res.ok) {
throw new Error('Failed to fetch machinery data')
}
return res.json()
}
```
### 状态管理架构