599 lines
11 KiB
Markdown
599 lines
11 KiB
Markdown
|
|
# 宁夏智慧养殖监管平台代码规范
|
|||
|
|
|
|||
|
|
## 版本历史
|
|||
|
|
|
|||
|
|
| 版本 | 日期 | 修改内容 | 修改人 |
|
|||
|
|
|------|------|----------|--------|
|
|||
|
|
| v1.0 | 2024-01-20 | 初始版本,制定基础代码规范 | 开发团队 |
|
|||
|
|
|
|||
|
|
## 1. 概述
|
|||
|
|
|
|||
|
|
本文档规定了宁夏智慧养殖监管平台项目的代码编写规范,旨在提高代码质量、可读性和可维护性。
|
|||
|
|
|
|||
|
|
## 2. 通用规范
|
|||
|
|
|
|||
|
|
### 2.1 文件命名
|
|||
|
|
- **文件名**: 使用小写字母和连字符,如 `user-service.js`
|
|||
|
|
- **目录名**: 使用小写字母和连字符,如 `user-management`
|
|||
|
|
- **组件文件**: 使用 PascalCase,如 `UserProfile.vue`
|
|||
|
|
|
|||
|
|
### 2.2 编码格式
|
|||
|
|
- **字符编码**: UTF-8
|
|||
|
|
- **换行符**: LF (Unix)
|
|||
|
|
- **缩进**: 2个空格
|
|||
|
|
- **行尾**: 不允许有多余空格
|
|||
|
|
|
|||
|
|
### 2.3 注释规范
|
|||
|
|
```javascript
|
|||
|
|
/**
|
|||
|
|
* 函数功能描述
|
|||
|
|
* @param {string} param1 - 参数1描述
|
|||
|
|
* @param {number} param2 - 参数2描述
|
|||
|
|
* @returns {boolean} 返回值描述
|
|||
|
|
* @author 作者名
|
|||
|
|
* @since 版本号
|
|||
|
|
*/
|
|||
|
|
function exampleFunction(param1, param2) {
|
|||
|
|
// 单行注释说明
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 3. JavaScript/Node.js 规范
|
|||
|
|
|
|||
|
|
### 3.1 变量命名
|
|||
|
|
```javascript
|
|||
|
|
// 使用 camelCase
|
|||
|
|
const userName = 'admin';
|
|||
|
|
const userAge = 25;
|
|||
|
|
|
|||
|
|
// 常量使用 UPPER_SNAKE_CASE
|
|||
|
|
const MAX_RETRY_COUNT = 3;
|
|||
|
|
const API_BASE_URL = 'https://api.example.com';
|
|||
|
|
|
|||
|
|
// 私有变量使用下划线前缀
|
|||
|
|
const _privateVariable = 'private';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 函数定义
|
|||
|
|
```javascript
|
|||
|
|
// 优先使用箭头函数
|
|||
|
|
const getUserInfo = (userId) => {
|
|||
|
|
return userService.findById(userId);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 异步函数
|
|||
|
|
const fetchUserData = async (userId) => {
|
|||
|
|
try {
|
|||
|
|
const user = await userService.findById(userId);
|
|||
|
|
return user;
|
|||
|
|
} catch (error) {
|
|||
|
|
logger.error('获取用户数据失败', error);
|
|||
|
|
throw error;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 对象和数组
|
|||
|
|
```javascript
|
|||
|
|
// 对象属性换行
|
|||
|
|
const userConfig = {
|
|||
|
|
name: 'admin',
|
|||
|
|
role: 'administrator',
|
|||
|
|
permissions: ['read', 'write', 'delete'],
|
|||
|
|
settings: {
|
|||
|
|
theme: 'dark',
|
|||
|
|
language: 'zh-CN'
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 数组解构
|
|||
|
|
const [first, second, ...rest] = items;
|
|||
|
|
|
|||
|
|
// 对象解构
|
|||
|
|
const { name, age, ...otherProps } = user;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.4 错误处理
|
|||
|
|
```javascript
|
|||
|
|
// 统一错误处理
|
|||
|
|
const handleApiError = (error) => {
|
|||
|
|
if (error.response) {
|
|||
|
|
// 服务器响应错误
|
|||
|
|
logger.error('API响应错误', {
|
|||
|
|
status: error.response.status,
|
|||
|
|
data: error.response.data
|
|||
|
|
});
|
|||
|
|
} else if (error.request) {
|
|||
|
|
// 请求发送失败
|
|||
|
|
logger.error('请求发送失败', error.request);
|
|||
|
|
} else {
|
|||
|
|
// 其他错误
|
|||
|
|
logger.error('未知错误', error.message);
|
|||
|
|
}
|
|||
|
|
throw error;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4. Vue.js 规范
|
|||
|
|
|
|||
|
|
### 4.1 组件命名
|
|||
|
|
```javascript
|
|||
|
|
// 组件名使用 PascalCase
|
|||
|
|
export default {
|
|||
|
|
name: 'UserProfile',
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 文件名: UserProfile.vue
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 组件结构
|
|||
|
|
```vue
|
|||
|
|
<template>
|
|||
|
|
<div class="user-profile">
|
|||
|
|
<!-- 模板内容 -->
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import { ref, computed, onMounted } from 'vue'
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
name: 'UserProfile',
|
|||
|
|
props: {
|
|||
|
|
userId: {
|
|||
|
|
type: String,
|
|||
|
|
required: true
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
emits: ['update', 'delete'],
|
|||
|
|
setup(props, { emit }) {
|
|||
|
|
// 响应式数据
|
|||
|
|
const user = ref(null)
|
|||
|
|
|
|||
|
|
// 计算属性
|
|||
|
|
const displayName = computed(() => {
|
|||
|
|
return user.value ? user.value.name : '未知用户'
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 方法
|
|||
|
|
const loadUser = async () => {
|
|||
|
|
try {
|
|||
|
|
user.value = await userApi.getById(props.userId)
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('加载用户失败', error)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生命周期
|
|||
|
|
onMounted(() => {
|
|||
|
|
loadUser()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
user,
|
|||
|
|
displayName,
|
|||
|
|
loadUser
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.user-profile {
|
|||
|
|
padding: 16px;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 Props 定义
|
|||
|
|
```javascript
|
|||
|
|
props: {
|
|||
|
|
// 基础类型检查
|
|||
|
|
title: String,
|
|||
|
|
count: Number,
|
|||
|
|
isActive: Boolean,
|
|||
|
|
|
|||
|
|
// 复杂类型检查
|
|||
|
|
user: {
|
|||
|
|
type: Object,
|
|||
|
|
required: true,
|
|||
|
|
validator: (value) => {
|
|||
|
|
return value && typeof value.id === 'string'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 带默认值
|
|||
|
|
size: {
|
|||
|
|
type: String,
|
|||
|
|
default: 'medium',
|
|||
|
|
validator: (value) => {
|
|||
|
|
return ['small', 'medium', 'large'].includes(value)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.4 事件命名
|
|||
|
|
```javascript
|
|||
|
|
// 使用 kebab-case
|
|||
|
|
this.$emit('user-updated', userData)
|
|||
|
|
this.$emit('form-submitted', formData)
|
|||
|
|
|
|||
|
|
// 在模板中
|
|||
|
|
<UserForm @user-updated="handleUserUpdate" />
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5. CSS/SCSS 规范
|
|||
|
|
|
|||
|
|
### 5.1 类名命名
|
|||
|
|
```css
|
|||
|
|
/* 使用 BEM 命名法 */
|
|||
|
|
.user-profile {
|
|||
|
|
/* 块 */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.user-profile__header {
|
|||
|
|
/* 元素 */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.user-profile__header--large {
|
|||
|
|
/* 修饰符 */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.user-profile__avatar {
|
|||
|
|
/* 元素 */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.user-profile__avatar--round {
|
|||
|
|
/* 修饰符 */
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.2 样式组织
|
|||
|
|
```scss
|
|||
|
|
// 变量定义
|
|||
|
|
$primary-color: #1890ff;
|
|||
|
|
$success-color: #52c41a;
|
|||
|
|
$warning-color: #faad14;
|
|||
|
|
$error-color: #f5222d;
|
|||
|
|
|
|||
|
|
// 混入定义
|
|||
|
|
@mixin flex-center {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: center;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 组件样式
|
|||
|
|
.user-profile {
|
|||
|
|
padding: 16px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
background-color: #fff;
|
|||
|
|
|
|||
|
|
&__header {
|
|||
|
|
@include flex-center;
|
|||
|
|
margin-bottom: 16px;
|
|||
|
|
font-size: 18px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&__content {
|
|||
|
|
line-height: 1.6;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 6. API 接口规范
|
|||
|
|
|
|||
|
|
### 6.1 接口命名
|
|||
|
|
```javascript
|
|||
|
|
// RESTful API 命名
|
|||
|
|
GET /api/users // 获取用户列表
|
|||
|
|
GET /api/users/:id // 获取单个用户
|
|||
|
|
POST /api/users // 创建用户
|
|||
|
|
PUT /api/users/:id // 更新用户
|
|||
|
|
DELETE /api/users/:id // 删除用户
|
|||
|
|
|
|||
|
|
// 复杂操作使用动词
|
|||
|
|
POST /api/users/:id/reset-password // 重置密码
|
|||
|
|
POST /api/users/:id/change-status // 更改状态
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 请求响应格式
|
|||
|
|
```javascript
|
|||
|
|
// 统一响应格式
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "操作成功",
|
|||
|
|
"data": {
|
|||
|
|
// 具体数据
|
|||
|
|
},
|
|||
|
|
"timestamp": "2024-01-20T10:30:00Z"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 分页响应格式
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"message": "获取成功",
|
|||
|
|
"data": {
|
|||
|
|
"list": [...],
|
|||
|
|
"pagination": {
|
|||
|
|
"current": 1,
|
|||
|
|
"pageSize": 10,
|
|||
|
|
"total": 100,
|
|||
|
|
"totalPages": 10
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 错误响应格式
|
|||
|
|
{
|
|||
|
|
"code": 400,
|
|||
|
|
"message": "参数错误",
|
|||
|
|
"error": {
|
|||
|
|
"field": "email",
|
|||
|
|
"reason": "邮箱格式不正确"
|
|||
|
|
},
|
|||
|
|
"timestamp": "2024-01-20T10:30:00Z"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 7. 数据库规范
|
|||
|
|
|
|||
|
|
### 7.1 表命名
|
|||
|
|
```sql
|
|||
|
|
-- 表名使用复数形式,下划线分隔
|
|||
|
|
users
|
|||
|
|
farm_devices
|
|||
|
|
alert_records
|
|||
|
|
user_roles
|
|||
|
|
|
|||
|
|
-- 关联表使用两个表名组合
|
|||
|
|
user_farm_bindings
|
|||
|
|
device_alert_configs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 字段命名
|
|||
|
|
```sql
|
|||
|
|
-- 字段名使用下划线分隔
|
|||
|
|
CREATE TABLE users (
|
|||
|
|
id VARCHAR(36) PRIMARY KEY,
|
|||
|
|
user_name VARCHAR(50) NOT NULL,
|
|||
|
|
email VARCHAR(100) UNIQUE,
|
|||
|
|
phone_number VARCHAR(20),
|
|||
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|||
|
|
is_active BOOLEAN DEFAULT TRUE
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 8. Git 提交规范
|
|||
|
|
|
|||
|
|
### 8.1 提交信息格式
|
|||
|
|
```
|
|||
|
|
<type>(<scope>): <subject>
|
|||
|
|
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<footer>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.2 类型说明
|
|||
|
|
- **feat**: 新功能
|
|||
|
|
- **fix**: 修复bug
|
|||
|
|
- **docs**: 文档更新
|
|||
|
|
- **style**: 代码格式调整
|
|||
|
|
- **refactor**: 代码重构
|
|||
|
|
- **test**: 测试相关
|
|||
|
|
- **chore**: 构建过程或辅助工具的变动
|
|||
|
|
|
|||
|
|
### 8.3 提交示例
|
|||
|
|
```
|
|||
|
|
feat(user): 添加用户头像上传功能
|
|||
|
|
|
|||
|
|
- 支持jpg、png格式图片上传
|
|||
|
|
- 添加图片压缩和裁剪功能
|
|||
|
|
- 更新用户资料页面UI
|
|||
|
|
|
|||
|
|
Closes #123
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9. 测试规范
|
|||
|
|
|
|||
|
|
### 9.1 单元测试
|
|||
|
|
```javascript
|
|||
|
|
// 测试文件命名: *.test.js 或 *.spec.js
|
|||
|
|
describe('UserService', () => {
|
|||
|
|
describe('getUserById', () => {
|
|||
|
|
it('应该返回正确的用户信息', async () => {
|
|||
|
|
// Arrange
|
|||
|
|
const userId = '123';
|
|||
|
|
const expectedUser = { id: '123', name: 'Test User' };
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
const result = await userService.getUserById(userId);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
expect(result).toEqual(expectedUser);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('用户不存在时应该抛出错误', async () => {
|
|||
|
|
// Arrange
|
|||
|
|
const userId = 'nonexistent';
|
|||
|
|
|
|||
|
|
// Act & Assert
|
|||
|
|
await expect(userService.getUserById(userId))
|
|||
|
|
.rejects.toThrow('用户不存在');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.2 集成测试
|
|||
|
|
```javascript
|
|||
|
|
describe('User API', () => {
|
|||
|
|
beforeEach(async () => {
|
|||
|
|
await setupTestDatabase();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
afterEach(async () => {
|
|||
|
|
await cleanupTestDatabase();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('POST /api/users 应该创建新用户', async () => {
|
|||
|
|
const userData = {
|
|||
|
|
name: 'Test User',
|
|||
|
|
email: 'test@example.com'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const response = await request(app)
|
|||
|
|
.post('/api/users')
|
|||
|
|
.send(userData)
|
|||
|
|
.expect(201);
|
|||
|
|
|
|||
|
|
expect(response.body.data).toMatchObject(userData);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 10. 性能优化规范
|
|||
|
|
|
|||
|
|
### 10.1 前端优化
|
|||
|
|
```javascript
|
|||
|
|
// 懒加载组件
|
|||
|
|
const UserProfile = () => import('./components/UserProfile.vue');
|
|||
|
|
|
|||
|
|
// 防抖处理
|
|||
|
|
import { debounce } from 'lodash-es';
|
|||
|
|
|
|||
|
|
const handleSearch = debounce((keyword) => {
|
|||
|
|
// 搜索逻辑
|
|||
|
|
}, 300);
|
|||
|
|
|
|||
|
|
// 虚拟滚动
|
|||
|
|
<VirtualList
|
|||
|
|
:items="largeDataSet"
|
|||
|
|
:item-height="50"
|
|||
|
|
:visible-count="10"
|
|||
|
|
/>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.2 后端优化
|
|||
|
|
```javascript
|
|||
|
|
// 数据库查询优化
|
|||
|
|
const users = await User.findAll({
|
|||
|
|
attributes: ['id', 'name', 'email'], // 只查询需要的字段
|
|||
|
|
include: [{
|
|||
|
|
model: Role,
|
|||
|
|
attributes: ['name']
|
|||
|
|
}],
|
|||
|
|
limit: 10,
|
|||
|
|
offset: (page - 1) * 10
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 缓存使用
|
|||
|
|
const cacheKey = `user:${userId}`;
|
|||
|
|
let user = await redis.get(cacheKey);
|
|||
|
|
|
|||
|
|
if (!user) {
|
|||
|
|
user = await User.findById(userId);
|
|||
|
|
await redis.setex(cacheKey, 3600, JSON.stringify(user));
|
|||
|
|
} else {
|
|||
|
|
user = JSON.parse(user);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11. 安全规范
|
|||
|
|
|
|||
|
|
### 11.1 输入验证
|
|||
|
|
```javascript
|
|||
|
|
// 使用验证库
|
|||
|
|
const Joi = require('joi');
|
|||
|
|
|
|||
|
|
const userSchema = Joi.object({
|
|||
|
|
name: Joi.string().min(2).max(50).required(),
|
|||
|
|
email: Joi.string().email().required(),
|
|||
|
|
password: Joi.string().min(8).pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const { error, value } = userSchema.validate(req.body);
|
|||
|
|
if (error) {
|
|||
|
|
return res.status(400).json({ message: error.details[0].message });
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 11.2 SQL 注入防护
|
|||
|
|
```javascript
|
|||
|
|
// 使用参数化查询
|
|||
|
|
const user = await User.findOne({
|
|||
|
|
where: {
|
|||
|
|
email: req.body.email // Sequelize 自动转义
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 原生查询使用占位符
|
|||
|
|
const result = await sequelize.query(
|
|||
|
|
'SELECT * FROM users WHERE email = ?',
|
|||
|
|
{
|
|||
|
|
replacements: [email],
|
|||
|
|
type: QueryTypes.SELECT
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 12. 代码审查清单
|
|||
|
|
|
|||
|
|
### 12.1 功能性检查
|
|||
|
|
- [ ] 功能是否按需求实现
|
|||
|
|
- [ ] 边界条件是否处理
|
|||
|
|
- [ ] 错误处理是否完善
|
|||
|
|
- [ ] 性能是否满足要求
|
|||
|
|
|
|||
|
|
### 12.2 代码质量检查
|
|||
|
|
- [ ] 命名是否清晰明确
|
|||
|
|
- [ ] 代码结构是否合理
|
|||
|
|
- [ ] 是否有重复代码
|
|||
|
|
- [ ] 注释是否充分
|
|||
|
|
|
|||
|
|
### 12.3 安全性检查
|
|||
|
|
- [ ] 输入验证是否完整
|
|||
|
|
- [ ] 权限控制是否正确
|
|||
|
|
- [ ] 敏感信息是否泄露
|
|||
|
|
- [ ] SQL注入防护是否到位
|
|||
|
|
|
|||
|
|
## 13. 工具配置
|
|||
|
|
|
|||
|
|
### 13.1 ESLint 配置
|
|||
|
|
```javascript
|
|||
|
|
// .eslintrc.js
|
|||
|
|
module.exports = {
|
|||
|
|
extends: [
|
|||
|
|
'eslint:recommended',
|
|||
|
|
'@vue/eslint-config-prettier'
|
|||
|
|
],
|
|||
|
|
rules: {
|
|||
|
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|||
|
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
|||
|
|
'vue/multi-word-component-names': 'off'
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 13.2 Prettier 配置
|
|||
|
|
```javascript
|
|||
|
|
// .prettierrc.js
|
|||
|
|
module.exports = {
|
|||
|
|
semi: true,
|
|||
|
|
singleQuote: true,
|
|||
|
|
tabWidth: 2,
|
|||
|
|
trailingComma: 'es5',
|
|||
|
|
printWidth: 80,
|
|||
|
|
endOfLine: 'lf'
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**注意**: 本规范会根据项目发展持续更新,请团队成员定期查看最新版本。
|