932 lines
20 KiB
Markdown
932 lines
20 KiB
Markdown
|
|
# 开发指南
|
||
|
|
|
||
|
|
## 概述
|
||
|
|
|
||
|
|
本文档为开发者提供宁夏智慧养殖监管平台的详细开发指南,包括开发环境搭建、代码规范、开发流程、调试技巧等内容。
|
||
|
|
|
||
|
|
## 开发环境搭建
|
||
|
|
|
||
|
|
### 系统要求
|
||
|
|
- **Node.js**: 18.0+ (推荐使用 LTS 版本)
|
||
|
|
- **npm**: 8.0+ 或 **yarn**: 1.22+
|
||
|
|
- **MySQL**: 8.0+
|
||
|
|
- **Git**: 2.25+
|
||
|
|
- **编辑器**: VSCode (推荐)
|
||
|
|
|
||
|
|
### 工具推荐
|
||
|
|
- **API测试**: Postman 或 Insomnia
|
||
|
|
- **数据库管理**: MySQL Workbench 或 phpMyAdmin
|
||
|
|
- **版本控制**: Git + GitHub/GitLab
|
||
|
|
- **终端**: iTerm2 (macOS) 或 Windows Terminal
|
||
|
|
|
||
|
|
### 环境搭建步骤
|
||
|
|
|
||
|
|
#### 1. 克隆项目
|
||
|
|
```bash
|
||
|
|
git clone <repository-url>
|
||
|
|
cd nxxmdata
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. 安装依赖
|
||
|
|
```bash
|
||
|
|
# 后端依赖
|
||
|
|
cd backend
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# 前端依赖 - 管理后台
|
||
|
|
cd ../admin-system/frontend
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# 前端依赖 - 官网大屏
|
||
|
|
cd ../../website/data-screen
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# 微信小程序(可选)
|
||
|
|
cd ../../mini_program/farm-monitor-dashboard
|
||
|
|
npm install
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. 数据库配置
|
||
|
|
```bash
|
||
|
|
# 创建数据库
|
||
|
|
mysql -u root -p
|
||
|
|
CREATE DATABASE nxxmdata CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
|
|
|
||
|
|
# 导入数据结构
|
||
|
|
cd backend
|
||
|
|
mysql -u root -p nxxmdata < ../create_tables.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4. 环境变量配置
|
||
|
|
```bash
|
||
|
|
# 后端环境变量
|
||
|
|
cp backend/.env.example backend/.env
|
||
|
|
# 编辑 .env 文件,配置数据库连接等信息
|
||
|
|
|
||
|
|
# 前端环境变量
|
||
|
|
cp admin-system/frontend/.env.example admin-system/frontend/.env
|
||
|
|
# 配置API基础URL等
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 5. 启动开发服务器
|
||
|
|
```bash
|
||
|
|
# 启动后端 (Terminal 1)
|
||
|
|
cd backend
|
||
|
|
npm run dev
|
||
|
|
|
||
|
|
# 启动管理后台前端 (Terminal 2)
|
||
|
|
cd admin-system/frontend
|
||
|
|
npm run dev
|
||
|
|
|
||
|
|
# 启动官网大屏 (Terminal 3)
|
||
|
|
cd website/data-screen
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
## 项目结构详解
|
||
|
|
|
||
|
|
### 后端架构 (`backend/`)
|
||
|
|
```
|
||
|
|
backend/
|
||
|
|
├── config/ # 配置文件
|
||
|
|
│ ├── database.js # 数据库配置
|
||
|
|
│ ├── swagger.js # API文档配置
|
||
|
|
│ └── performance-config.js # 性能监控配置
|
||
|
|
├── controllers/ # 控制器层
|
||
|
|
│ ├── farmController.js # 农场业务逻辑
|
||
|
|
│ ├── deviceController.js # 设备业务逻辑
|
||
|
|
│ └── userController.js # 用户业务逻辑
|
||
|
|
├── models/ # 数据模型层
|
||
|
|
│ ├── Farm.js # 农场模型
|
||
|
|
│ ├── Device.js # 设备模型
|
||
|
|
│ └── User.js # 用户模型
|
||
|
|
├── routes/ # 路由层
|
||
|
|
│ ├── farms.js # 农场相关路由
|
||
|
|
│ ├── devices.js # 设备相关路由
|
||
|
|
│ └── auth.js # 认证相关路由
|
||
|
|
├── middleware/ # 中间件
|
||
|
|
│ ├── auth.js # 认证中间件
|
||
|
|
│ └── performance-middleware.js # 性能监控中间件
|
||
|
|
├── utils/ # 工具类
|
||
|
|
│ ├── logger.js # 日志工具
|
||
|
|
│ └── performance-monitor.js # 性能监控工具
|
||
|
|
├── migrations/ # 数据库迁移
|
||
|
|
├── seeds/ # 种子数据
|
||
|
|
├── logs/ # 日志文件
|
||
|
|
└── server.js # 服务器入口
|
||
|
|
```
|
||
|
|
|
||
|
|
### 前端架构 (`admin-system/frontend/`)
|
||
|
|
```
|
||
|
|
frontend/
|
||
|
|
├── src/
|
||
|
|
│ ├── components/ # 可复用组件
|
||
|
|
│ │ ├── BaiduMap.vue # 百度地图组件
|
||
|
|
│ │ ├── EChart.vue # 图表组件
|
||
|
|
│ │ └── Dashboard.vue # 仪表盘组件
|
||
|
|
│ ├── views/ # 页面组件
|
||
|
|
│ │ ├── Home.vue # 首页
|
||
|
|
│ │ ├── MapView.vue # 地图视图
|
||
|
|
│ │ └── Analytics.vue # 数据分析
|
||
|
|
│ ├── stores/ # 状态管理 (Pinia)
|
||
|
|
│ │ ├── user.js # 用户状态
|
||
|
|
│ │ └── data.js # 数据状态
|
||
|
|
│ ├── router/ # 路由配置
|
||
|
|
│ │ ├── index.js # 路由实例
|
||
|
|
│ │ └── routes.js # 路由定义
|
||
|
|
│ ├── utils/ # 工具函数
|
||
|
|
│ │ └── api.js # API调用封装
|
||
|
|
│ ├── styles/ # 样式文件
|
||
|
|
│ └── config/ # 配置文件
|
||
|
|
├── public/ # 静态资源
|
||
|
|
└── vite.config.js # Vite配置
|
||
|
|
```
|
||
|
|
|
||
|
|
## 开发规范
|
||
|
|
|
||
|
|
### 代码风格规范
|
||
|
|
|
||
|
|
#### JavaScript/Vue.js 规范
|
||
|
|
```javascript
|
||
|
|
// 1. 使用 ES6+ 语法
|
||
|
|
const apiUrl = process.env.VITE_API_BASE_URL;
|
||
|
|
|
||
|
|
// 2. 函数命名使用驼峰命名
|
||
|
|
function getUserInfo() {}
|
||
|
|
|
||
|
|
// 3. 常量使用大写字母和下划线
|
||
|
|
const API_BASE_URL = 'http://localhost:5350/api';
|
||
|
|
|
||
|
|
// 4. 类名使用 PascalCase
|
||
|
|
class UserService {}
|
||
|
|
|
||
|
|
// 5. 文件名使用 kebab-case
|
||
|
|
// user-service.js, farm-detail.vue
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Vue.js 组件规范
|
||
|
|
```vue
|
||
|
|
<template>
|
||
|
|
<!-- 1. 模板根元素必须有唯一的根节点 -->
|
||
|
|
<div class="component-name">
|
||
|
|
<!-- 2. 使用语义化的HTML标签 -->
|
||
|
|
<header class="component-header">
|
||
|
|
<h1>{{ title }}</h1>
|
||
|
|
</header>
|
||
|
|
<main class="component-content">
|
||
|
|
<!-- 3. 事件处理使用 handle 前缀 -->
|
||
|
|
<button @click="handleSubmit">提交</button>
|
||
|
|
</main>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import { ref, computed, onMounted } from 'vue'
|
||
|
|
|
||
|
|
export default {
|
||
|
|
name: 'ComponentName', // 4. 组件名使用 PascalCase
|
||
|
|
props: {
|
||
|
|
// 5. Props 定义要详细
|
||
|
|
title: {
|
||
|
|
type: String,
|
||
|
|
required: true,
|
||
|
|
default: ''
|
||
|
|
}
|
||
|
|
},
|
||
|
|
emits: ['submit'], // 6. 声明所有 emit 事件
|
||
|
|
setup(props, { emit }) {
|
||
|
|
// 7. 响应式数据使用 ref 或 reactive
|
||
|
|
const isLoading = ref(false)
|
||
|
|
|
||
|
|
// 8. 计算属性使用 computed
|
||
|
|
const displayTitle = computed(() => {
|
||
|
|
return props.title.toUpperCase()
|
||
|
|
})
|
||
|
|
|
||
|
|
// 9. 方法使用 handle 前缀
|
||
|
|
const handleSubmit = () => {
|
||
|
|
emit('submit')
|
||
|
|
}
|
||
|
|
|
||
|
|
// 10. 生命周期钩子
|
||
|
|
onMounted(() => {
|
||
|
|
// 组件挂载后的逻辑
|
||
|
|
})
|
||
|
|
|
||
|
|
return {
|
||
|
|
isLoading,
|
||
|
|
displayTitle,
|
||
|
|
handleSubmit
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
/* 11. 样式使用 scoped 避免污染 */
|
||
|
|
.component-name {
|
||
|
|
/* 12. 使用 BEM 命名法 */
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Node.js 后端规范
|
||
|
|
```javascript
|
||
|
|
// 1. 使用严格模式
|
||
|
|
'use strict';
|
||
|
|
|
||
|
|
// 2. 模块导入顺序:内置模块 -> 第三方模块 -> 本地模块
|
||
|
|
const path = require('path');
|
||
|
|
const express = require('express');
|
||
|
|
const { Farm } = require('../models');
|
||
|
|
|
||
|
|
// 3. 异步函数使用 async/await
|
||
|
|
const getFarms = async (req, res) => {
|
||
|
|
try {
|
||
|
|
// 4. 输入验证
|
||
|
|
const { page = 1, limit = 10 } = req.query;
|
||
|
|
|
||
|
|
// 5. 业务逻辑
|
||
|
|
const farms = await Farm.findAll({
|
||
|
|
limit: parseInt(limit),
|
||
|
|
offset: (parseInt(page) - 1) * parseInt(limit)
|
||
|
|
});
|
||
|
|
|
||
|
|
// 6. 统一响应格式
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
data: farms,
|
||
|
|
message: '获取成功'
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
// 7. 错误处理
|
||
|
|
res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
error: {
|
||
|
|
message: error.message
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
module.exports = {
|
||
|
|
getFarms
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Git 工作流规范
|
||
|
|
|
||
|
|
#### 分支命名规范
|
||
|
|
```bash
|
||
|
|
# 功能分支
|
||
|
|
feature/user-management
|
||
|
|
feature/device-monitoring
|
||
|
|
|
||
|
|
# 修复分支
|
||
|
|
fix/login-error
|
||
|
|
fix/map-display-issue
|
||
|
|
|
||
|
|
# 发布分支
|
||
|
|
release/v1.0.0
|
||
|
|
|
||
|
|
# 热修复分支
|
||
|
|
hotfix/security-patch
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 提交信息规范
|
||
|
|
```bash
|
||
|
|
# 格式: type(scope): description
|
||
|
|
|
||
|
|
# 类型 (type):
|
||
|
|
# feat: 新功能
|
||
|
|
# fix: 修复bug
|
||
|
|
# docs: 文档更新
|
||
|
|
# style: 代码格式调整
|
||
|
|
# refactor: 重构
|
||
|
|
# test: 测试相关
|
||
|
|
# chore: 构建过程或辅助工具的变动
|
||
|
|
|
||
|
|
# 示例:
|
||
|
|
git commit -m "feat(user): add user registration functionality"
|
||
|
|
git commit -m "fix(map): resolve baidu map display issue"
|
||
|
|
git commit -m "docs(api): update API documentation"
|
||
|
|
```
|
||
|
|
|
||
|
|
### 数据库设计规范
|
||
|
|
|
||
|
|
#### 表命名规范
|
||
|
|
```sql
|
||
|
|
-- 表名使用小写字母和下划线
|
||
|
|
CREATE TABLE users (...);
|
||
|
|
CREATE TABLE user_roles (...);
|
||
|
|
CREATE TABLE device_sensors (...);
|
||
|
|
|
||
|
|
-- 字段名使用小写字母和下划线
|
||
|
|
ALTER TABLE users ADD COLUMN created_at DATETIME;
|
||
|
|
ALTER TABLE users ADD COLUMN updated_at DATETIME;
|
||
|
|
|
||
|
|
-- 索引命名
|
||
|
|
CREATE INDEX idx_users_email ON users(email);
|
||
|
|
CREATE INDEX idx_farms_location ON farms(location);
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 模型定义规范
|
||
|
|
```javascript
|
||
|
|
// models/User.js
|
||
|
|
const { DataTypes } = require('sequelize');
|
||
|
|
|
||
|
|
module.exports = (sequelize) => {
|
||
|
|
const User = sequelize.define('User', {
|
||
|
|
id: {
|
||
|
|
type: DataTypes.INTEGER,
|
||
|
|
primaryKey: true,
|
||
|
|
autoIncrement: true,
|
||
|
|
comment: '用户唯一标识'
|
||
|
|
},
|
||
|
|
username: {
|
||
|
|
type: DataTypes.STRING(50),
|
||
|
|
allowNull: false,
|
||
|
|
unique: true,
|
||
|
|
comment: '用户名'
|
||
|
|
},
|
||
|
|
email: {
|
||
|
|
type: DataTypes.STRING(100),
|
||
|
|
allowNull: false,
|
||
|
|
unique: true,
|
||
|
|
validate: {
|
||
|
|
isEmail: true
|
||
|
|
},
|
||
|
|
comment: '邮箱地址'
|
||
|
|
}
|
||
|
|
}, {
|
||
|
|
tableName: 'users',
|
||
|
|
timestamps: true,
|
||
|
|
underscored: true,
|
||
|
|
comment: '用户表'
|
||
|
|
});
|
||
|
|
|
||
|
|
// 定义关联关系
|
||
|
|
User.associate = (models) => {
|
||
|
|
User.belongsToMany(models.Role, {
|
||
|
|
through: models.UserRole,
|
||
|
|
foreignKey: 'user_id',
|
||
|
|
otherKey: 'role_id'
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
return User;
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
## 开发流程
|
||
|
|
|
||
|
|
### 功能开发流程
|
||
|
|
|
||
|
|
#### 1. 需求分析
|
||
|
|
- 理解业务需求
|
||
|
|
- 确认技术方案
|
||
|
|
- 评估开发时间
|
||
|
|
|
||
|
|
#### 2. 设计阶段
|
||
|
|
```bash
|
||
|
|
# 数据库设计
|
||
|
|
# 1. 创建或修改表结构
|
||
|
|
# 2. 更新模型定义
|
||
|
|
# 3. 编写迁移脚本
|
||
|
|
|
||
|
|
# API设计
|
||
|
|
# 1. 定义路由
|
||
|
|
# 2. 设计请求/响应格式
|
||
|
|
# 3. 更新API文档
|
||
|
|
|
||
|
|
# 前端设计
|
||
|
|
# 1. UI组件设计
|
||
|
|
# 2. 状态管理设计
|
||
|
|
# 3. 路由规划
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. 开发阶段
|
||
|
|
```bash
|
||
|
|
# 创建功能分支
|
||
|
|
git checkout -b feature/new-feature
|
||
|
|
|
||
|
|
# 后端开发
|
||
|
|
# 1. 创建/修改模型
|
||
|
|
# 2. 编写控制器逻辑
|
||
|
|
# 3. 添加路由
|
||
|
|
# 4. 编写单元测试
|
||
|
|
|
||
|
|
# 前端开发
|
||
|
|
# 1. 创建Vue组件
|
||
|
|
# 2. 实现业务逻辑
|
||
|
|
# 3. 添加样式
|
||
|
|
# 4. 集成API
|
||
|
|
|
||
|
|
# 提交代码
|
||
|
|
git add .
|
||
|
|
git commit -m "feat: implement new feature"
|
||
|
|
git push origin feature/new-feature
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4. 测试阶段
|
||
|
|
```bash
|
||
|
|
# 单元测试
|
||
|
|
npm test
|
||
|
|
|
||
|
|
# 集成测试
|
||
|
|
npm run test:integration
|
||
|
|
|
||
|
|
# 端到端测试
|
||
|
|
npm run test:e2e
|
||
|
|
|
||
|
|
# 手动测试
|
||
|
|
# 1. 功能测试
|
||
|
|
# 2. 兼容性测试
|
||
|
|
# 3. 性能测试
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 5. 代码审查
|
||
|
|
- 创建 Pull Request
|
||
|
|
- 代码审查
|
||
|
|
- 修改反馈问题
|
||
|
|
- 合并到主分支
|
||
|
|
|
||
|
|
### 调试技巧
|
||
|
|
|
||
|
|
#### 后端调试
|
||
|
|
|
||
|
|
##### 1. 使用 console.log 调试
|
||
|
|
```javascript
|
||
|
|
// 在关键位置添加日志
|
||
|
|
console.log('User data:', userData);
|
||
|
|
console.log('Database query result:', result);
|
||
|
|
|
||
|
|
// 使用 JSON.stringify 查看对象
|
||
|
|
console.log('Request body:', JSON.stringify(req.body, null, 2));
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 2. 使用 Winston 日志
|
||
|
|
```javascript
|
||
|
|
const logger = require('../utils/logger');
|
||
|
|
|
||
|
|
// 不同级别的日志
|
||
|
|
logger.info('User logged in', { userId: user.id });
|
||
|
|
logger.warn('Invalid input', { input: req.body });
|
||
|
|
logger.error('Database error', { error: error.message });
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 3. 使用 Node.js 调试器
|
||
|
|
```bash
|
||
|
|
# 启动调试模式
|
||
|
|
node --inspect-brk server.js
|
||
|
|
|
||
|
|
# 在 Chrome 中打开 chrome://inspect
|
||
|
|
# 连接到 Node.js 进程进行调试
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 4. 数据库查询调试
|
||
|
|
```javascript
|
||
|
|
// 启用 Sequelize 日志
|
||
|
|
const sequelize = new Sequelize(config, {
|
||
|
|
logging: console.log, // 显示 SQL 查询
|
||
|
|
benchmark: true // 显示查询时间
|
||
|
|
});
|
||
|
|
|
||
|
|
// 手动执行 SQL 查询
|
||
|
|
const [results, metadata] = await sequelize.query(
|
||
|
|
'SELECT * FROM users WHERE id = ?',
|
||
|
|
{ replacements: [userId] }
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 前端调试
|
||
|
|
|
||
|
|
##### 1. 使用 Vue DevTools
|
||
|
|
```bash
|
||
|
|
# 安装 Vue DevTools 浏览器扩展
|
||
|
|
# 查看组件状态、props、events
|
||
|
|
# 检查 Pinia store 状态
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 2. 使用 console.log
|
||
|
|
```javascript
|
||
|
|
// 在组件中添加调试信息
|
||
|
|
export default {
|
||
|
|
setup() {
|
||
|
|
const userData = ref(null);
|
||
|
|
|
||
|
|
const fetchUser = async () => {
|
||
|
|
console.log('Fetching user data...');
|
||
|
|
const response = await api.getUser();
|
||
|
|
console.log('User response:', response);
|
||
|
|
userData.value = response.data;
|
||
|
|
};
|
||
|
|
|
||
|
|
return { userData, fetchUser };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 3. 使用浏览器开发者工具
|
||
|
|
```javascript
|
||
|
|
// 在代码中设置断点
|
||
|
|
debugger;
|
||
|
|
|
||
|
|
// 查看网络请求
|
||
|
|
// Network 标签页 -> 检查 API 请求和响应
|
||
|
|
|
||
|
|
// 查看控制台错误
|
||
|
|
// Console 标签页 -> 查看 JavaScript 错误
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 4. API 调试
|
||
|
|
```javascript
|
||
|
|
// 创建 API 调试工具
|
||
|
|
const apiDebug = {
|
||
|
|
log: (method, url, data, response) => {
|
||
|
|
console.group(`API ${method.toUpperCase()} ${url}`);
|
||
|
|
console.log('Request data:', data);
|
||
|
|
console.log('Response:', response);
|
||
|
|
console.groupEnd();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// 在 API 调用中使用
|
||
|
|
const response = await axios.post('/api/farms', farmData);
|
||
|
|
apiDebug.log('POST', '/api/farms', farmData, response.data);
|
||
|
|
```
|
||
|
|
|
||
|
|
### 性能优化
|
||
|
|
|
||
|
|
#### 后端性能优化
|
||
|
|
|
||
|
|
##### 1. 数据库查询优化
|
||
|
|
```javascript
|
||
|
|
// 使用索引
|
||
|
|
// 在经常查询的字段上添加索引
|
||
|
|
CREATE INDEX idx_farms_status ON farms(status);
|
||
|
|
|
||
|
|
// 避免 N+1 查询
|
||
|
|
const farms = await Farm.findAll({
|
||
|
|
include: [{
|
||
|
|
model: Device,
|
||
|
|
as: 'devices'
|
||
|
|
}]
|
||
|
|
});
|
||
|
|
|
||
|
|
// 使用分页
|
||
|
|
const farms = await Farm.findAndCountAll({
|
||
|
|
limit: 10,
|
||
|
|
offset: (page - 1) * 10
|
||
|
|
});
|
||
|
|
|
||
|
|
// 只查询需要的字段
|
||
|
|
const farms = await Farm.findAll({
|
||
|
|
attributes: ['id', 'name', 'status']
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 2. 缓存策略
|
||
|
|
```javascript
|
||
|
|
// 使用内存缓存
|
||
|
|
const cache = new Map();
|
||
|
|
|
||
|
|
const getCachedData = (key) => {
|
||
|
|
if (cache.has(key)) {
|
||
|
|
return cache.get(key);
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
};
|
||
|
|
|
||
|
|
const setCachedData = (key, data, ttl = 300000) => {
|
||
|
|
cache.set(key, data);
|
||
|
|
setTimeout(() => cache.delete(key), ttl);
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 3. 异步处理
|
||
|
|
```javascript
|
||
|
|
// 使用 Promise.all 并行处理
|
||
|
|
const [farms, devices, users] = await Promise.all([
|
||
|
|
Farm.findAll(),
|
||
|
|
Device.findAll(),
|
||
|
|
User.findAll()
|
||
|
|
]);
|
||
|
|
|
||
|
|
// 使用 stream 处理大量数据
|
||
|
|
const stream = Farm.findAll({ stream: true });
|
||
|
|
stream.on('data', (farm) => {
|
||
|
|
// 处理单个农场数据
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 前端性能优化
|
||
|
|
|
||
|
|
##### 1. 组件懒加载
|
||
|
|
```javascript
|
||
|
|
// router/routes.js
|
||
|
|
const routes = [
|
||
|
|
{
|
||
|
|
path: '/farms',
|
||
|
|
component: () => import('../views/Farms.vue') // 懒加载
|
||
|
|
}
|
||
|
|
];
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 2. 图片优化
|
||
|
|
```vue
|
||
|
|
<template>
|
||
|
|
<!-- 图片懒加载 -->
|
||
|
|
<img v-lazy="imageUrl" alt="Farm image">
|
||
|
|
|
||
|
|
<!-- 响应式图片 -->
|
||
|
|
<picture>
|
||
|
|
<source media="(min-width: 800px)" :srcset="largeImage">
|
||
|
|
<img :src="smallImage" alt="Farm">
|
||
|
|
</picture>
|
||
|
|
</template>
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 3. 虚拟滚动
|
||
|
|
```vue
|
||
|
|
<template>
|
||
|
|
<!-- 大列表虚拟滚动 -->
|
||
|
|
<virtual-scroll
|
||
|
|
:items="farms"
|
||
|
|
:item-height="60"
|
||
|
|
#default="{ item }"
|
||
|
|
>
|
||
|
|
<farm-item :farm="item" />
|
||
|
|
</virtual-scroll>
|
||
|
|
</template>
|
||
|
|
```
|
||
|
|
|
||
|
|
### 测试指南
|
||
|
|
|
||
|
|
#### 单元测试
|
||
|
|
|
||
|
|
##### 后端单元测试 (Jest)
|
||
|
|
```javascript
|
||
|
|
// tests/controllers/farmController.test.js
|
||
|
|
const { getFarms } = require('../../controllers/farmController');
|
||
|
|
const { Farm } = require('../../models');
|
||
|
|
|
||
|
|
jest.mock('../../models');
|
||
|
|
|
||
|
|
describe('Farm Controller', () => {
|
||
|
|
describe('getFarms', () => {
|
||
|
|
it('should return farms list', async () => {
|
||
|
|
const mockFarms = [
|
||
|
|
{ id: 1, name: 'Farm 1' },
|
||
|
|
{ id: 2, name: 'Farm 2' }
|
||
|
|
];
|
||
|
|
|
||
|
|
Farm.findAll.mockResolvedValue(mockFarms);
|
||
|
|
|
||
|
|
const req = { query: {} };
|
||
|
|
const res = {
|
||
|
|
json: jest.fn(),
|
||
|
|
status: jest.fn().mockReturnThis()
|
||
|
|
};
|
||
|
|
|
||
|
|
await getFarms(req, res);
|
||
|
|
|
||
|
|
expect(res.json).toHaveBeenCalledWith({
|
||
|
|
success: true,
|
||
|
|
data: mockFarms,
|
||
|
|
message: '获取成功'
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
##### 前端单元测试 (Vitest)
|
||
|
|
```javascript
|
||
|
|
// tests/components/FarmList.test.js
|
||
|
|
import { mount } from '@vue/test-utils';
|
||
|
|
import FarmList from '@/components/FarmList.vue';
|
||
|
|
|
||
|
|
describe('FarmList', () => {
|
||
|
|
it('renders farm list correctly', () => {
|
||
|
|
const farms = [
|
||
|
|
{ id: 1, name: 'Farm 1', status: 'active' },
|
||
|
|
{ id: 2, name: 'Farm 2', status: 'inactive' }
|
||
|
|
];
|
||
|
|
|
||
|
|
const wrapper = mount(FarmList, {
|
||
|
|
props: { farms }
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(wrapper.findAll('.farm-item')).toHaveLength(2);
|
||
|
|
expect(wrapper.text()).toContain('Farm 1');
|
||
|
|
expect(wrapper.text()).toContain('Farm 2');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('emits select event when farm is clicked', async () => {
|
||
|
|
const farms = [{ id: 1, name: 'Farm 1', status: 'active' }];
|
||
|
|
|
||
|
|
const wrapper = mount(FarmList, {
|
||
|
|
props: { farms }
|
||
|
|
});
|
||
|
|
|
||
|
|
await wrapper.find('.farm-item').trigger('click');
|
||
|
|
|
||
|
|
expect(wrapper.emitted('select')).toBeTruthy();
|
||
|
|
expect(wrapper.emitted('select')[0]).toEqual([farms[0]]);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 集成测试
|
||
|
|
```javascript
|
||
|
|
// tests/integration/farms.test.js
|
||
|
|
const request = require('supertest');
|
||
|
|
const app = require('../../server');
|
||
|
|
|
||
|
|
describe('Farms API', () => {
|
||
|
|
it('GET /api/farms should return farms list', async () => {
|
||
|
|
const response = await request(app)
|
||
|
|
.get('/api/farms')
|
||
|
|
.set('Authorization', 'Bearer valid_token')
|
||
|
|
.expect(200);
|
||
|
|
|
||
|
|
expect(response.body.success).toBe(true);
|
||
|
|
expect(Array.isArray(response.body.data)).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('POST /api/farms should create new farm', async () => {
|
||
|
|
const farmData = {
|
||
|
|
name: 'Test Farm',
|
||
|
|
type: 'cattle',
|
||
|
|
longitude: 106.26667,
|
||
|
|
latitude: 38.46667
|
||
|
|
};
|
||
|
|
|
||
|
|
const response = await request(app)
|
||
|
|
.post('/api/farms')
|
||
|
|
.set('Authorization', 'Bearer admin_token')
|
||
|
|
.send(farmData)
|
||
|
|
.expect(201);
|
||
|
|
|
||
|
|
expect(response.body.success).toBe(true);
|
||
|
|
expect(response.body.data.name).toBe(farmData.name);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
### 部署和运维
|
||
|
|
|
||
|
|
#### 本地开发部署
|
||
|
|
```bash
|
||
|
|
# 1. 启动所有服务
|
||
|
|
npm run dev:all
|
||
|
|
|
||
|
|
# 2. 查看日志
|
||
|
|
tail -f backend/logs/app.log
|
||
|
|
|
||
|
|
# 3. 数据库管理
|
||
|
|
npm run db:migrate
|
||
|
|
npm run db:seed
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 生产环境部署
|
||
|
|
```bash
|
||
|
|
# 1. 构建项目
|
||
|
|
npm run build
|
||
|
|
|
||
|
|
# 2. 使用 PM2 部署
|
||
|
|
pm2 start ecosystem.config.js --env production
|
||
|
|
|
||
|
|
# 3. 监控服务
|
||
|
|
pm2 monit
|
||
|
|
pm2 logs
|
||
|
|
```
|
||
|
|
|
||
|
|
## 常见问题解决
|
||
|
|
|
||
|
|
### 开发环境问题
|
||
|
|
|
||
|
|
#### 1. 端口占用
|
||
|
|
```bash
|
||
|
|
# 查找占用端口的进程
|
||
|
|
lsof -i :5350
|
||
|
|
netstat -ano | findstr :5350 # Windows
|
||
|
|
|
||
|
|
# 杀死进程
|
||
|
|
kill -9 <PID>
|
||
|
|
taskkill /PID <PID> /F # Windows
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. 依赖安装失败
|
||
|
|
```bash
|
||
|
|
# 清除 npm 缓存
|
||
|
|
npm cache clean --force
|
||
|
|
|
||
|
|
# 删除 node_modules 重新安装
|
||
|
|
rm -rf node_modules package-lock.json
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# 使用 yarn 代替 npm
|
||
|
|
yarn install
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. 数据库连接失败
|
||
|
|
```bash
|
||
|
|
# 检查 MySQL 服务状态
|
||
|
|
brew services list | grep mysql # macOS
|
||
|
|
systemctl status mysql # Linux
|
||
|
|
net start mysql # Windows
|
||
|
|
|
||
|
|
# 测试数据库连接
|
||
|
|
mysql -u root -p -h localhost -P 3306
|
||
|
|
```
|
||
|
|
|
||
|
|
### 运行时问题
|
||
|
|
|
||
|
|
#### 1. API 请求失败
|
||
|
|
```javascript
|
||
|
|
// 检查网络请求
|
||
|
|
// 1. 打开浏览器开发者工具
|
||
|
|
// 2. 查看 Network 标签页
|
||
|
|
// 3. 检查请求状态码和响应内容
|
||
|
|
|
||
|
|
// 添加请求拦截器
|
||
|
|
axios.interceptors.request.use(
|
||
|
|
config => {
|
||
|
|
console.log('Request:', config);
|
||
|
|
return config;
|
||
|
|
},
|
||
|
|
error => {
|
||
|
|
console.error('Request Error:', error);
|
||
|
|
return Promise.reject(error);
|
||
|
|
}
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. 组件渲染问题
|
||
|
|
```javascript
|
||
|
|
// 检查 Vue 组件状态
|
||
|
|
// 1. 安装 Vue DevTools
|
||
|
|
// 2. 检查组件 props 和 data
|
||
|
|
// 3. 查看 computed 属性
|
||
|
|
// 4. 检查事件监听器
|
||
|
|
```
|
||
|
|
|
||
|
|
## 最佳实践
|
||
|
|
|
||
|
|
### 代码组织
|
||
|
|
1. **模块化开发**: 将功能拆分成独立的模块
|
||
|
|
2. **组件复用**: 创建可复用的组件库
|
||
|
|
3. **状态管理**: 合理使用 Pinia 管理应用状态
|
||
|
|
4. **错误处理**: 统一的错误处理机制
|
||
|
|
5. **日志记录**: 详细的日志记录便于调试
|
||
|
|
|
||
|
|
### 性能优化
|
||
|
|
1. **懒加载**: 组件和路由懒加载
|
||
|
|
2. **缓存策略**: 合理使用缓存提升性能
|
||
|
|
3. **数据库优化**: 优化查询语句和索引
|
||
|
|
4. **图片优化**: 压缩图片和使用适当格式
|
||
|
|
5. **打包优化**: 优化 Webpack/Vite 配置
|
||
|
|
|
||
|
|
### 安全考虑
|
||
|
|
1. **输入验证**: 严格验证用户输入
|
||
|
|
2. **权限控制**: 实现细粒度的权限控制
|
||
|
|
3. **SQL注入防护**: 使用参数化查询
|
||
|
|
4. **XSS防护**: 过滤和转义用户输入
|
||
|
|
5. **CSRF防护**: 实现 CSRF Token 机制
|
||
|
|
|
||
|
|
## 工具和资源
|
||
|
|
|
||
|
|
### 开发工具
|
||
|
|
- **IDE**: VSCode
|
||
|
|
- **API测试**: Postman
|
||
|
|
- **数据库**: MySQL Workbench
|
||
|
|
- **版本控制**: Git
|
||
|
|
- **包管理**: npm/yarn
|
||
|
|
|
||
|
|
### 有用的 VSCode 插件
|
||
|
|
- **Vue Language Features (Volar)**: Vue 3 支持
|
||
|
|
- **ESLint**: 代码质量检查
|
||
|
|
- **Prettier**: 代码格式化
|
||
|
|
- **Auto Rename Tag**: 自动重命名标签
|
||
|
|
- **Bracket Pair Colorizer**: 括号高亮
|
||
|
|
- **GitLens**: Git 增强
|
||
|
|
|
||
|
|
### 学习资源
|
||
|
|
- **Vue.js 官方文档**: https://vuejs.org/
|
||
|
|
- **Node.js 官方文档**: https://nodejs.org/
|
||
|
|
- **Sequelize 文档**: https://sequelize.org/
|
||
|
|
- **Ant Design Vue**: https://antdv.com/
|
||
|
|
- **ECharts 文档**: https://echarts.apache.org/
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 联系支持
|
||
|
|
|
||
|
|
如有开发相关问题,请联系:
|
||
|
|
- **技术支持**: dev-support@nxxmdata.com
|
||
|
|
- **文档反馈**: docs@nxxmdata.com
|
||
|
|
- **Bug 报告**: bugs@nxxmdata.com
|
||
|
|
|
||
|
|
*最后更新: 2025年1月*
|