提交1 bmad搭建与项目启动 - ok
This commit is contained in:
779
docs/Pages目录结构与开发规范.md
Normal file
779
docs/Pages目录结构与开发规范.md
Normal file
@@ -0,0 +1,779 @@
|
||||
# Pages目录结构与开发规范
|
||||
|
||||
## 1. 目录结构规范
|
||||
|
||||
### 1.1 页面目录标准结构
|
||||
|
||||
每个页面目录采用以下标准结构:
|
||||
|
||||
```
|
||||
pages/ModuleName/SubModuleName/
|
||||
├── 📄 index.jsx # 页面主组件
|
||||
├── 📂 components/ # 页面子组件目录
|
||||
│ ├── 📂 Component1/ # 子组件1(拆分的大组件)
|
||||
│ │ ├── 📄 index.jsx # 子组件主文件
|
||||
│ │ ├── 📄 Component1.jsx # 子组件实现
|
||||
│ │ ├── 📄 index.css # 子组件样式
|
||||
│ │ └── 📄 types.ts # 子组件类型定义
|
||||
│ ├── 📂 Component2/ # 子组件2
|
||||
│ │ └── ...
|
||||
│ └── 📂 common/ # 页面通用组件
|
||||
│ ├── 📄 Header.jsx
|
||||
│ ├── 📄 Footer.jsx
|
||||
│ └── ...
|
||||
├── 📄 index.css # 页面主样式文件
|
||||
├── 📄 index.types.ts # 页面类型定义
|
||||
├── 📄 hooks/ # 页面专用Hooks
|
||||
│ ├── 📄 usePageData.tsx
|
||||
│ └── 📄 usePageActions.tsx
|
||||
├── 📄 utils/ # 页面专用工具函数
|
||||
│ ├── 📄 pageHelpers.tsx
|
||||
│ └── 📄 formatters.tsx
|
||||
└── 📄 constants.tsx # 页面常量定义
|
||||
```
|
||||
|
||||
### 1.2 组件拆分原则
|
||||
|
||||
**拆分条件:**
|
||||
1. 组件代码超过100行
|
||||
2. 组件承担多个职责
|
||||
3. 组件需要复用
|
||||
4. 组件逻辑复杂(包含多个useState或useEffect)
|
||||
|
||||
**拆分命名:**
|
||||
- 主组件:保持原名称(如:MachineryEntry)
|
||||
- 子组件:基于功能命名(如:MachineryList、MachineryForm、MachineryFilter)
|
||||
- 通用组件:基于用途命名(如:TableHeader、FormActions)
|
||||
|
||||
## 2. 开发规范
|
||||
|
||||
### 2.1 组件开发规范
|
||||
|
||||
#### 2.1.1 主组件规范
|
||||
|
||||
```jsx
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/index.jsx
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { MachineryList } from './components/MachineryList';
|
||||
import { MachineryForm } from './components/MachineryForm';
|
||||
import { MachineryFilter } from './components/MachineryFilter';
|
||||
import { useMachineryData } from './hooks/usePageData';
|
||||
import { useMachineryActions } from './hooks/usePageActions';
|
||||
import './index.css';
|
||||
|
||||
export function MachineryEntry() {
|
||||
const {
|
||||
machinery,
|
||||
loading,
|
||||
error,
|
||||
filters,
|
||||
pagination,
|
||||
handleFilterChange,
|
||||
handlePageChange,
|
||||
refreshData
|
||||
} = useMachineryData();
|
||||
|
||||
const {
|
||||
handleCreate,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleBatchDelete,
|
||||
handleExport
|
||||
} = useMachineryActions(refreshData);
|
||||
|
||||
return (
|
||||
<div className="machinery-entry">
|
||||
<div className="page-header">
|
||||
<h1>农机档案管理</h1>
|
||||
<div className="page-actions">
|
||||
<button onClick={handleCreate}>新增农机</button>
|
||||
<button onClick={handleExport}>导出数据</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MachineryFilter
|
||||
filters={filters}
|
||||
onFilterChange={handleFilterChange}
|
||||
/>
|
||||
|
||||
<MachineryList
|
||||
machinery={machinery}
|
||||
loading={loading}
|
||||
error={error}
|
||||
pagination={pagination}
|
||||
onPageChange={handlePageChange}
|
||||
onEdit={handleEdit}
|
||||
onDelete={handleDelete}
|
||||
onBatchDelete={handleBatchDelete}
|
||||
/>
|
||||
|
||||
<MachineryForm />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.1.2 子组件规范
|
||||
|
||||
```jsx
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/components/MachineryList/index.jsx
|
||||
import { memo } from 'react';
|
||||
import { MachineryTable } from './MachineryTable';
|
||||
import { TableActions } from './TableActions';
|
||||
import { useMachineryList } from '../hooks/usePageData';
|
||||
import { MachineryRecord } from '../types';
|
||||
import './index.css';
|
||||
|
||||
interface MachineryListProps {
|
||||
machinery: MachineryRecord[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
pagination: {
|
||||
current: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
};
|
||||
onPageChange: (page: number) => void;
|
||||
onEdit: (record: MachineryRecord) => void;
|
||||
onDelete: (id: string) => void;
|
||||
onBatchDelete: (ids: string[]) => void;
|
||||
}
|
||||
|
||||
export const MachineryList = memo<MachineryListProps>(({
|
||||
machinery,
|
||||
loading,
|
||||
error,
|
||||
pagination,
|
||||
onPageChange,
|
||||
onEdit,
|
||||
onDelete,
|
||||
onBatchDelete
|
||||
}) => {
|
||||
const {
|
||||
selectedRows,
|
||||
handleRowSelection,
|
||||
handleSelectAll,
|
||||
handleBatchActions
|
||||
} = useMachineryList(machinery);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="error-state">
|
||||
<p>加载失败:{error}</p>
|
||||
<button onClick={() => window.location.reload()}>
|
||||
重新加载
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="machinery-list">
|
||||
<TableActions
|
||||
selectedRows={selectedRows}
|
||||
onBatchDelete={handleBatchDelete}
|
||||
onRefresh={() => onPageChange(pagination.current)}
|
||||
/>
|
||||
|
||||
<MachineryTable
|
||||
data={machinery}
|
||||
loading={loading}
|
||||
selectedRows={selectedRows}
|
||||
onRowSelection={handleRowSelection}
|
||||
onSelectAll={handleSelectAll}
|
||||
onEdit={onEdit}
|
||||
onDelete={onDelete}
|
||||
pagination={pagination}
|
||||
onPageChange={onPageChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
MachineryList.displayName = 'MachineryList';
|
||||
```
|
||||
|
||||
### 2.2 类型定义规范
|
||||
|
||||
#### 2.2.1 页面类型定义
|
||||
|
||||
```typescript
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/index.types.ts
|
||||
export interface MachineryRecord {
|
||||
id: string;
|
||||
name: string;
|
||||
model: string;
|
||||
category: MachineryCategory;
|
||||
status: MachineryStatus;
|
||||
manufacturer: string;
|
||||
purchaseDate: string;
|
||||
price: number;
|
||||
// ... 其他字段
|
||||
}
|
||||
|
||||
export type MachineryCategory =
|
||||
| '耕地机械'
|
||||
| '播种机械'
|
||||
| '收获机械'
|
||||
| '植保机械';
|
||||
|
||||
export type MachineryStatus =
|
||||
| '运行中'
|
||||
| '空闲中'
|
||||
| '待维护'
|
||||
| '已报废';
|
||||
|
||||
export interface MachineryFilters {
|
||||
category?: MachineryCategory;
|
||||
status?: MachineryStatus;
|
||||
manufacturer?: string;
|
||||
dateRange?: [string, string];
|
||||
}
|
||||
|
||||
export interface PaginationState {
|
||||
current: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.2 组件类型定义
|
||||
|
||||
```typescript
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/components/MachineryList/types.ts
|
||||
import { MachineryRecord, MachineryFilters, PaginationState } from '../../index.types';
|
||||
|
||||
export interface MachineryListProps {
|
||||
machinery: MachineryRecord[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
filters: MachineryFilters;
|
||||
pagination: PaginationState;
|
||||
onPageChange: (page: number) => void;
|
||||
onEdit: (record: MachineryRecord) => void;
|
||||
onDelete: (id: string) => void;
|
||||
onBatchDelete: (ids: string[]) => void;
|
||||
}
|
||||
|
||||
export interface SelectedRow {
|
||||
id: string;
|
||||
name: string;
|
||||
// ... 其他需要显示在选中行的字段
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 Hooks规范
|
||||
|
||||
#### 2.3.1 页面数据Hook
|
||||
|
||||
```javascript
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/hooks/usePageData.js
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { getMachineryList, deleteMachinery } from '@/apis/subModules/agriculturalMachinery';
|
||||
import { showMessage } from '@/utils/message';
|
||||
|
||||
export function useMachineryData() {
|
||||
const [machinery, setMachinery] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [filters, setFilters] = useState({});
|
||||
const [pagination, setPagination] = useState({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
});
|
||||
|
||||
// 获取数据
|
||||
const fetchMachinery = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const params = {
|
||||
...filters,
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize
|
||||
};
|
||||
|
||||
const response = await getMachineryList(params);
|
||||
setMachinery(response.data.list);
|
||||
setPagination(prev => ({
|
||||
...prev,
|
||||
total: response.data.total
|
||||
}));
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
showMessage('error', '获取农机数据失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [filters, pagination.current, pagination.pageSize]);
|
||||
|
||||
// 初始加载
|
||||
useEffect(() => {
|
||||
fetchMachinery();
|
||||
}, [fetchMachinery]);
|
||||
|
||||
// 处理筛选变化
|
||||
const handleFilterChange = useCallback((newFilters) => {
|
||||
setFilters(newFilters);
|
||||
setPagination(prev => ({ ...prev, current: 1 }));
|
||||
}, []);
|
||||
|
||||
// 处理分页变化
|
||||
const handlePageChange = useCallback((page) => {
|
||||
setPagination(prev => ({ ...prev, current: page }));
|
||||
}, []);
|
||||
|
||||
return {
|
||||
machinery,
|
||||
loading,
|
||||
error,
|
||||
filters,
|
||||
pagination,
|
||||
handleFilterChange,
|
||||
handlePageChange,
|
||||
refreshData: fetchMachinery
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3.2 页面操作Hook
|
||||
|
||||
```javascript
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/hooks/usePageActions.js
|
||||
import { useCallback } from 'react';
|
||||
import { deleteMachinery, updateMachinery } from '@/apis/subModules/agriculturalMachinery';
|
||||
import { showMessage } from '@/utils/message';
|
||||
|
||||
export function useMachineryActions(refreshData) {
|
||||
// 删除农机
|
||||
const handleDelete = useCallback(async (id) => {
|
||||
try {
|
||||
await deleteMachinery(id);
|
||||
showMessage('success', '删除成功');
|
||||
refreshData();
|
||||
} catch (error) {
|
||||
showMessage('error', '删除失败');
|
||||
}
|
||||
}, [refreshData]);
|
||||
|
||||
// 编辑农机
|
||||
const handleEdit = useCallback(async (data) => {
|
||||
try {
|
||||
await updateMachinery(data.id, data);
|
||||
showMessage('success', '更新成功');
|
||||
refreshData();
|
||||
} catch (error) {
|
||||
showMessage('error', '更新失败');
|
||||
}
|
||||
}, [refreshData]);
|
||||
|
||||
// 批量删除
|
||||
const handleBatchDelete = useCallback(async (ids) => {
|
||||
try {
|
||||
await Promise.all(ids.map(id => deleteMachinery(id)));
|
||||
showMessage('success', '批量删除成功');
|
||||
refreshData();
|
||||
} catch (error) {
|
||||
showMessage('error', '批量删除失败');
|
||||
}
|
||||
}, [refreshData]);
|
||||
|
||||
// 导出数据
|
||||
const handleExport = useCallback(() => {
|
||||
// 实现导出逻辑
|
||||
console.log('导出数据');
|
||||
}, []);
|
||||
|
||||
return {
|
||||
handleDelete,
|
||||
handleEdit,
|
||||
handleBatchDelete,
|
||||
handleExport
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 样式规范
|
||||
|
||||
#### 2.4.1 页面主样式
|
||||
|
||||
```css
|
||||
/* pages/AgriculturalMachinery/Archive/MachineryEntry/index.css */
|
||||
.machinery-entry {
|
||||
padding: 24px;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.page-actions button {
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d9d9d9;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.page-actions button:hover {
|
||||
background: #f0f0f0;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
|
||||
.page-actions button.primary {
|
||||
background: #40a9ff;
|
||||
color: white;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
|
||||
.page-actions button.primary:hover {
|
||||
background: #1890ff;
|
||||
border-color: #1890ff;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4.2 组件样式
|
||||
|
||||
```css
|
||||
/* pages/AgriculturalMachinery/Archive/MachineryEntry/components/MachineryList/index.css */
|
||||
.machinery-list {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.error-state {
|
||||
padding: 48px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.error-state p {
|
||||
margin-bottom: 16px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.error-state button {
|
||||
padding: 8px 16px;
|
||||
background: #ff4d4f;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.error-state button:hover {
|
||||
background: #ff7875;
|
||||
}
|
||||
|
||||
.table-actions {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.selected-info {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.batch-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.batch-actions button {
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d9d9d9;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.batch-actions button:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
.batch-actions button.danger {
|
||||
color: #ff4d4f;
|
||||
border-color: #ff4d4f;
|
||||
}
|
||||
|
||||
.batch-actions button.danger:hover {
|
||||
background: #ff4d4f;
|
||||
color: white;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 工具函数规范
|
||||
|
||||
#### 2.5.1 页面工具函数
|
||||
|
||||
```javascript
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/utils/pageHelpers.js
|
||||
import dayjs from 'dayjs';
|
||||
import { formatCurrency } from '@/utils/formatters';
|
||||
|
||||
/**
|
||||
* 格式化农机状态
|
||||
*/
|
||||
export function formatMachineryStatus(status) {
|
||||
const statusMap = {
|
||||
'运行中': { text: '运行中', color: '#52c41a' },
|
||||
'空闲中': { text: '空闲中', color: '#d9d9d9' },
|
||||
'待维护': { text: '待维护', color: '#faad14' },
|
||||
'已报废': { text: '已报废', color: '#ff4d4f' }
|
||||
};
|
||||
|
||||
return statusMap[status] || { text: '未知', color: '#d9d9d9' };
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
*/
|
||||
export function formatDate(date) {
|
||||
return dayjs(date).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化价格
|
||||
*/
|
||||
export function formatPrice(price) {
|
||||
return formatCurrency(price);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成农机二维码内容
|
||||
*/
|
||||
export function generateQRCode(machinery) {
|
||||
return JSON.stringify({
|
||||
id: machinery.id,
|
||||
name: machinery.name,
|
||||
model: machinery.model,
|
||||
category: machinery.category,
|
||||
manufacturer: machinery.manufacturer
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.5.2 格式化工具
|
||||
|
||||
```javascript
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/utils/formatters.js
|
||||
/**
|
||||
* 格式化货币
|
||||
*/
|
||||
export function formatCurrency(amount) {
|
||||
return new Intl.NumberFormat('zh-CN', {
|
||||
style: 'currency',
|
||||
currency: 'CNY'
|
||||
}).format(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化数字
|
||||
*/
|
||||
export function formatNumber(num, precision = 2) {
|
||||
return new Intl.NumberFormat('zh-CN', {
|
||||
minimumFractionDigits: precision,
|
||||
maximumFractionDigits: precision
|
||||
}).format(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化百分比
|
||||
*/
|
||||
export function formatPercent(value) {
|
||||
return `${(value * 100).toFixed(1)}%`;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 常量定义规范
|
||||
|
||||
```javascript
|
||||
// pages/AgriculturalMachinery/Archive/MachineryEntry/constants.js
|
||||
export const MACHINERY_CATEGORIES = [
|
||||
{ value: '耕地机械', label: '耕地机械' },
|
||||
{ value: '播种机械', label: '播种机械' },
|
||||
{ value: '收获机械', label: '收获机械' },
|
||||
{ value: '植保机械', label: '植保机械' }
|
||||
];
|
||||
|
||||
export const MACHINERY_STATUS = [
|
||||
{ value: '运行中', label: '运行中', color: '#52c41a' },
|
||||
{ value: '空闲中', label: '空闲中', color: '#d9d9d9' },
|
||||
{ value: '待维护', label: '待维护', color: '#faad14' },
|
||||
{ value: '已报废', label: '已报废', color: '#ff4d4f' }
|
||||
];
|
||||
|
||||
export const MANUFACTURERS = [
|
||||
'约翰迪尔',
|
||||
'久保田',
|
||||
'福田雷沃',
|
||||
'中国一拖',
|
||||
'时风集团'
|
||||
];
|
||||
|
||||
export const PAGE_SIZE_OPTIONS = [10, 20, 50, 100];
|
||||
export const DEFAULT_PAGE_SIZE = 10;
|
||||
```
|
||||
|
||||
## 3. 组件拆分示例
|
||||
|
||||
### 3.1 MachineryEntry 组件拆分
|
||||
|
||||
```
|
||||
MachineryEntry/
|
||||
├── index.jsx # 主组件
|
||||
├── index.css # 主样式
|
||||
├── index.types.ts # 主类型定义
|
||||
├── hooks/ # 页面Hooks
|
||||
│ ├── usePageData.js # 数据管理Hook
|
||||
│ └── usePageActions.js # 操作Hook
|
||||
├── utils/ # 工具函数
|
||||
│ ├── pageHelpers.js # 页面工具函数
|
||||
│ └── formatters.js # 格式化函数
|
||||
├── constants.js # 常量定义
|
||||
└── components/ # 子组件
|
||||
├── MachineryFilter/ # 筛选组件
|
||||
│ ├── index.jsx
|
||||
│ ├── index.css
|
||||
│ └── types.ts
|
||||
├── MachineryList/ # 列表组件
|
||||
│ ├── index.jsx
|
||||
│ ├── index.css
|
||||
│ ├── types.ts
|
||||
│ └── components/
|
||||
│ ├── MachineryTable/ # 表格组件
|
||||
│ │ ├── index.jsx
|
||||
│ │ ├── index.css
|
||||
│ │ └── types.ts
|
||||
│ └── TableActions/ # 表格操作组件
|
||||
│ ├── index.jsx
|
||||
│ ├── index.css
|
||||
│ └── types.ts
|
||||
├── MachineryForm/ # 表单组件
|
||||
│ ├── index.jsx
|
||||
│ ├── index.css
|
||||
│ ├── types.ts
|
||||
│ └── components/
|
||||
│ ├── BasicInfo/ # 基本信息表单
|
||||
│ ├── TechnicalInfo/ # 技术参数表单
|
||||
│ ├── PurchaseInfo/ # 购买信息表单
|
||||
│ └── InsuranceInfo/ # 保险信息表单
|
||||
└── common/ # 通用组件
|
||||
├── PageHeader/ # 页面头部
|
||||
├── LoadingSpinner/ # 加载动画
|
||||
└── EmptyState/ # 空状态
|
||||
```
|
||||
|
||||
## 4. 文件命名规范
|
||||
|
||||
### 4.1 组件文件命名
|
||||
|
||||
- **主组件**: 使用功能名称,如 `MachineryEntry.jsx`
|
||||
- **子组件**: 使用功能描述,如 `MachineryTable.jsx`
|
||||
- **通用组件**: 使用通用描述,如 `TableHeader.jsx`
|
||||
- **Hooks**: 以 `use` 开头,如 `usePageData.js`
|
||||
- **工具函数**: 使用动词或名词,如 `pageHelpers.js`, `formatters.js`
|
||||
- **类型文件**: 以 `.types.ts` 结尾,如 `index.types.ts`
|
||||
- **样式文件**: 与组件同名,如 `index.css`
|
||||
|
||||
### 4.2 目录命名
|
||||
|
||||
- **页面目录**: 使用业务模块名,如 `AgriculturalMachinery`
|
||||
- **组件目录**: 使用功能描述,如 `MachineryList`
|
||||
- **通用目录**: 使用通用描述,如 `common`
|
||||
|
||||
## 5. 开发流程
|
||||
|
||||
### 5.1 新页面开发流程
|
||||
|
||||
1. **创建页面目录结构**
|
||||
2. **定义类型接口** (index.types.ts)
|
||||
3. **开发主组件** (index.jsx)
|
||||
4. **拆分子组件** (components/)
|
||||
5. **创建Hooks** (hooks/)
|
||||
6. **编写工具函数** (utils/)
|
||||
7. **定义常量** (constants.js)
|
||||
8. **编写样式** (index.css)
|
||||
9. **单元测试**
|
||||
|
||||
### 5.2 组件拆分流程
|
||||
|
||||
1. **识别拆分点**: 组件代码复杂度、复用性、职责单一性
|
||||
2. **创建组件目录**: 创建 `components/ComponentName/` 目录
|
||||
3. **提取组件逻辑**: 将相关代码移动到新组件
|
||||
4. **定义Props接口**: 创建类型定义文件
|
||||
5. **处理状态管理**: 使用Hooks或状态提升
|
||||
6. **更新主组件**: 修改主组件使用新组件
|
||||
7. **样式分离**: 创建独立的样式文件
|
||||
8. **测试验证**: 确保功能正常
|
||||
|
||||
## 6. 质量保证
|
||||
|
||||
### 6.1 代码检查
|
||||
|
||||
- 使用ESLint检查代码规范
|
||||
- 使用Prettier格式化代码
|
||||
- 使用TypeScript进行类型检查
|
||||
- 组件必须有PropTypes或TypeScript接口
|
||||
|
||||
### 6.2 性能优化
|
||||
|
||||
- 使用React.memo包装组件避免不必要的重渲染
|
||||
- 使用useCallback和useMemo优化性能
|
||||
- 实现虚拟滚动处理大数据量
|
||||
- 使用懒加载和代码分割
|
||||
|
||||
### 6.3 可维护性
|
||||
|
||||
- 保持组件单一职责
|
||||
- 提取可复用的通用组件
|
||||
- 编写清晰的注释和文档
|
||||
- 保持一致的代码风格
|
||||
|
||||
这个规范为pages目录的开发提供了完整的指导,确保代码的可维护性、可扩展性和团队协作效率。
|
||||
Reference in New Issue
Block a user