# 管理后台开发规范 ## 版本信息 | 版本 | 日期 | 描述 | 作者 | |------|------|------|------| | 1.0 | 2025-10-16 | 初始版本,基于现有管理后台实现 | Winston | ## 概述 本文档定义了出行服务项目管理后台的开发标准和最佳实践,确保所有管理后台功能开发的一致性和可维护性。 ## 技术栈要求 ### 核心框架 - **React**: 19.1.0+,使用函数组件和Hooks - **TypeScript**: 严格模式,类型安全优先 - **React Router**: v7,声明式路由管理 ### 状态管理 - **@tanstack/react-query**: 服务端状态管理 - **React Context**: 本地状态和全局状态 - **React Hook Form**: 表单状态管理 ### UI组件库 - **shadcn/ui**: 基于Radix UI的组件库 - **Tailwind CSS**: 4.1.11+,原子化样式 - **Lucide React**: 图标库 ### 开发工具 - **Vite**: 7.0.0+,构建工具 - **Zod**: 表单验证和类型定义 - **Sonner**: Toast通知 ## 页面开发规范 ### 页面结构标准 每个管理后台页面应遵循以下结构: ```typescript import React, { useState, useMemo } from 'react'; import { useQuery, useMutation } from '@tanstack/react-query'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { toast } from 'sonner'; // 1. 导入必要的组件和工具 import { Button } from '@/client/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/client/components/ui/card'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/client/components/ui/table'; // 2. 定义类型(使用后端Schema生成的类型) type EntityResponse = InferResponseType['data'][0]; // 3. 页面组件定义 export const EntityPage = () => { // 4. 状态管理 const [searchParams, setSearchParams] = useState({ page: 1, limit: 10, keyword: '' }); // 5. 数据获取 const { data, isLoading, refetch } = useQuery({ queryKey: ['entities', searchParams], queryFn: async () => { const res = await entityClient.$get({ query: searchParams }); if (res.status !== 200) throw new Error('获取数据失败'); return await res.json(); } }); // 6. 渲染逻辑 return (
{/* 页面标题和操作按钮 */}

实体管理

{/* 内容区域 */} 实体列表 {/* 表格或列表内容 */}
); }; ``` ### 数据表格规范 #### 表格结构要求 ```typescript // 标准表格结构 ID 名称 状态 操作 {data?.data?.map((item) => ( {item.id} {item.name} {item.status === 'active' ? '启用' : '禁用'}
))}
``` #### 分页组件使用 ```typescript // 使用标准分页组件 setSearchParams(prev => ({ ...prev, page, limit }))} /> ``` ### 表单处理规范 #### 表单验证 ```typescript // 使用Zod Schema进行表单验证 const formSchema = z.object({ name: z.string().min(1, '名称不能为空'), email: z.string().email('请输入有效的邮箱地址'), phone: z.string().optional(), }); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { name: '', email: '', phone: '', }, }); ``` #### 表单提交 ```typescript // 标准表单提交处理 const handleSubmit = async (data: FormData) => { try { const res = await entityClient.$post({ json: data }); if (res.status !== 201) throw new Error('创建失败'); toast.success('创建成功'); refetch(); // 重新获取数据 } catch { toast.error('操作失败,请重试'); } }; ``` ## 搜索和筛选规范 ### 搜索功能 ```typescript // 防抖搜索实现 const debounce = (func: Function, delay: number) => { let timeoutId: NodeJS.Timeout; return (...args: any[]) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func(...args), delay); }; }; const debouncedSearch = useCallback( debounce((keyword: string) => { setSearchParams(prev => ({ ...prev, keyword, page: 1 })); }, 300), [] ); ``` ### 高级筛选 ```typescript // 筛选状态管理 const [filters, setFilters] = useState({ status: undefined as string | undefined, category: [] as number[], dateRange: undefined as { start?: string; end?: string } | undefined }); // 筛选条件显示 const hasActiveFilters = useMemo(() => { return filters.status !== undefined || filters.category.length > 0 || filters.dateRange !== undefined; }, [filters]); ``` ## 权限控制规范 ### 基于角色的访问控制 ```typescript // 权限检查Hook const usePermission = () => { const { user } = useAuth(); const hasPermission = (permission: string) => { return user?.roles?.some(role => role.permissions.includes(permission) ) ?? false; }; return { hasPermission }; }; // 页面级别权限控制 const ProtectedPage = () => { const { hasPermission } = usePermission(); if (!hasPermission('page:entity:view')) { return ; } return ; }; ``` ### 操作级别权限控制 ```typescript // 条件渲染操作按钮 {hasPermission('entity:create') && ( )} {hasPermission('entity:delete') && ( )} ``` ## 用户体验规范 ### 加载状态处理 ```typescript // 表格骨架屏 const renderTableSkeleton = () => (
{Array.from({ length: 5 }).map((_, index) => (
))}
); // 使用 {isLoading ? renderTableSkeleton() : renderTableContent()} ``` ### 错误处理 ```typescript // 统一错误处理 const handleOperation = async (operation: () => Promise) => { try { await operation(); toast.success('操作成功'); } catch (error) { console.error('操作失败:', error); toast.error('操作失败,请重试'); } }; ``` ### 确认对话框 ```typescript // 删除确认对话框 const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); const handleDelete = (id: number) => { setItemToDelete(id); setDeleteDialogOpen(true); }; const confirmDelete = async () => { if (!itemToDelete) return; await handleOperation(async () => { const res = await entityClient[':id'].$delete({ param: { id: itemToDelete } }); if (res.status !== 204) throw new Error('删除失败'); }); setDeleteDialogOpen(false); setItemToDelete(null); }; ``` ## 组件使用规范 ### shadcn/ui组件使用 #### 按钮组件 ```typescript // 标准按钮使用 ``` #### 表单组件 ```typescript // 表单字段标准结构 ( 字段标签 )} /> ``` #### 对话框组件 ```typescript // 标准对话框使用 对话框标题 对话框描述 {/* 对话框内容 */} ``` ### 自定义组件开发 #### 组件命名规范 - 使用PascalCase命名 - 文件名与组件名一致 - 导出命名组件 #### 组件Props定义 ```typescript interface CustomComponentProps { value?: string; onChange?: (value: string) => void; placeholder?: string; disabled?: boolean; className?: string; } export const CustomComponent: React.FC = ({ value, onChange, placeholder, disabled = false, className }) => { // 组件实现 }; ``` ## 响应式设计规范 ### 移动端适配 ```typescript // 使用Tailwind响应式类
{/* 内容 */}
// 移动端菜单 {/* 移动端菜单内容 */} ``` ### 布局规范 - 桌面端:侧边栏 + 主内容区 - 移动端:汉堡菜单 + 全屏内容 - 断点:sm(640px), md(768px), lg(1024px), xl(1280px) ## 性能优化规范 ### 代码分割 ```typescript // 使用React.lazy进行代码分割 const LazyComponent = React.lazy(() => import('./LazyComponent')); // 在路由中使用 加载中...}> ``` ### 数据缓存 ```typescript // React Query缓存配置 const { data } = useQuery({ queryKey: ['entities', searchParams], queryFn: fetchEntities, staleTime: 5 * 60 * 1000, // 5分钟 cacheTime: 10 * 60 * 1000, // 10分钟 }); ``` ## 测试规范 ### 组件测试 ```typescript // 使用Testing Library进行组件测试 import { render, screen, fireEvent } from '@testing-library/react'; import { EntityPage } from './EntityPage'; describe('EntityPage', () => { it('should render entity list', () => { render(); expect(screen.getByText('实体管理')).toBeInTheDocument(); }); }); ``` ### E2E测试 ```typescript // 使用Playwright进行E2E测试 test('should create new entity', async ({ page }) => { await page.goto('/admin/entities'); await page.click('button:has-text("创建实体")'); await page.fill('input[name="name"]', '测试实体'); await page.click('button:has-text("创建")'); await expect(page.locator('text=创建成功')).toBeVisible(); }); ``` ## 代码质量规范 ### 代码风格 - 使用ESLint + Prettier进行代码格式化 - 遵循TypeScript严格模式 - 使用函数组件和Hooks - 避免使用any类型 ### 文件组织 ```text src/client/admin/ ├── components/ # 管理后台专用组件 ├── hooks/ # 管理后台Hooks ├── layouts/ # 布局组件 ├── pages/ # 页面组件 ├── utils/ # 工具函数 └── types/ # 类型定义 ``` ## 部署和构建规范 ### 环境变量 ```bash # 前端环境变量 VITE_API_BASE_URL=http://localhost:3000/api VITE_APP_NAME=管理后台 ``` ### 构建配置 ```typescript // vite.config.ts export default defineConfig({ build: { rollupOptions: { output: { manualChunks: { vendor: ['react', 'react-dom'], ui: ['@/client/components/ui'] } } } } }); ``` --- **文档状态**: 正式版 **下次评审**: 2025-11-16 **维护者**: Winston 🏗️