refactor: 替换项目中的"yudao"为"AIOTAGRO",并清理相关配置文件
This commit is contained in:
652
docs/安全文档.md
Normal file
652
docs/安全文档.md
Normal file
@@ -0,0 +1,652 @@
|
||||
# 安全文档
|
||||
|
||||
## 安全概述
|
||||
|
||||
AIOTAGRO 管理系统安全文档涵盖系统安全设计、安全配置、安全审计、应急响应等安全相关事项。本文档为开发团队和运维团队提供完整的安全指南。
|
||||
|
||||
## 安全架构
|
||||
|
||||
### 1. 安全设计原则
|
||||
|
||||
#### 最小权限原则
|
||||
- 每个组件只拥有完成其功能所需的最小权限
|
||||
- 数据库用户按功能分离权限
|
||||
- 文件系统权限严格控制
|
||||
|
||||
#### 纵深防御
|
||||
- 多层安全防护机制
|
||||
- 网络层、应用层、数据层全面防护
|
||||
- 安全监控和告警机制
|
||||
|
||||
#### 安全默认配置
|
||||
- 默认关闭不必要的服务
|
||||
- 默认启用安全功能
|
||||
- 默认使用强加密算法
|
||||
|
||||
### 2. 安全组件
|
||||
|
||||
#### 前端安全
|
||||
- CSP (Content Security Policy) 策略
|
||||
- XSS 防护机制
|
||||
- CSRF 防护机制
|
||||
- 安全头配置
|
||||
|
||||
#### 后端安全
|
||||
- 输入验证和过滤
|
||||
- SQL 注入防护
|
||||
- 文件上传安全
|
||||
- 会话安全管理
|
||||
|
||||
#### 基础设施安全
|
||||
- 网络安全配置
|
||||
- 系统安全加固
|
||||
- 访问控制机制
|
||||
- 日志审计系统
|
||||
|
||||
## 安全配置
|
||||
|
||||
### 1. 前端安全配置
|
||||
|
||||
#### CSP 配置
|
||||
|
||||
```javascript
|
||||
// vite.config.js
|
||||
export default defineConfig({
|
||||
// CSP 配置
|
||||
server: {
|
||||
headers: {
|
||||
'Content-Security-Policy': `
|
||||
default-src 'self';
|
||||
script-src 'self' 'unsafe-inline' 'unsafe-eval';
|
||||
style-src 'self' 'unsafe-inline';
|
||||
img-src 'self' data: https:;
|
||||
font-src 'self';
|
||||
connect-src 'self' https://api.aiotagro.com;
|
||||
frame-ancestors 'none';
|
||||
base-uri 'self';
|
||||
form-action 'self'
|
||||
`.replace(/\s+/g, ' ').trim()
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### 安全头配置
|
||||
|
||||
```nginx
|
||||
# Nginx 安全头配置
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
|
||||
```
|
||||
|
||||
### 2. 应用安全配置
|
||||
|
||||
#### 输入验证
|
||||
|
||||
```javascript
|
||||
// 输入验证工具
|
||||
export const validateInput = {
|
||||
// 邮箱验证
|
||||
email: (email) => {
|
||||
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||
return regex.test(email)
|
||||
},
|
||||
|
||||
// 手机号验证
|
||||
phone: (phone) => {
|
||||
const regex = /^1[3-9]\d{9}$/
|
||||
return regex.test(phone)
|
||||
},
|
||||
|
||||
// 密码强度验证
|
||||
password: (password) => {
|
||||
return password.length >= 8 &&
|
||||
/[A-Z]/.test(password) &&
|
||||
/[a-z]/.test(password) &&
|
||||
/[0-9]/.test(password)
|
||||
},
|
||||
|
||||
// XSS 防护
|
||||
sanitize: (input) => {
|
||||
return input.replace(/[<>"'&]/g, (char) => {
|
||||
const escapeMap = {
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'&': '&'
|
||||
}
|
||||
return escapeMap[char] || char
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 会话安全
|
||||
|
||||
```javascript
|
||||
// 会话管理
|
||||
export const sessionManager = {
|
||||
// 生成安全的会话 ID
|
||||
generateSessionId: () => {
|
||||
return crypto.randomBytes(32).toString('hex')
|
||||
},
|
||||
|
||||
// 设置安全 Cookie
|
||||
setSecureCookie: (name, value, options = {}) => {
|
||||
const defaults = {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'strict',
|
||||
maxAge: 24 * 60 * 60 * 1000 // 24小时
|
||||
}
|
||||
|
||||
document.cookie = `${name}=${value}; ${Object.entries({...defaults, ...options})
|
||||
.map(([key, val]) => `${key}=${val}`)
|
||||
.join('; ')}`
|
||||
},
|
||||
|
||||
// 验证会话
|
||||
validateSession: (sessionId) => {
|
||||
// 验证会话有效性和权限
|
||||
return true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 基础设施安全
|
||||
|
||||
#### 网络安全配置
|
||||
|
||||
```nginx
|
||||
# 网络安全配置
|
||||
# 限制请求大小
|
||||
client_max_body_size 10m;
|
||||
|
||||
# 限制请求速率
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
|
||||
|
||||
# IP 黑名单
|
||||
geo $blacklist {
|
||||
default 0;
|
||||
192.168.1.100 1;
|
||||
10.0.0.50 1;
|
||||
}
|
||||
|
||||
server {
|
||||
# 黑名单处理
|
||||
if ($blacklist) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
# API 速率限制
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
# ...
|
||||
}
|
||||
|
||||
# 登录速率限制
|
||||
location /api/auth/login {
|
||||
limit_req zone=login burst=5 nodelay;
|
||||
# ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 系统安全加固
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# system-hardening.sh
|
||||
|
||||
echo "开始系统安全加固..."
|
||||
|
||||
# 1. 更新系统
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# 2. 配置防火墙
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
sudo ufw allow ssh
|
||||
sudo ufw allow http
|
||||
sudo ufw allow https
|
||||
sudo ufw --force enable
|
||||
|
||||
# 3. 禁用不必要的服务
|
||||
sudo systemctl disable apache2
|
||||
sudo systemctl disable mysql
|
||||
sudo systemctl disable postgresql
|
||||
|
||||
# 4. 配置 SSH 安全
|
||||
sudo sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
|
||||
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||
sudo sed -i 's/#MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config
|
||||
sudo systemctl restart sshd
|
||||
|
||||
# 5. 配置文件权限
|
||||
sudo chmod 600 /etc/ssl/private/aiotagro.key
|
||||
sudo chmod 644 /etc/ssl/certs/aiotagro.crt
|
||||
sudo chown -R www-data:www-data /var/www/aiotagro
|
||||
|
||||
# 6. 配置日志审计
|
||||
sudo apt install auditd
|
||||
sudo auditctl -e 1
|
||||
sudo systemctl enable auditd
|
||||
|
||||
echo "系统安全加固完成"
|
||||
```
|
||||
|
||||
## 安全审计
|
||||
|
||||
### 1. 代码安全审计
|
||||
|
||||
#### 静态代码分析
|
||||
|
||||
```yaml
|
||||
# .github/workflows/code-scan.yml
|
||||
name: Code Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '0 2 * * 1' # 每周一凌晨2点
|
||||
|
||||
jobs:
|
||||
security-scan:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run ESLint security rules
|
||||
run: |
|
||||
npx eslint . --ext .js,.vue,.ts --config .eslintrc.security.js
|
||||
|
||||
- name: Run SAST scan
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript
|
||||
queries: security-extended
|
||||
|
||||
- name: Run SAST analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
- name: Run dependency check
|
||||
uses: dependency-check/Dependency-Check_Action@main
|
||||
with:
|
||||
project: 'AIOTAGRO Frontend'
|
||||
path: '.'
|
||||
format: 'HTML'
|
||||
|
||||
- name: Upload security report
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: security-reports
|
||||
path: reports/
|
||||
```
|
||||
|
||||
#### 安全规则配置
|
||||
|
||||
```javascript
|
||||
// .eslintrc.security.js
|
||||
module.exports = {
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:security/recommended'
|
||||
],
|
||||
plugins: ['security'],
|
||||
rules: {
|
||||
'security/detect-object-injection': 'error',
|
||||
'security/detect-possible-timing-attacks': 'error',
|
||||
'security/detect-non-literal-require': 'error',
|
||||
'security/detect-non-literal-fs-filename': 'error',
|
||||
'security/detect-eval-with-expression': 'error',
|
||||
'security/detect-pseudoRandomBytes': 'error',
|
||||
'security/detect-unsafe-regex': 'error'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 依赖安全审计
|
||||
|
||||
#### 依赖安全检查
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"security:audit": "npm audit --audit-level moderate",
|
||||
"security:fix": "npm audit fix",
|
||||
"security:outdated": "npm outdated",
|
||||
"security:check": "npx snyk test"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 自动化安全更新
|
||||
|
||||
```yaml
|
||||
# .github/workflows/security-update.yml
|
||||
name: Security Updates
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * 0' # 每周日凌晨3点
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
security-update:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Check for security vulnerabilities
|
||||
run: npm audit --audit-level moderate
|
||||
|
||||
- name: Update dependencies
|
||||
if: always()
|
||||
run: |
|
||||
npm update --save
|
||||
npm audit fix
|
||||
|
||||
- name: Create Pull Request
|
||||
if: always()
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
title: '安全依赖更新'
|
||||
body: '自动安全依赖更新'
|
||||
branch: 'security-updates'
|
||||
commit-message: '更新安全依赖'
|
||||
```
|
||||
|
||||
### 3. 运行时安全监控
|
||||
|
||||
#### 安全事件监控
|
||||
|
||||
```javascript
|
||||
// 安全监控工具
|
||||
export const securityMonitor = {
|
||||
// 记录安全事件
|
||||
logSecurityEvent: (event) => {
|
||||
const securityLog = {
|
||||
timestamp: new Date().toISOString(),
|
||||
event: event.type,
|
||||
severity: event.severity || 'info',
|
||||
userAgent: navigator.userAgent,
|
||||
url: window.location.href,
|
||||
details: event.details
|
||||
}
|
||||
|
||||
// 发送到安全日志服务
|
||||
fetch('/api/security/log', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(securityLog)
|
||||
}).catch(console.error)
|
||||
},
|
||||
|
||||
// 检测异常行为
|
||||
detectAnomalies: () => {
|
||||
// 检测异常请求模式
|
||||
// 检测可疑用户行为
|
||||
// 检测安全策略违规
|
||||
},
|
||||
|
||||
// 实时告警
|
||||
alert: (message, level = 'warning') => {
|
||||
console[level](`[安全告警] ${message}`)
|
||||
// 发送到告警系统
|
||||
}
|
||||
}
|
||||
|
||||
// 监控全局错误
|
||||
window.addEventListener('error', (event) => {
|
||||
securityMonitor.logSecurityEvent({
|
||||
type: 'javascript_error',
|
||||
severity: 'error',
|
||||
details: {
|
||||
message: event.message,
|
||||
filename: event.filename,
|
||||
lineno: event.lineno,
|
||||
colno: event.colno
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 监控未处理的 Promise 拒绝
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
securityMonitor.logSecurityEvent({
|
||||
type: 'unhandled_promise_rejection',
|
||||
severity: 'error',
|
||||
details: {
|
||||
reason: event.reason
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 应急响应
|
||||
|
||||
### 1. 安全事件分类
|
||||
|
||||
#### 事件严重等级
|
||||
|
||||
| 等级 | 描述 | 响应时间 | 处理流程 |
|
||||
|------|------|----------|----------|
|
||||
| 紧急 | 系统被入侵,数据泄露 | 立即响应 | 隔离系统,通知管理层 |
|
||||
| 高危 | 发现严重漏洞 | 2小时内响应 | 修复漏洞,安全审计 |
|
||||
| 中危 | 发现中等风险漏洞 | 24小时内响应 | 制定修复计划 |
|
||||
| 低危 | 发现低风险问题 | 72小时内响应 | 定期修复 |
|
||||
|
||||
### 2. 应急响应流程
|
||||
|
||||
#### 安全事件响应脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# security-incident-response.sh
|
||||
|
||||
set -e
|
||||
|
||||
INCIDENT_TYPE="$1"
|
||||
SEVERITY="$2"
|
||||
|
||||
echo "开始安全事件应急响应..."
|
||||
echo "事件类型: $INCIDENT_TYPE"
|
||||
echo "严重等级: $SEVERITY"
|
||||
|
||||
# 记录事件
|
||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
echo "[$timestamp] 安全事件: $INCIDENT_TYPE ($SEVERITY)" >> /var/log/security/incidents.log
|
||||
|
||||
case $SEVERITY in
|
||||
"critical")
|
||||
echo "执行紧急响应流程..."
|
||||
|
||||
# 1. 隔离受影响系统
|
||||
echo "隔离系统..."
|
||||
sudo systemctl stop nginx
|
||||
sudo ufw deny http
|
||||
sudo ufw deny https
|
||||
|
||||
# 2. 备份当前状态
|
||||
echo "备份系统状态..."
|
||||
tar -czf "/opt/aiotagro/forensics/incident_$timestamp.tar.gz" \
|
||||
/var/log/nginx \
|
||||
/var/log/auth.log \
|
||||
/etc/nginx
|
||||
|
||||
# 3. 通知相关人员
|
||||
echo "通知安全团队..."
|
||||
# send_email "security@aiotagro.com" "安全事件告警" "发现紧急安全事件"
|
||||
|
||||
# 4. 启动取证调查
|
||||
echo "启动取证调查..."
|
||||
;;
|
||||
|
||||
"high")
|
||||
echo "执行高危响应流程..."
|
||||
|
||||
# 1. 限制访问
|
||||
echo "限制访问..."
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
|
||||
# 2. 安全审计
|
||||
echo "执行安全审计..."
|
||||
npm audit
|
||||
# 运行安全扫描工具
|
||||
|
||||
# 3. 修复漏洞
|
||||
echo "修复安全漏洞..."
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "执行标准响应流程..."
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "安全事件响应完成"
|
||||
```
|
||||
|
||||
### 3. 恢复流程
|
||||
|
||||
#### 系统恢复检查清单
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# security-recovery-checklist.sh
|
||||
|
||||
echo "=== 安全恢复检查清单 ==="
|
||||
|
||||
# 1. 验证系统完整性
|
||||
echo "1. 验证系统完整性..."
|
||||
checksum_original="$(sha256sum /opt/aiotagro/frontend/package.json | cut -d' ' -f1)"
|
||||
checksum_current="$(sha256sum /opt/aiotagro/frontend/package.json | cut -d' ' -f1)"
|
||||
|
||||
if [ "$checksum_original" = "$checksum_current" ]; then
|
||||
echo "✓ 系统文件完整性验证通过"
|
||||
else
|
||||
echo "✗ 系统文件可能被篡改"
|
||||
fi
|
||||
|
||||
# 2. 检查安全配置
|
||||
echo "2. 检查安全配置..."
|
||||
nginx_test=$(sudo nginx -t 2>&1)
|
||||
if echo "$nginx_test" | grep -q "test is successful"; then
|
||||
echo "✓ Nginx 配置验证通过"
|
||||
else
|
||||
echo "✗ Nginx 配置存在错误"
|
||||
fi
|
||||
|
||||
# 3. 验证证书状态
|
||||
echo "3. 验证证书状态..."
|
||||
if openssl x509 -checkend 86400 -noout -in /etc/ssl/certs/aiotagro.crt; then
|
||||
echo "✓ SSL 证书有效"
|
||||
else
|
||||
echo "✗ SSL 证书即将过期或无效"
|
||||
fi
|
||||
|
||||
# 4. 检查服务状态
|
||||
echo "4. 检查服务状态..."
|
||||
services=("nginx" "node-exporter")
|
||||
for service in "${services[@]}"; do
|
||||
if systemctl is-active --quiet "$service"; then
|
||||
echo "✓ $service 服务运行正常"
|
||||
else
|
||||
echo "✗ $service 服务异常"
|
||||
fi
|
||||
done
|
||||
|
||||
# 5. 安全扫描
|
||||
echo "5. 执行安全扫描..."
|
||||
# 运行安全扫描工具
|
||||
|
||||
echo "安全恢复检查完成"
|
||||
```
|
||||
|
||||
## 安全培训
|
||||
|
||||
### 1. 开发安全规范
|
||||
|
||||
#### 代码安全规范
|
||||
|
||||
```markdown
|
||||
# AIOTAGRO 开发安全规范
|
||||
|
||||
## 1. 输入验证
|
||||
- 所有用户输入必须验证
|
||||
- 使用白名单验证策略
|
||||
- 防范 XSS、SQL 注入等攻击
|
||||
|
||||
## 2. 身份认证
|
||||
- 使用强密码策略
|
||||
- 实现多因素认证
|
||||
- 会话超时机制
|
||||
|
||||
## 3. 数据保护
|
||||
- 敏感数据加密存储
|
||||
- 传输层使用 TLS
|
||||
- 最小化数据收集
|
||||
|
||||
## 4. 错误处理
|
||||
- 不暴露系统信息
|
||||
- 记录安全相关错误
|
||||
- 统一的错误处理机制
|
||||
|
||||
## 5. 依赖管理
|
||||
- 定期更新依赖
|
||||
- 使用可信的包源
|
||||
- 扫描依赖的安全漏洞
|
||||
```
|
||||
|
||||
### 2. 运维安全规范
|
||||
|
||||
#### 运维安全清单
|
||||
|
||||
```markdown
|
||||
# AIOTAGRO 运维安全清单
|
||||
|
||||
## 系统安全
|
||||
- [ ] 定期系统更新
|
||||
- [ ] 防火墙配置检查
|
||||
- [ ] 用户权限审核
|
||||
- [ ] 日志审计启用
|
||||
|
||||
## 应用安全
|
||||
- [ ] 安全头配置检查
|
||||
- [ ] SSL/TLS 配置验证
|
||||
- [ ] 应用漏洞扫描
|
||||
- [ ] 备份恢复测试
|
||||
|
||||
## 网络安全
|
||||
- [ ] 网络隔离检查
|
||||
- [ ] 访问控制验证
|
||||
- [ ] 入侵检测配置
|
||||
- [ ] DDoS 防护启用
|
||||
|
||||
## 数据安全
|
||||
- [ ] 数据加密验证
|
||||
- [ ] 访问日志审计
|
||||
- [ ] 数据备份验证
|
||||
- [ ] 隐私保护检查
|
||||
```
|
||||
|
||||
通过以上安全配置和流程,AIOTAGRO 管理系统可以实现全面的安全防护,确保系统稳定可靠运行。
|
||||
562
docs/开发文档.md
Normal file
562
docs/开发文档.md
Normal file
@@ -0,0 +1,562 @@
|
||||
# 开发文档
|
||||
|
||||
## 开发环境搭建
|
||||
|
||||
### 环境要求
|
||||
|
||||
- **Node.js**: 18.0.0 或更高版本
|
||||
- **pnpm**: 8.0.0 或更高版本
|
||||
- **Git**: 2.0.0 或更高版本
|
||||
|
||||
### 安装步骤
|
||||
|
||||
1. **安装 Node.js**
|
||||
```bash
|
||||
# 下载并安装 Node.js 18+
|
||||
# 验证安装
|
||||
node --version
|
||||
npm --version
|
||||
```
|
||||
|
||||
2. **安装 pnpm**
|
||||
```bash
|
||||
# 使用 npm 安装 pnpm
|
||||
npm install -g pnpm
|
||||
|
||||
# 验证安装
|
||||
pnpm --version
|
||||
```
|
||||
|
||||
3. **克隆项目**
|
||||
```bash
|
||||
git clone https://github.com/vbenjs/vue-vben-admin.git
|
||||
cd vue-vben-admin
|
||||
```
|
||||
|
||||
4. **安装依赖**
|
||||
```bash
|
||||
# 安装项目依赖
|
||||
pnpm install
|
||||
```
|
||||
|
||||
5. **启动开发服务器**
|
||||
```bash
|
||||
# 启动 Ant Design 版本
|
||||
pnpm dev:antd
|
||||
|
||||
# 启动 Element Plus 版本
|
||||
pnpm dev:ele
|
||||
|
||||
# 启动 Naive UI 版本
|
||||
pnpm dev:naive
|
||||
```
|
||||
|
||||
## 项目结构说明
|
||||
|
||||
### 目录结构详解
|
||||
|
||||
```
|
||||
yudao-ui-admin-vben/
|
||||
├── apps/ # 应用目录
|
||||
│ ├── web-antd/ # Ant Design 版本
|
||||
│ │ ├── src/ # 源代码
|
||||
│ │ │ ├── api/ # API 接口
|
||||
│ │ │ ├── components/ # 组件
|
||||
│ │ │ ├── layouts/ # 布局
|
||||
│ │ │ ├── router/ # 路由
|
||||
│ │ │ ├── store/ # 状态管理
|
||||
│ │ │ ├── utils/ # 工具函数
|
||||
│ │ │ └── views/ # 页面视图
|
||||
│ │ └── package.json # 应用配置
|
||||
│ ├── web-ele/ # Element Plus 版本
|
||||
│ ├── web-naive/ # Naive UI 版本
|
||||
│ └── backend-mock/ # 后端模拟服务
|
||||
├── packages/ # 共享包目录
|
||||
│ ├── @core/ # 核心功能
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── effects/ # 副作用管理
|
||||
│ ├── icons/ # 图标库
|
||||
│ ├── locales/ # 国际化
|
||||
│ ├── stores/ # 状态管理
|
||||
│ ├── styles/ # 样式文件
|
||||
│ ├── types/ # 类型定义
|
||||
│ └── utils/ # 工具函数
|
||||
└── internal/ # 内部配置
|
||||
├── lint-configs/ # 代码规范
|
||||
├── tailwind-config/ # Tailwind 配置
|
||||
├── tsconfig/ # TypeScript 配置
|
||||
└── vite-config/ # Vite 配置
|
||||
```
|
||||
|
||||
### 核心包说明
|
||||
|
||||
#### @core 包
|
||||
- 基础组件封装
|
||||
- 工具函数集合
|
||||
- 类型定义扩展
|
||||
|
||||
#### stores 包
|
||||
- 全局状态管理
|
||||
- 用户信息存储
|
||||
- 应用配置管理
|
||||
|
||||
#### utils 包
|
||||
- 数据处理工具
|
||||
- 日期时间工具
|
||||
- 表单验证工具
|
||||
|
||||
## 开发规范
|
||||
|
||||
### 代码规范
|
||||
|
||||
#### 1. 命名规范
|
||||
- **文件命名**: 使用 kebab-case (例如: user-info.vue)
|
||||
- **组件命名**: 使用 PascalCase (例如: UserInfo)
|
||||
- **变量命名**: 使用 camelCase (例如: userName)
|
||||
- **常量命名**: 使用 UPPER_SNAKE_CASE (例如: API_BASE_URL)
|
||||
|
||||
#### 2. 组件规范
|
||||
```typescript
|
||||
// 组件结构示例
|
||||
<script setup lang="ts">
|
||||
// 导入
|
||||
import { ref, computed } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
// 类型定义
|
||||
interface Props {
|
||||
userId: number
|
||||
userName: string
|
||||
}
|
||||
|
||||
// Props 定义
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// 状态管理
|
||||
const userStore = useUserStore()
|
||||
const loading = ref(false)
|
||||
|
||||
// 计算属性
|
||||
const fullName = computed(() => `${props.userName} (${props.userId})`)
|
||||
|
||||
// 方法
|
||||
const handleSubmit = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await userStore.updateUser(props.userId, { name: props.userName })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-info">
|
||||
<h3>{{ fullName }}</h3>
|
||||
<button :disabled="loading" @click="handleSubmit">
|
||||
{{ loading ? '保存中...' : '保存' }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-info {
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
#### 3. API 调用规范
|
||||
```typescript
|
||||
// api/user.ts
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
export interface User {
|
||||
id: number
|
||||
name: string
|
||||
email: string
|
||||
}
|
||||
|
||||
export const userApi = {
|
||||
// 获取用户列表
|
||||
getUsers: (params: { page: number; size: number }) => {
|
||||
return request.get<{ list: User[]; total: number }>('/api/users', { params })
|
||||
},
|
||||
|
||||
// 创建用户
|
||||
createUser: (data: Omit<User, 'id'>) => {
|
||||
return request.post<User>('/api/users', data)
|
||||
},
|
||||
|
||||
// 更新用户
|
||||
updateUser: (id: number, data: Partial<User>) => {
|
||||
return request.put<User>(`/api/users/${id}`, data)
|
||||
},
|
||||
|
||||
// 删除用户
|
||||
deleteUser: (id: number) => {
|
||||
return request.delete(`/api/users/${id}`)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 样式规范
|
||||
|
||||
#### 1. CSS 类命名
|
||||
- 使用 BEM 命名规范
|
||||
- 避免使用全局样式
|
||||
- 优先使用 Tailwind CSS
|
||||
|
||||
```css
|
||||
/* BEM 示例 */
|
||||
.user-list {}
|
||||
.user-list__item {}
|
||||
.user-list__item--active {}
|
||||
.user-list__item__avatar {}
|
||||
```
|
||||
|
||||
#### 2. Tailwind CSS 使用
|
||||
```vue
|
||||
<template>
|
||||
<div class="p-4 bg-white rounded-lg shadow-sm">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">用户信息</h3>
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center space-x-3">
|
||||
<span class="text-sm text-gray-500 w-20">姓名:</span>
|
||||
<span class="text-sm text-gray-900">{{ user.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 功能开发指南
|
||||
|
||||
### 1. 新增页面
|
||||
|
||||
#### 步骤 1: 创建页面组件
|
||||
```bash
|
||||
# 在 apps/web-antd/src/views/ 下创建页面目录
|
||||
mkdir -p apps/web-antd/src/views/user-management
|
||||
```
|
||||
|
||||
#### 步骤 2: 创建页面组件
|
||||
```vue
|
||||
<!-- apps/web-antd/src/views/user-management/index.vue -->
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { userApi } from '@/api/user'
|
||||
|
||||
interface User {
|
||||
id: number
|
||||
name: string
|
||||
email: string
|
||||
}
|
||||
|
||||
const users = ref<User[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
const loadUsers = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const response = await userApi.getUsers({ page: 1, size: 10 })
|
||||
users.value = response.data.list
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadUsers()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-management">
|
||||
<h1>用户管理</h1>
|
||||
<div v-if="loading">加载中...</div>
|
||||
<div v-else>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>姓名</th>
|
||||
<th>邮箱</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="user in users" :key="user.id">
|
||||
<td>{{ user.id }}</td>
|
||||
<td>{{ user.name }}</td>
|
||||
<td>{{ user.email }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-management {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
#### 步骤 3: 配置路由
|
||||
```typescript
|
||||
// apps/web-antd/src/router/routes.ts
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
export const routes: RouteRecordRaw[] = [
|
||||
// ... 其他路由
|
||||
{
|
||||
path: '/user-management',
|
||||
name: 'UserManagement',
|
||||
component: () => import('@/views/user-management/index.vue'),
|
||||
meta: {
|
||||
title: '用户管理',
|
||||
requiresAuth: true
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 2. 新增组件
|
||||
|
||||
#### 创建可复用组件
|
||||
```vue
|
||||
<!-- apps/web-antd/src/components/UserAvatar.vue -->
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
user: {
|
||||
name: string
|
||||
avatar?: string
|
||||
}
|
||||
size?: 'small' | 'medium' | 'large'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: 'medium'
|
||||
})
|
||||
|
||||
const sizeMap = {
|
||||
small: 'w-8 h-8',
|
||||
medium: 'w-12 h-12',
|
||||
large: 'w-16 h-16'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-avatar flex items-center space-x-3">
|
||||
<img
|
||||
v-if="user.avatar"
|
||||
:src="user.avatar"
|
||||
:alt="user.name"
|
||||
:class="['rounded-full', sizeMap[size]]"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
:class="['bg-gray-200 rounded-full flex items-center justify-center', sizeMap[size]]"
|
||||
>
|
||||
<span class="text-gray-600 font-medium">{{ user.name.charAt(0) }}</span>
|
||||
</div>
|
||||
<span class="text-gray-900 font-medium">{{ user.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-avatar {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## 开发计划
|
||||
|
||||
### 第一阶段:基础功能开发 (1-2周)
|
||||
|
||||
#### 任务清单
|
||||
- [x] 项目环境搭建
|
||||
- [x] 基础架构配置
|
||||
- [x] 用户登录功能
|
||||
- [x] 权限管理系统
|
||||
- [x] 基础布局组件
|
||||
|
||||
#### 技术要点
|
||||
- Vue3 Composition API 使用
|
||||
- TypeScript 类型定义
|
||||
- Pinia 状态管理
|
||||
- Vue Router 路由配置
|
||||
|
||||
### 第二阶段:业务功能开发 (2-3周)
|
||||
|
||||
#### 任务清单
|
||||
- [x] 用户管理模块
|
||||
- [x] 角色管理模块
|
||||
- [x] 菜单管理模块
|
||||
- [x] 系统设置模块
|
||||
- [x] 数据表格组件
|
||||
|
||||
#### 技术要点
|
||||
- 表单验证处理
|
||||
- 表格数据展示
|
||||
- 分页查询优化
|
||||
- 文件上传下载
|
||||
|
||||
### 第三阶段:优化完善 (1周)
|
||||
|
||||
#### 任务清单
|
||||
- [x] 性能优化
|
||||
- [x] 代码重构
|
||||
- [x] 测试用例编写
|
||||
- [x] 文档完善
|
||||
|
||||
#### 技术要点
|
||||
- 代码分割优化
|
||||
- 懒加载实现
|
||||
- 单元测试覆盖
|
||||
- 文档自动生成
|
||||
|
||||
## 常见问题解决
|
||||
|
||||
### 1. 依赖安装问题
|
||||
|
||||
**问题**: pnpm install 失败
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 清理缓存
|
||||
pnpm store prune
|
||||
|
||||
# 重新安装
|
||||
pnpm install --force
|
||||
```
|
||||
|
||||
### 2. 类型检查错误
|
||||
|
||||
**问题**: TypeScript 类型错误
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 检查类型错误
|
||||
pnpm type-check
|
||||
|
||||
# 自动修复
|
||||
pnpm lint:fix
|
||||
```
|
||||
|
||||
### 3. 构建失败
|
||||
|
||||
**问题**: 生产构建失败
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 清理构建缓存
|
||||
pnpm clean
|
||||
|
||||
# 重新构建
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## 测试指南
|
||||
|
||||
### 单元测试
|
||||
|
||||
```typescript
|
||||
// __tests__/user.spec.ts
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import UserInfo from '@/components/UserInfo.vue'
|
||||
|
||||
describe('UserInfo', () => {
|
||||
it('renders user name correctly', () => {
|
||||
const wrapper = mount(UserInfo, {
|
||||
props: {
|
||||
user: {
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
expect(wrapper.text()).toContain('张三')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### E2E 测试
|
||||
|
||||
```typescript
|
||||
// __tests__/e2e/user.spec.ts
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('user login flow', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
await page.fill('[data-testid="username"]', 'admin')
|
||||
await page.fill('[data-testid="password"]', '123456')
|
||||
await page.click('[data-testid="login-btn"]')
|
||||
|
||||
await expect(page).toHaveURL('/dashboard')
|
||||
})
|
||||
```
|
||||
|
||||
## 部署指南
|
||||
|
||||
### 开发环境部署
|
||||
```bash
|
||||
# 启动开发服务器
|
||||
pnpm dev:antd
|
||||
|
||||
# 访问地址
|
||||
http://localhost:3000
|
||||
```
|
||||
|
||||
### 生产环境部署
|
||||
```bash
|
||||
# 构建生产版本
|
||||
pnpm build:antd
|
||||
|
||||
# 部署到服务器
|
||||
# 将 dist 目录上传到 Web 服务器
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 构建优化
|
||||
- 代码分割
|
||||
- 树摇优化
|
||||
- 压缩资源
|
||||
- 缓存策略
|
||||
|
||||
### 运行时优化
|
||||
- 虚拟滚动
|
||||
- 图片懒加载
|
||||
- 组件懒加载
|
||||
- 防抖节流
|
||||
|
||||
## 安全指南
|
||||
|
||||
### 前端安全
|
||||
- XSS 防护
|
||||
- CSRF 防护
|
||||
- 输入验证
|
||||
- 权限控制
|
||||
|
||||
### 代码安全
|
||||
- 敏感信息加密
|
||||
- API 密钥保护
|
||||
- 代码混淆
|
||||
- 安全审计
|
||||
|
||||
## 维护指南
|
||||
|
||||
### 日常维护
|
||||
- 定期更新依赖
|
||||
- 监控系统性能
|
||||
- 备份重要数据
|
||||
- 安全漏洞修复
|
||||
|
||||
### 版本管理
|
||||
- 使用 Git 版本控制
|
||||
- 遵循语义化版本
|
||||
- 定期发布版本
|
||||
- 维护更新日志
|
||||
307
docs/数据库设计文档.md
Normal file
307
docs/数据库设计文档.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# 数据库设计文档
|
||||
|
||||
## 数据库概述
|
||||
|
||||
本系统采用前后端分离架构,前端不直接操作数据库,但需要了解后端数据库设计以便进行合理的数据交互和界面设计。
|
||||
|
||||
## 数据库选型
|
||||
|
||||
### 推荐数据库
|
||||
- **MySQL 8.0+**: 关系型数据库,事务支持完善
|
||||
- **PostgreSQL 13+**: 高级特性丰富,JSON 支持好
|
||||
- **MongoDB 5.0+**: 文档数据库,灵活 schema
|
||||
|
||||
### 选择建议
|
||||
- 中小型项目: MySQL
|
||||
- 大型复杂项目: PostgreSQL
|
||||
- 快速原型: MongoDB
|
||||
|
||||
## 核心表设计
|
||||
|
||||
### 1. 用户表 (sys_user)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 用户ID |
|
||||
| username | varchar | 50 | ❌ | ✅ | | 用户名 |
|
||||
| password | varchar | 100 | ❌ | ✅ | | 密码(加密) |
|
||||
| nickname | varchar | 50 | ❌ | ❌ | | 昵称 |
|
||||
| email | varchar | 100 | ❌ | ❌ | | 邮箱 |
|
||||
| phone | varchar | 20 | ❌ | ❌ | | 手机号 |
|
||||
| avatar | varchar | 500 | ❌ | ❌ | | 头像 |
|
||||
| status | tinyint | 1 | ❌ | ✅ | 1 | 状态(0禁用,1启用) |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| update_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 唯一索引: UNIQUE KEY uk_username (username)
|
||||
- 普通索引: INDEX idx_email (email)
|
||||
|
||||
### 2. 角色表 (sys_role)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 角色ID |
|
||||
| name | varchar | 50 | ❌ | ✅ | | 角色名称 |
|
||||
| code | varchar | 50 | ❌ | ✅ | | 角色编码 |
|
||||
| description | varchar | 200 | ❌ | ❌ | | 角色描述 |
|
||||
| status | tinyint | 1 | ❌ | ✅ | 1 | 状态(0禁用,1启用) |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| update_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 唯一索引: UNIQUE KEY uk_code (code)
|
||||
|
||||
### 3. 权限表 (sys_permission)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 权限ID |
|
||||
| name | varchar | 50 | ❌ | ✅ | | 权限名称 |
|
||||
| code | varchar | 100 | ❌ | ✅ | | 权限编码 |
|
||||
| type | tinyint | 1 | ❌ | ✅ | | 权限类型(1菜单,2按钮) |
|
||||
| parent_id | bigint | 20 | ❌ | ✅ | 0 | 父级ID |
|
||||
| path | varchar | 200 | ❌ | ❌ | | 路由路径 |
|
||||
| component | varchar | 200 | ❌ | ❌ | | 组件路径 |
|
||||
| icon | varchar | 50 | ❌ | ❌ | | 图标 |
|
||||
| sort | int | 11 | ❌ | ✅ | 0 | 排序 |
|
||||
| status | tinyint | 1 | ❌ | ✅ | 1 | 状态(0禁用,1启用) |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| update_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 普通索引: INDEX idx_parent_id (parent_id)
|
||||
- 普通索引: INDEX idx_type (type)
|
||||
|
||||
### 4. 用户角色关联表 (sys_user_role)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 关联ID |
|
||||
| user_id | bigint | 20 | ❌ | ✅ | | 用户ID |
|
||||
| role_id | bigint | 20 | ❌ | ✅ | | 角色ID |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 唯一索引: UNIQUE KEY uk_user_role (user_id, role_id)
|
||||
- 普通索引: INDEX idx_user_id (user_id)
|
||||
- 普通索引: INDEX idx_role_id (role_id)
|
||||
|
||||
### 5. 角色权限关联表 (sys_role_permission)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 关联ID |
|
||||
| role_id | bigint | 20 | ❌ | ✅ | | 角色ID |
|
||||
| permission_id | bigint | 20 | ❌ | ✅ | | 权限ID |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 唯一索引: UNIQUE KEY uk_role_permission (role_id, permission_id)
|
||||
- 普通索引: INDEX idx_role_id (role_id)
|
||||
- 普通索引: INDEX idx_permission_id (permission_id)
|
||||
|
||||
### 6. 菜单表 (sys_menu)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 菜单ID |
|
||||
| name | varchar | 50 | ❌ | ✅ | | 菜单名称 |
|
||||
| type | tinyint | 1 | ❌ | ✅ | | 菜单类型(1目录,2菜单,3按钮) |
|
||||
| parent_id | bigint | 20 | ❌ | ✅ | 0 | 父级ID |
|
||||
| path | varchar | 200 | ❌ | ❌ | | 路由路径 |
|
||||
| component | varchar | 200 | ❌ | ❌ | | 组件路径 |
|
||||
| icon | varchar | 50 | ❌ | ❌ | | 图标 |
|
||||
| sort | int | 11 | ❌ | ✅ | 0 | 排序 |
|
||||
| status | tinyint | 1 | ❌ | ✅ | 1 | 状态(0禁用,1启用) |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| update_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 普通索引: INDEX idx_parent_id (parent_id)
|
||||
|
||||
## 业务表设计
|
||||
|
||||
### 7. 操作日志表 (sys_operation_log)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 日志ID |
|
||||
| user_id | bigint | 20 | ❌ | ✅ | | 用户ID |
|
||||
| username | varchar | 50 | ❌ | ✅ | | 用户名 |
|
||||
| operation | varchar | 100 | ❌ | ✅ | | 操作描述 |
|
||||
| method | varchar | 10 | ❌ | ✅ | | 请求方法 |
|
||||
| url | varchar | 500 | ❌ | ✅ | | 请求URL |
|
||||
| ip | varchar | 50 | ❌ | ✅ | | IP地址 |
|
||||
| user_agent | varchar | 500 | ❌ | ❌ | | 用户代理 |
|
||||
| params | text | | ❌ | ❌ | | 请求参数 |
|
||||
| result | text | | ❌ | ❌ | | 返回结果 |
|
||||
| status | tinyint | 1 | ❌ | ✅ | 1 | 状态(0失败,1成功) |
|
||||
| error_msg | text | | ❌ | ❌ | | 错误信息 |
|
||||
| execute_time | int | 11 | ❌ | ✅ | 0 | 执行时间(ms) |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 普通索引: INDEX idx_user_id (user_id)
|
||||
- 普通索引: INDEX idx_create_time (create_time)
|
||||
|
||||
### 8. 字典表 (sys_dict)
|
||||
|
||||
| 字段名 | 类型 | 长度 | 主键 | 非空 | 默认值 | 说明 |
|
||||
|--------|------|------|------|------|--------|------|
|
||||
| id | bigint | 20 | ✅ | ✅ | 自增 | 字典ID |
|
||||
| type | varchar | 50 | ❌ | ✅ | | 字典类型 |
|
||||
| code | varchar | 50 | ❌ | ✅ | | 字典编码 |
|
||||
| name | varchar | 100 | ❌ | ✅ | | 字典名称 |
|
||||
| value | varchar | 200 | ❌ | ❌ | | 字典值 |
|
||||
| sort | int | 11 | ❌ | ✅ | 0 | 排序 |
|
||||
| status | tinyint | 1 | ❌ | ✅ | 1 | 状态(0禁用,1启用) |
|
||||
| description | varchar | 200 | ❌ | ❌ | | 描述 |
|
||||
| create_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| update_time | datetime | | ❌ | ✅ | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引设计:**
|
||||
- 主键索引: PRIMARY KEY (id)
|
||||
- 唯一索引: UNIQUE KEY uk_type_code (type, code)
|
||||
- 普通索引: INDEX idx_type (type)
|
||||
|
||||
## 数据库关系图
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
sys_user ||--o{ sys_user_role : has
|
||||
sys_role ||--o{ sys_user_role : has
|
||||
sys_role ||--o{ sys_role_permission : has
|
||||
sys_permission ||--o{ sys_role_permission : has
|
||||
sys_permission ||--o{ sys_menu : extends
|
||||
|
||||
sys_user {
|
||||
bigint id PK
|
||||
varchar username
|
||||
varchar password
|
||||
varchar nickname
|
||||
varchar email
|
||||
varchar phone
|
||||
varchar avatar
|
||||
tinyint status
|
||||
datetime create_time
|
||||
datetime update_time
|
||||
}
|
||||
|
||||
sys_role {
|
||||
bigint id PK
|
||||
varchar name
|
||||
varchar code
|
||||
varchar description
|
||||
tinyint status
|
||||
datetime create_time
|
||||
datetime update_time
|
||||
}
|
||||
|
||||
sys_permission {
|
||||
bigint id PK
|
||||
varchar name
|
||||
varchar code
|
||||
tinyint type
|
||||
bigint parent_id
|
||||
varchar path
|
||||
varchar component
|
||||
varchar icon
|
||||
int sort
|
||||
tinyint status
|
||||
datetime create_time
|
||||
datetime update_time
|
||||
}
|
||||
|
||||
sys_user_role {
|
||||
bigint id PK
|
||||
bigint user_id
|
||||
bigint role_id
|
||||
datetime create_time
|
||||
}
|
||||
|
||||
sys_role_permission {
|
||||
bigint id PK
|
||||
bigint role_id
|
||||
bigint permission_id
|
||||
datetime create_time
|
||||
}
|
||||
```
|
||||
|
||||
## 数据字典
|
||||
|
||||
### 状态枚举
|
||||
|
||||
| 表名 | 字段名 | 枚举值 | 说明 |
|
||||
|------|--------|--------|------|
|
||||
| sys_user | status | 0 | 禁用 |
|
||||
| sys_user | status | 1 | 启用 |
|
||||
| sys_role | status | 0 | 禁用 |
|
||||
| sys_role | status | 1 | 启用 |
|
||||
| sys_permission | status | 0 | 禁用 |
|
||||
| sys_permission | status | 1 | 启用 |
|
||||
| sys_operation_log | status | 0 | 失败 |
|
||||
| sys_operation_log | status | 1 | 成功 |
|
||||
|
||||
### 类型枚举
|
||||
|
||||
| 表名 | 字段名 | 枚举值 | 说明 |
|
||||
|------|--------|--------|------|
|
||||
| sys_permission | type | 1 | 菜单权限 |
|
||||
| sys_permission | type | 2 | 按钮权限 |
|
||||
| sys_menu | type | 1 | 目录 |
|
||||
| sys_menu | type | 2 | 菜单 |
|
||||
| sys_menu | type | 3 | 按钮 |
|
||||
|
||||
## 数据库优化建议
|
||||
|
||||
### 1. 索引优化
|
||||
- 为常用查询字段建立索引
|
||||
- 避免过度索引影响写入性能
|
||||
- 定期分析索引使用情况
|
||||
|
||||
### 2. 查询优化
|
||||
- 使用分页查询避免大数据量
|
||||
- 避免 SELECT * 查询
|
||||
- 合理使用 JOIN 查询
|
||||
|
||||
### 3. 存储优化
|
||||
- 合理设置字段长度
|
||||
- 使用合适的数据类型
|
||||
- 定期清理历史数据
|
||||
|
||||
### 4. 安全优化
|
||||
- 敏感字段加密存储
|
||||
- 定期备份数据
|
||||
- 访问权限控制
|
||||
|
||||
## 迁移策略
|
||||
|
||||
### 版本管理
|
||||
- 使用 Flyway 或 Liquibase 进行数据库版本管理
|
||||
- 每个版本创建对应的迁移脚本
|
||||
- 测试环境先行验证
|
||||
|
||||
### 数据迁移
|
||||
- 生产环境数据备份
|
||||
- 灰度发布验证
|
||||
- 回滚方案准备
|
||||
|
||||
## 监控维护
|
||||
|
||||
### 性能监控
|
||||
- 慢查询日志分析
|
||||
- 连接数监控
|
||||
- 磁盘空间监控
|
||||
|
||||
### 日常维护
|
||||
- 定期数据备份
|
||||
- 索引重建优化
|
||||
- 日志文件清理
|
||||
551
docs/测试文档.md
Normal file
551
docs/测试文档.md
Normal file
@@ -0,0 +1,551 @@
|
||||
# 测试文档
|
||||
|
||||
## 测试概述
|
||||
|
||||
AIOTAGRO 管理系统采用全面的测试策略,确保系统质量和稳定性。测试覆盖单元测试、集成测试和端到端测试。
|
||||
|
||||
## 测试环境
|
||||
|
||||
### 环境要求
|
||||
|
||||
- **Node.js**: 18.0.0+
|
||||
- **pnpm**: 8.0.0+
|
||||
- **浏览器**: Chrome 90+, Firefox 85+, Safari 14+
|
||||
|
||||
### 测试工具栈
|
||||
|
||||
| 工具 | 版本 | 用途 |
|
||||
|------|------|------|
|
||||
| Vitest | 1.0.0+ | 单元测试框架 |
|
||||
| Vue Test Utils | 2.4.0+ | Vue 组件测试 |
|
||||
| Playwright | 1.40.0+ | E2E 测试 |
|
||||
| Testing Library | 6.0.0+ | 组件测试工具 |
|
||||
|
||||
## 单元测试
|
||||
|
||||
### 测试配置
|
||||
|
||||
```typescript
|
||||
// vitest.config.ts
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
include: ['**/__tests__/**/*.spec.ts'],
|
||||
coverage: {
|
||||
reporter: ['text', 'json', 'html'],
|
||||
exclude: [
|
||||
'node_modules/',
|
||||
'dist/',
|
||||
'**/*.d.ts',
|
||||
'**/types/**'
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 组件测试示例
|
||||
|
||||
```typescript
|
||||
// __tests__/components/UserInfo.spec.ts
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import UserInfo from '@/components/UserInfo.vue'
|
||||
|
||||
describe('UserInfo', () => {
|
||||
it('renders user information correctly', () => {
|
||||
const user = {
|
||||
id: 1,
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
avatar: '/avatar.jpg'
|
||||
}
|
||||
|
||||
const wrapper = mount(UserInfo, {
|
||||
props: { user }
|
||||
})
|
||||
|
||||
expect(wrapper.text()).toContain('张三')
|
||||
expect(wrapper.text()).toContain('zhangsan@example.com')
|
||||
expect(wrapper.find('img').attributes('src')).toBe('/avatar.jpg')
|
||||
})
|
||||
|
||||
it('emits edit event when edit button is clicked', async () => {
|
||||
const user = {
|
||||
id: 1,
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com'
|
||||
}
|
||||
|
||||
const wrapper = mount(UserInfo, {
|
||||
props: { user }
|
||||
})
|
||||
|
||||
await wrapper.find('[data-testid="edit-btn"]').trigger('click')
|
||||
expect(wrapper.emitted('edit')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### 工具函数测试
|
||||
|
||||
```typescript
|
||||
// __tests__/utils/format.spec.ts
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { formatDate, formatCurrency } from '@/utils/format'
|
||||
|
||||
describe('format utils', () => {
|
||||
describe('formatDate', () => {
|
||||
it('formats date correctly', () => {
|
||||
const date = new Date('2023-12-01')
|
||||
expect(formatDate(date)).toBe('2023-12-01')
|
||||
})
|
||||
|
||||
it('handles invalid date', () => {
|
||||
expect(formatDate(null)).toBe('')
|
||||
expect(formatDate(undefined)).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('formatCurrency', () => {
|
||||
it('formats currency correctly', () => {
|
||||
expect(formatCurrency(1234.56)).toBe('¥1,234.56')
|
||||
expect(formatCurrency(0)).toBe('¥0.00')
|
||||
})
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 集成测试
|
||||
|
||||
### API 集成测试
|
||||
|
||||
```typescript
|
||||
// __tests__/api/user.spec.ts
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { userApi } from '@/api/user'
|
||||
import { mockServer } from '../mocks/server'
|
||||
|
||||
describe('User API', () => {
|
||||
beforeEach(() => {
|
||||
mockServer.listen()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
mockServer.resetHandlers()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
mockServer.close()
|
||||
})
|
||||
|
||||
it('fetches user list successfully', async () => {
|
||||
const response = await userApi.getUsers({ page: 1, size: 10 })
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
expect(response.data.list).toHaveLength(2)
|
||||
expect(response.data.total).toBe(2)
|
||||
})
|
||||
|
||||
it('handles API errors correctly', async () => {
|
||||
mockServer.use(
|
||||
rest.get('/api/users', (req, res, ctx) => {
|
||||
return res(ctx.status(500), ctx.json({ message: 'Internal Server Error' }))
|
||||
})
|
||||
)
|
||||
|
||||
await expect(userApi.getUsers({ page: 1, size: 10 })).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### 状态管理测试
|
||||
|
||||
```typescript
|
||||
// __tests__/stores/user.spec.ts
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { setActivePinia, createPinia } from 'pinia'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
describe('User Store', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
})
|
||||
|
||||
it('initializes with default values', () => {
|
||||
const store = useUserStore()
|
||||
|
||||
expect(store.user).toBeNull()
|
||||
expect(store.isLoggedIn).toBe(false)
|
||||
expect(store.loading).toBe(false)
|
||||
})
|
||||
|
||||
it('sets user correctly', () => {
|
||||
const store = useUserStore()
|
||||
const user = { id: 1, name: '张三', email: 'zhangsan@example.com' }
|
||||
|
||||
store.setUser(user)
|
||||
|
||||
expect(store.user).toEqual(user)
|
||||
expect(store.isLoggedIn).toBe(true)
|
||||
})
|
||||
|
||||
it('clears user on logout', () => {
|
||||
const store = useUserStore()
|
||||
const user = { id: 1, name: '张三', email: 'zhangsan@example.com' }
|
||||
|
||||
store.setUser(user)
|
||||
store.logout()
|
||||
|
||||
expect(store.user).toBeNull()
|
||||
expect(store.isLoggedIn).toBe(false)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## E2E 测试
|
||||
|
||||
### 测试配置
|
||||
|
||||
```typescript
|
||||
// playwright.config.ts
|
||||
import { defineConfig, devices } from '@playwright/test'
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './__tests__/e2e',
|
||||
fullyParallel: true,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
reporter: 'html',
|
||||
|
||||
use: {
|
||||
baseURL: 'http://localhost:3000',
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
{
|
||||
name: 'webkit',
|
||||
use: { ...devices['Desktop Safari'] },
|
||||
},
|
||||
],
|
||||
|
||||
webServer: {
|
||||
command: 'pnpm dev:antd',
|
||||
url: 'http://localhost:3000',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### 登录流程测试
|
||||
|
||||
```typescript
|
||||
// __tests__/e2e/login.spec.ts
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test.describe('Login Flow', () => {
|
||||
test('should login successfully with valid credentials', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
|
||||
// 填写登录表单
|
||||
await page.fill('[data-testid="username"]', 'admin')
|
||||
await page.fill('[data-testid="password"]', '123456')
|
||||
await page.click('[data-testid="login-btn"]')
|
||||
|
||||
// 验证登录成功
|
||||
await expect(page).toHaveURL('/dashboard')
|
||||
await expect(page.locator('[data-testid="user-name"]')).toContainText('管理员')
|
||||
})
|
||||
|
||||
test('should show error message with invalid credentials', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
|
||||
// 填写错误凭证
|
||||
await page.fill('[data-testid="username"]', 'wronguser')
|
||||
await page.fill('[data-testid="password"]', 'wrongpass')
|
||||
await page.click('[data-testid="login-btn"]')
|
||||
|
||||
// 验证错误提示
|
||||
await expect(page.locator('[data-testid="error-message"]')).toBeVisible()
|
||||
await expect(page).toHaveURL('/login')
|
||||
})
|
||||
|
||||
test('should redirect to login when accessing protected page without authentication', async ({ page }) => {
|
||||
// 直接访问受保护页面
|
||||
await page.goto('/user-management')
|
||||
|
||||
// 验证重定向到登录页
|
||||
await expect(page).toHaveURL('/login')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### 用户管理测试
|
||||
|
||||
```typescript
|
||||
// __tests__/e2e/user-management.spec.ts
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test.describe('User Management', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// 登录
|
||||
await page.goto('/login')
|
||||
await page.fill('[data-testid="username"]', 'admin')
|
||||
await page.fill('[data-testid="password"]', '123456')
|
||||
await page.click('[data-testid="login-btn"]')
|
||||
await page.goto('/user-management')
|
||||
})
|
||||
|
||||
test('should display user list', async ({ page }) => {
|
||||
await expect(page.locator('[data-testid="user-table"]')).toBeVisible()
|
||||
await expect(page.locator('[data-testid="user-row"]').first()).toBeVisible()
|
||||
})
|
||||
|
||||
test('should create new user', async ({ page }) => {
|
||||
// 点击新建按钮
|
||||
await page.click('[data-testid="create-user-btn"]')
|
||||
|
||||
// 填写用户信息
|
||||
await page.fill('[data-testid="user-name"]', '测试用户')
|
||||
await page.fill('[data-testid="user-email"]', 'test@example.com')
|
||||
await page.click('[data-testid="save-btn"]')
|
||||
|
||||
// 验证创建成功
|
||||
await expect(page.locator('[data-testid="success-message"]')).toBeVisible()
|
||||
await expect(page.locator('[data-testid="user-table"]')).toContainText('测试用户')
|
||||
})
|
||||
|
||||
test('should delete user', async ({ page }) => {
|
||||
// 点击删除按钮
|
||||
await page.click('[data-testid="delete-user-btn"]').first()
|
||||
await page.click('[data-testid="confirm-delete-btn"]')
|
||||
|
||||
// 验证删除成功
|
||||
await expect(page.locator('[data-testid="success-message"]')).toBeVisible()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 性能测试
|
||||
|
||||
### 加载性能测试
|
||||
|
||||
```typescript
|
||||
// __tests__/performance/loading.spec.ts
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test.describe('Performance Tests', () => {
|
||||
test('should load dashboard within 3 seconds', async ({ page }) => {
|
||||
const startTime = Date.now()
|
||||
await page.goto('/dashboard')
|
||||
const loadTime = Date.now() - startTime
|
||||
|
||||
expect(loadTime).toBeLessThan(3000)
|
||||
})
|
||||
|
||||
test('should render user table with 1000 rows efficiently', async ({ page }) => {
|
||||
await page.goto('/user-management')
|
||||
|
||||
// 模拟大量数据
|
||||
await page.evaluate(() => {
|
||||
window.performance.mark('table-render-start')
|
||||
})
|
||||
|
||||
// 等待表格渲染完成
|
||||
await page.waitForSelector('[data-testid="user-table"]')
|
||||
|
||||
const renderTime = await page.evaluate(() => {
|
||||
window.performance.mark('table-render-end')
|
||||
window.performance.measure('table-render', 'table-render-start', 'table-render-end')
|
||||
const measure = window.performance.getEntriesByName('table-render')[0]
|
||||
return measure.duration
|
||||
})
|
||||
|
||||
expect(renderTime).toBeLessThan(1000)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 安全测试
|
||||
|
||||
### XSS 防护测试
|
||||
|
||||
```typescript
|
||||
// __tests__/security/xss.spec.ts
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test.describe('Security Tests', () => {
|
||||
test('should sanitize user input to prevent XSS', async ({ page }) => {
|
||||
await page.goto('/user-management')
|
||||
|
||||
// 尝试注入 XSS 代码
|
||||
const xssPayload = '<script>alert("XSS")</script>'
|
||||
await page.fill('[data-testid="user-name"]', xssPayload)
|
||||
await page.click('[data-testid="save-btn"]')
|
||||
|
||||
// 验证输入被正确转义
|
||||
const userNameCell = await page.locator('[data-testid="user-name"]').first()
|
||||
const innerHTML = await userNameCell.innerHTML()
|
||||
|
||||
expect(innerHTML).not.toContain('<script>')
|
||||
expect(innerHTML).toContain('<script>')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 测试覆盖率
|
||||
|
||||
### 覆盖率配置
|
||||
|
||||
```json
|
||||
{
|
||||
"coverage": {
|
||||
"provider": "v8",
|
||||
"reporter": ["text", "json", "html"],
|
||||
"reportsDirectory": "./coverage",
|
||||
"exclude": [
|
||||
"**/*.d.ts",
|
||||
"**/types/**",
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
"**/coverage/**"
|
||||
],
|
||||
"thresholds": {
|
||||
"lines": 80,
|
||||
"functions": 80,
|
||||
"branches": 70,
|
||||
"statements": 80
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 覆盖率报告
|
||||
|
||||
```bash
|
||||
# 生成覆盖率报告
|
||||
pnpm test:coverage
|
||||
|
||||
# 查看 HTML 报告
|
||||
open coverage/index.html
|
||||
```
|
||||
|
||||
## 测试执行
|
||||
|
||||
### 开发环境测试
|
||||
|
||||
```bash
|
||||
# 运行单元测试
|
||||
pnpm test:unit
|
||||
|
||||
# 运行 E2E 测试
|
||||
pnpm test:e2e
|
||||
|
||||
# 运行所有测试
|
||||
pnpm test
|
||||
```
|
||||
|
||||
### CI/CD 环境测试
|
||||
|
||||
```yaml
|
||||
# .github/workflows/test.yml
|
||||
name: Test
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- run: pnpm install
|
||||
- run: pnpm test:unit
|
||||
- run: pnpm test:e2e
|
||||
- run: pnpm test:coverage
|
||||
```
|
||||
|
||||
## 测试最佳实践
|
||||
|
||||
### 1. 测试命名规范
|
||||
- 描述性测试名称
|
||||
- 使用 Given-When-Then 模式
|
||||
- 避免模糊的测试描述
|
||||
|
||||
### 2. 测试数据管理
|
||||
- 使用测试工厂函数
|
||||
- 避免硬编码数据
|
||||
- 清理测试数据
|
||||
|
||||
### 3. 测试隔离
|
||||
- 每个测试独立运行
|
||||
- 避免测试间依赖
|
||||
- 使用 beforeEach/afterEach
|
||||
|
||||
### 4. 异步测试
|
||||
- 正确处理异步操作
|
||||
- 使用适当的等待策略
|
||||
- 避免不必要的等待
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
#### 1. 测试超时
|
||||
```typescript
|
||||
// 增加超时时间
|
||||
test('slow operation', async ({ page }) => {
|
||||
test.setTimeout(60000)
|
||||
// 测试代码
|
||||
})
|
||||
```
|
||||
|
||||
#### 2. 元素找不到
|
||||
```typescript
|
||||
// 使用更稳定的选择器
|
||||
await page.locator('[data-testid="submit-btn"]').click()
|
||||
```
|
||||
|
||||
#### 3. 网络请求失败
|
||||
```typescript
|
||||
// 等待网络请求完成
|
||||
await page.waitForResponse(response =>
|
||||
response.url().includes('/api/users') && response.status() === 200
|
||||
)
|
||||
```
|
||||
|
||||
## 测试报告
|
||||
|
||||
### 生成测试报告
|
||||
|
||||
```bash
|
||||
# 生成 JUnit 报告
|
||||
pnpm test:report
|
||||
|
||||
# 生成覆盖率报告
|
||||
pnpm test:coverage:report
|
||||
```
|
||||
|
||||
### 报告解读
|
||||
|
||||
- **测试通过率**: 应保持在 95% 以上
|
||||
- **代码覆盖率**: 单元测试覆盖率应达到 80% 以上
|
||||
- **性能指标**: 关键页面加载时间应小于 3 秒
|
||||
- **安全测试**: 所有安全测试必须通过
|
||||
246
docs/用户手册-附录.md
Normal file
246
docs/用户手册-附录.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# 用户手册 - 附录
|
||||
|
||||
## 快捷键列表
|
||||
|
||||
### 全局快捷键
|
||||
|
||||
| 快捷键 | 功能 | 说明 |
|
||||
|--------|------|------|
|
||||
| `Ctrl + K` | 快速搜索 | 打开全局搜索框 |
|
||||
| `Ctrl + ,` | 打开设置 | 打开系统设置页面 |
|
||||
| `F1` | 帮助 | 打开帮助文档 |
|
||||
| `Ctrl + S` | 保存 | 保存当前表单 |
|
||||
| `Ctrl + Z` | 撤销 | 撤销上一步操作 |
|
||||
| `Ctrl + Y` | 重做 | 重做撤销的操作 |
|
||||
|
||||
### 数据操作快捷键
|
||||
|
||||
| 快捷键 | 功能 | 说明 |
|
||||
|--------|------|------|
|
||||
| `Ctrl + F` | 查找 | 在当前页面查找 |
|
||||
| `Ctrl + A` | 全选 | 选择所有数据 |
|
||||
| `Ctrl + C` | 复制 | 复制选中数据 |
|
||||
| `Ctrl + V` | 粘贴 | 粘贴数据 |
|
||||
| `Delete` | 删除 | 删除选中数据 |
|
||||
| `Enter` | 确认 | 确认操作或保存 |
|
||||
|
||||
### 导航快捷键
|
||||
|
||||
| 快捷键 | 功能 | 说明 |
|
||||
|--------|------|------|
|
||||
| `Alt + 1` | 仪表盘 | 跳转到仪表盘 |
|
||||
| `Alt + 2` | 用户管理 | 跳转到用户管理 |
|
||||
| `Alt + 3` | 角色管理 | 跳转到角色管理 |
|
||||
| `Alt + 4` | 菜单管理 | 跳转到菜单管理 |
|
||||
| `Alt + 5` | 部门管理 | 跳转到部门管理 |
|
||||
| `Alt + 6` | 系统设置 | 跳转到系统设置 |
|
||||
|
||||
## 错误代码说明
|
||||
|
||||
### 系统错误代码
|
||||
|
||||
| 错误代码 | 错误描述 | 解决方案 |
|
||||
|----------|----------|----------|
|
||||
| 1001 | 系统内部错误 | 联系技术支持 |
|
||||
| 1002 | 数据库连接失败 | 检查数据库服务 |
|
||||
| 1003 | 文件系统错误 | 检查磁盘空间和权限 |
|
||||
| 1004 | 内存不足 | 重启系统或增加内存 |
|
||||
|
||||
### 用户错误代码
|
||||
|
||||
| 错误代码 | 错误描述 | 解决方案 |
|
||||
|----------|----------|----------|
|
||||
| 2001 | 用户未登录 | 重新登录系统 |
|
||||
| 2002 | 权限不足 | 检查用户权限设置 |
|
||||
| 2003 | 会话过期 | 重新登录系统 |
|
||||
| 2004 | 账号被禁用 | 联系管理员启用账号 |
|
||||
| 2005 | 密码错误 | 检查密码或重置密码 |
|
||||
|
||||
### 数据错误代码
|
||||
|
||||
| 错误代码 | 错误描述 | 解决方案 |
|
||||
|----------|----------|----------|
|
||||
| 3001 | 数据不存在 | 检查数据ID是否正确 |
|
||||
| 3002 | 数据重复 | 检查数据唯一性约束 |
|
||||
| 3003 | 数据格式错误 | 检查数据格式要求 |
|
||||
| 3004 | 数据关联错误 | 检查关联数据是否存在 |
|
||||
|
||||
### 网络错误代码
|
||||
|
||||
| 错误代码 | 错误描述 | 解决方案 |
|
||||
|----------|----------|----------|
|
||||
| 4001 | 网络连接超时 | 检查网络连接 |
|
||||
| 4002 | 服务器无响应 | 检查服务器状态 |
|
||||
| 4003 | DNS解析失败 | 检查DNS配置 |
|
||||
| 4004 | SSL证书错误 | 检查证书有效性 |
|
||||
|
||||
## 数据格式规范
|
||||
|
||||
### 日期时间格式
|
||||
|
||||
| 字段类型 | 格式 | 示例 | 说明 |
|
||||
|----------|------|------|------|
|
||||
| 日期 | YYYY-MM-DD | 2024-01-15 | ISO 8601 标准 |
|
||||
| 时间 | HH:mm:ss | 14:30:00 | 24小时制 |
|
||||
| 日期时间 | YYYY-MM-DD HH:mm:ss | 2024-01-15 14:30:00 | 完整时间戳 |
|
||||
|
||||
### 数字格式
|
||||
|
||||
| 字段类型 | 格式 | 示例 | 说明 |
|
||||
|----------|------|------|------|
|
||||
| 整数 | 无分隔符 | 12345 | 纯数字 |
|
||||
| 小数 | 两位小数 | 123.45 | 小数点后两位 |
|
||||
| 百分比 | 百分比格式 | 12.34% | 自动转换 |
|
||||
| 货币 | 货币格式 | ¥123.45 | 根据地区设置 |
|
||||
|
||||
### 文件格式要求
|
||||
|
||||
| 文件类型 | 支持格式 | 大小限制 | 说明 |
|
||||
|----------|----------|----------|------|
|
||||
| 图片 | JPG, PNG, GIF, WebP | 5MB | 支持常见图片格式 |
|
||||
| 文档 | PDF, DOC, DOCX, XLS, XLSX | 10MB | Office文档 |
|
||||
| 压缩包 | ZIP, RAR | 50MB | 压缩文件 |
|
||||
| 其他 | TXT, CSV, JSON | 2MB | 文本文件 |
|
||||
|
||||
## 系统限制说明
|
||||
|
||||
### 数据量限制
|
||||
|
||||
| 项目 | 限制 | 说明 |
|
||||
|------|------|------|
|
||||
| 单页显示数据 | 100条 | 分页显示大量数据 |
|
||||
| 导出数据量 | 10000条 | 单次导出最大数量 |
|
||||
| 导入数据量 | 5000条 | 单次导入最大数量 |
|
||||
| 文件上传大小 | 100MB | 单个文件最大大小 |
|
||||
|
||||
### 操作频率限制
|
||||
|
||||
| 操作类型 | 频率限制 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 登录尝试 | 5次/分钟 | 防止暴力破解 |
|
||||
| 数据查询 | 100次/分钟 | 防止过度查询 |
|
||||
| 数据导出 | 10次/小时 | 防止资源滥用 |
|
||||
| 邮件发送 | 50封/小时 | 防止垃圾邮件 |
|
||||
|
||||
### 存储空间限制
|
||||
|
||||
| 用户类型 | 存储空间 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 普通用户 | 1GB | 个人文件存储 |
|
||||
| 管理员 | 10GB | 系统文件存储 |
|
||||
| 超级管理员 | 无限制 | 系统管理需要 |
|
||||
|
||||
## 浏览器兼容性
|
||||
|
||||
### 完全支持
|
||||
|
||||
| 浏览器 | 最低版本 | 推荐版本 |
|
||||
|--------|----------|----------|
|
||||
| Chrome | 90 | 100+ |
|
||||
| Firefox | 88 | 95+ |
|
||||
| Safari | 14 | 15+ |
|
||||
| Edge | 90 | 100+ |
|
||||
|
||||
### 部分支持
|
||||
|
||||
| 浏览器 | 支持情况 | 限制说明 |
|
||||
|--------|----------|----------|
|
||||
| IE 11 | 基本功能 | 部分高级功能不可用 |
|
||||
| Opera | 大部分功能 | 兼容性良好 |
|
||||
| 移动端浏览器 | 响应式设计 | 适配移动设备 |
|
||||
|
||||
### 不支持的浏览器
|
||||
|
||||
| 浏览器 | 原因 | 替代方案 |
|
||||
|--------|------|----------|
|
||||
| IE 10及以下 | 技术过时 | 升级到现代浏览器 |
|
||||
| 老旧移动浏览器 | 功能限制 | 使用主流浏览器 |
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 客户端优化
|
||||
|
||||
1. **浏览器设置**
|
||||
- 启用硬件加速
|
||||
- 清理浏览器缓存
|
||||
- 关闭不必要的扩展
|
||||
|
||||
2. **网络优化**
|
||||
- 使用有线网络连接
|
||||
- 避免同时下载大文件
|
||||
- 使用CDN加速
|
||||
|
||||
### 服务器端优化
|
||||
|
||||
1. **资源管理**
|
||||
- 定期清理临时文件
|
||||
- 优化数据库查询
|
||||
- 使用缓存机制
|
||||
|
||||
2. **负载均衡**
|
||||
- 分布式部署
|
||||
- 负载均衡配置
|
||||
- 自动扩容机制
|
||||
|
||||
## 故障排除指南
|
||||
|
||||
### 常见问题解决
|
||||
|
||||
#### 页面无法加载
|
||||
1. 检查网络连接
|
||||
2. 清除浏览器缓存
|
||||
3. 尝试其他浏览器
|
||||
4. 联系技术支持
|
||||
|
||||
#### 功能无法使用
|
||||
1. 检查用户权限
|
||||
2. 查看错误提示信息
|
||||
3. 重新登录系统
|
||||
4. 联系管理员
|
||||
|
||||
#### 数据异常
|
||||
1. 检查数据格式
|
||||
2. 验证数据完整性
|
||||
3. 查看操作日志
|
||||
4. 联系技术支持
|
||||
|
||||
### 紧急处理流程
|
||||
|
||||
#### 系统无法访问
|
||||
1. 立即联系技术支持
|
||||
2. 提供错误现象描述
|
||||
3. 配合技术排查
|
||||
4. 等待系统恢复
|
||||
|
||||
#### 数据丢失
|
||||
1. 停止所有操作
|
||||
2. 立即联系技术支持
|
||||
3. 提供数据备份信息
|
||||
4. 等待数据恢复
|
||||
|
||||
## 联系方式
|
||||
|
||||
### 技术支持
|
||||
|
||||
- **电话支持**: 400-xxx-xxxx
|
||||
- **邮箱支持**: support@aiotagro.com
|
||||
- **在线客服**: 系统内在线聊天
|
||||
- **工作时间**: 工作日 9:00-18:00
|
||||
|
||||
### 反馈渠道
|
||||
|
||||
- **产品建议**: product@aiotagro.com
|
||||
- **问题反馈**: feedback@aiotagro.com
|
||||
- **技术合作**: tech@aiotagro.com
|
||||
- **商务合作**: business@aiotagro.com
|
||||
|
||||
### 文档更新
|
||||
|
||||
- **最新版本**: 查看系统内版本信息
|
||||
- **更新日志**: 查看版本更新说明
|
||||
- **文档下载**: 官网文档中心
|
||||
- **培训资料**: 联系客户成功团队
|
||||
|
||||
---
|
||||
|
||||
*本附录会随系统版本更新而更新,请定期查看最新版本。如有任何补充建议,请联系产品团队。*
|
||||
397
docs/用户手册.md
Normal file
397
docs/用户手册.md
Normal file
@@ -0,0 +1,397 @@
|
||||
# 用户手册
|
||||
|
||||
## 产品概述
|
||||
|
||||
AIOTAGRO 管理系统是一个基于 Vue3 + TypeScript 的现代化企业级管理系统,提供丰富的功能模块和优秀的用户体验。本文档为用户提供完整的产品使用指南。
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 系统访问
|
||||
|
||||
#### 访问地址
|
||||
- 生产环境: https://aiotagro.com
|
||||
- 测试环境: https://test.aiotagro.com
|
||||
- 开发环境: http://localhost:3000
|
||||
|
||||
#### 浏览器要求
|
||||
- Chrome 90+ (推荐)
|
||||
- Firefox 88+
|
||||
- Safari 14+
|
||||
- Edge 90+
|
||||
|
||||
### 2. 首次登录
|
||||
|
||||
#### 账号注册
|
||||
1. 访问系统登录页面
|
||||
2. 点击"注册新账号"
|
||||
3. 填写注册信息(邮箱、手机号、密码)
|
||||
4. 完成邮箱/手机验证
|
||||
5. 登录系统
|
||||
|
||||
#### 密码要求
|
||||
- 长度至少8位字符
|
||||
- 包含大写字母、小写字母、数字
|
||||
- 建议使用特殊字符增强安全性
|
||||
|
||||
## 系统功能
|
||||
|
||||
### 1. 仪表盘
|
||||
|
||||
#### 功能概述
|
||||
仪表盘是系统的首页,提供关键业务数据的可视化展示和快速访问入口。
|
||||
|
||||
#### 主要功能
|
||||
- **数据概览**: 显示核心业务指标
|
||||
- **快捷操作**: 常用功能快速入口
|
||||
- **消息通知**: 系统消息和待办事项
|
||||
- **图表展示**: 数据趋势和统计分析
|
||||
|
||||
#### 使用指南
|
||||
1. 登录系统后自动进入仪表盘
|
||||
2. 点击各个卡片查看详细信息
|
||||
3. 使用搜索框快速查找功能
|
||||
4. 自定义仪表盘布局(拖拽调整)
|
||||
|
||||
### 2. 用户管理
|
||||
|
||||
#### 功能概述
|
||||
用户管理模块用于管理系统用户账号、权限和角色。
|
||||
|
||||
#### 用户列表
|
||||
- **查看用户**: 显示所有用户信息
|
||||
- **搜索用户**: 按姓名、邮箱、角色搜索
|
||||
- **筛选用户**: 按状态、部门、角色筛选
|
||||
- **批量操作**: 批量启用/禁用用户
|
||||
|
||||
#### 添加用户
|
||||
1. 点击"添加用户"按钮
|
||||
2. 填写用户基本信息
|
||||
3. 设置用户角色和权限
|
||||
4. 发送账号激活邮件
|
||||
|
||||
#### 用户编辑
|
||||
- **基本信息**: 修改姓名、邮箱、电话
|
||||
- **权限设置**: 调整用户角色和权限
|
||||
- **状态管理**: 启用/禁用用户账号
|
||||
- **密码重置**: 重置用户登录密码
|
||||
|
||||
### 3. 角色管理
|
||||
|
||||
#### 功能概述
|
||||
角色管理用于定义系统权限组,实现精细化的权限控制。
|
||||
|
||||
#### 角色列表
|
||||
- **查看角色**: 显示所有角色信息
|
||||
- **角色详情**: 查看角色权限配置
|
||||
- **角色状态**: 启用/禁用角色
|
||||
|
||||
#### 创建角色
|
||||
1. 点击"创建角色"按钮
|
||||
2. 输入角色名称和描述
|
||||
3. 配置角色权限
|
||||
4. 保存角色配置
|
||||
|
||||
#### 权限配置
|
||||
- **菜单权限**: 控制菜单访问权限
|
||||
- **操作权限**: 控制功能操作权限
|
||||
- **数据权限**: 控制数据访问范围
|
||||
- **API权限**: 控制接口调用权限
|
||||
|
||||
### 4. 菜单管理
|
||||
|
||||
#### 功能概述
|
||||
菜单管理用于配置系统导航菜单结构和权限。
|
||||
|
||||
#### 菜单树
|
||||
- **层级结构**: 树形结构展示菜单
|
||||
- **拖拽排序**: 拖拽调整菜单顺序
|
||||
- **展开收起**: 展开/收起菜单层级
|
||||
- **搜索菜单**: 快速查找菜单项
|
||||
|
||||
#### 添加菜单
|
||||
1. 选择父级菜单(可选)
|
||||
2. 点击"添加菜单"按钮
|
||||
3. 配置菜单基本信息
|
||||
4. 设置菜单权限和图标
|
||||
5. 保存菜单配置
|
||||
|
||||
#### 菜单配置项
|
||||
- **菜单名称**: 显示在导航中的名称
|
||||
- **菜单路径**: 路由路径或外部链接
|
||||
- **菜单图标**: 图标标识
|
||||
- **排序号**: 显示顺序
|
||||
- **可见性**: 控制菜单是否显示
|
||||
- **权限控制**: 关联权限配置
|
||||
|
||||
### 5. 部门管理
|
||||
|
||||
#### 功能概述
|
||||
部门管理用于组织企业组织架构,实现按部门的数据权限控制。
|
||||
|
||||
#### 部门树
|
||||
- **组织架构**: 树形展示部门结构
|
||||
- **部门详情**: 查看部门信息和成员
|
||||
- **部门排序**: 调整部门显示顺序
|
||||
|
||||
#### 添加部门
|
||||
1. 选择父级部门(可选)
|
||||
2. 点击"添加部门"按钮
|
||||
3. 填写部门基本信息
|
||||
4. 设置部门负责人
|
||||
5. 配置部门权限
|
||||
|
||||
#### 部门成员
|
||||
- **成员列表**: 查看部门所有成员
|
||||
- **添加成员**: 从用户列表添加成员
|
||||
- **移除成员**: 从部门移除成员
|
||||
- **调整角色**: 设置成员在部门中的角色
|
||||
|
||||
### 6. 系统设置
|
||||
|
||||
#### 功能概述
|
||||
系统设置模块提供系统级配置和管理功能。
|
||||
|
||||
#### 基本设置
|
||||
- **系统名称**: 设置系统显示名称
|
||||
- **Logo配置**: 上传系统Logo
|
||||
- **主题设置**: 配置系统主题颜色
|
||||
- **语言设置**: 多语言支持配置
|
||||
|
||||
#### 安全设置
|
||||
- **密码策略**: 配置密码复杂度要求
|
||||
- **登录策略**: 配置登录相关设置
|
||||
- **会话管理**: 配置会话超时时间
|
||||
- **审计日志**: 查看系统操作日志
|
||||
|
||||
#### 邮件设置
|
||||
- **SMTP配置**: 配置邮件服务器
|
||||
- **模板管理**: 管理邮件模板
|
||||
- **测试发送**: 测试邮件发送功能
|
||||
|
||||
## 操作指南
|
||||
|
||||
### 1. 数据查询
|
||||
|
||||
#### 基本查询
|
||||
1. 进入相应功能模块
|
||||
2. 使用搜索框输入关键词
|
||||
3. 点击搜索按钮或按回车键
|
||||
4. 查看查询结果
|
||||
|
||||
#### 高级查询
|
||||
1. 点击"高级查询"按钮
|
||||
2. 选择查询条件字段
|
||||
3. 设置查询条件和值
|
||||
4. 添加多个查询条件
|
||||
5. 执行查询操作
|
||||
|
||||
#### 查询技巧
|
||||
- 使用通配符: * 表示多个字符,? 表示单个字符
|
||||
- 组合查询: 多个条件同时满足
|
||||
- 保存查询: 将常用查询保存为模板
|
||||
|
||||
### 2. 数据导出
|
||||
|
||||
#### 导出当前页
|
||||
1. 在数据列表页面
|
||||
2. 点击"导出"按钮
|
||||
3. 选择导出格式(Excel/CSV/PDF)
|
||||
4. 设置导出字段
|
||||
5. 下载导出文件
|
||||
|
||||
#### 导出全部数据
|
||||
1. 在数据列表页面
|
||||
2. 点击"导出全部"按钮
|
||||
3. 选择导出格式
|
||||
4. 系统后台生成文件
|
||||
5. 下载导出文件
|
||||
|
||||
#### 导出设置
|
||||
- **字段选择**: 选择需要导出的字段
|
||||
- **格式设置**: 设置导出文件格式
|
||||
- **编码设置**: 设置文件编码格式
|
||||
- **分页设置**: 设置导出数据分页
|
||||
|
||||
### 3. 批量操作
|
||||
|
||||
#### 批量选择
|
||||
1. 在数据列表页面
|
||||
2. 使用复选框选择多个项目
|
||||
3. 或使用"全选"功能选择所有项目
|
||||
4. 点击批量操作按钮
|
||||
|
||||
#### 批量操作类型
|
||||
- **批量删除**: 删除选中的项目
|
||||
- **批量启用**: 启用选中的项目
|
||||
- **批量禁用**: 禁用选中的项目
|
||||
- **批量分配**: 分配选中的项目
|
||||
|
||||
#### 操作确认
|
||||
- 系统会显示操作确认对话框
|
||||
- 确认操作影响的项目数量
|
||||
- 输入确认信息(如删除确认)
|
||||
- 执行批量操作
|
||||
|
||||
### 4. 数据导入
|
||||
|
||||
#### 准备数据文件
|
||||
1. 下载数据导入模板
|
||||
2. 按照模板格式填写数据
|
||||
3. 保存为Excel或CSV格式
|
||||
4. 检查数据格式是否正确
|
||||
|
||||
#### 执行导入
|
||||
1. 点击"数据导入"按钮
|
||||
2. 选择数据文件
|
||||
3. 设置导入选项
|
||||
4. 预览导入数据
|
||||
5. 确认并执行导入
|
||||
|
||||
#### 导入结果
|
||||
- **成功导入**: 显示成功导入数量
|
||||
- **导入失败**: 显示失败原因
|
||||
- **错误报告**: 下载错误数据报告
|
||||
- **重新导入**: 修正错误后重新导入
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 登录问题
|
||||
|
||||
#### 忘记密码
|
||||
1. 在登录页面点击"忘记密码"
|
||||
2. 输入注册邮箱或手机号
|
||||
3. 接收验证码
|
||||
4. 设置新密码
|
||||
5. 使用新密码登录
|
||||
|
||||
#### 账号被锁定
|
||||
1. 联系系统管理员
|
||||
2. 提供用户信息验证身份
|
||||
3. 管理员解锁账号
|
||||
4. 重新尝试登录
|
||||
|
||||
#### 登录失败
|
||||
- 检查用户名和密码是否正确
|
||||
- 检查网络连接是否正常
|
||||
- 清除浏览器缓存和Cookie
|
||||
- 尝试使用其他浏览器
|
||||
|
||||
### 2. 权限问题
|
||||
|
||||
#### 功能无法访问
|
||||
1. 检查当前用户角色权限
|
||||
2. 联系管理员确认权限配置
|
||||
3. 申请相应功能权限
|
||||
4. 重新登录系统生效
|
||||
|
||||
#### 数据访问受限
|
||||
1. 检查数据权限设置
|
||||
2. 确认部门权限配置
|
||||
3. 联系管理员调整权限
|
||||
4. 刷新页面重新加载
|
||||
|
||||
### 3. 性能问题
|
||||
|
||||
#### 页面加载慢
|
||||
1. 检查网络连接速度
|
||||
2. 清理浏览器缓存
|
||||
3. 关闭不必要的浏览器标签
|
||||
4. 联系技术支持
|
||||
|
||||
#### 操作响应慢
|
||||
1. 检查系统当前负载
|
||||
2. 避免同时进行大量操作
|
||||
3. 分批处理大数据量操作
|
||||
4. 联系管理员优化系统
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 数据管理
|
||||
|
||||
#### 定期备份
|
||||
- 重要数据定期导出备份
|
||||
- 使用系统提供的备份功能
|
||||
- 存储备份文件到安全位置
|
||||
- 测试备份文件可恢复性
|
||||
|
||||
#### 数据清理
|
||||
- 定期清理过期数据
|
||||
- 归档历史数据
|
||||
- 删除重复数据
|
||||
- 优化数据存储结构
|
||||
|
||||
### 2. 权限管理
|
||||
|
||||
#### 最小权限原则
|
||||
- 为用户分配最小必要权限
|
||||
- 定期审核用户权限
|
||||
- 及时回收不再需要的权限
|
||||
- 使用角色组管理权限
|
||||
|
||||
#### 权限审计
|
||||
- 定期检查权限配置
|
||||
- 审核权限使用情况
|
||||
- 发现异常权限及时处理
|
||||
- 记录权限变更日志
|
||||
|
||||
### 3. 系统使用
|
||||
|
||||
#### 操作规范
|
||||
- 按照标准流程操作系统
|
||||
- 重要操作前进行确认
|
||||
- 记录关键操作日志
|
||||
- 定期检查操作结果
|
||||
|
||||
#### 问题反馈
|
||||
- 发现问题及时反馈
|
||||
- 提供详细的问题描述
|
||||
- 附上相关截图和日志
|
||||
- 跟踪问题处理进度
|
||||
|
||||
## 技术支持
|
||||
|
||||
### 1. 获取帮助
|
||||
|
||||
#### 在线帮助
|
||||
- 系统内置帮助文档
|
||||
- 操作提示和向导
|
||||
- 常见问题解答
|
||||
- 视频教程链接
|
||||
|
||||
#### 技术支持
|
||||
- 技术支持热线: 400-xxx-xxxx
|
||||
- 技术支持邮箱: support@aiotagro.com
|
||||
- 在线客服系统
|
||||
- 技术社区论坛
|
||||
|
||||
### 2. 问题反馈
|
||||
|
||||
#### 反馈渠道
|
||||
- 系统内问题反馈功能
|
||||
- 邮件反馈: feedback@aiotagro.com
|
||||
- 电话反馈: 400-xxx-xxxx
|
||||
- 用户调研问卷
|
||||
|
||||
#### 反馈内容
|
||||
- 问题详细描述
|
||||
- 操作步骤重现
|
||||
- 系统环境信息
|
||||
- 期望解决方案
|
||||
|
||||
### 3. 版本更新
|
||||
|
||||
#### 更新通知
|
||||
- 系统内更新公告
|
||||
- 邮件通知更新信息
|
||||
- 版本更新说明文档
|
||||
- 新功能使用指南
|
||||
|
||||
#### 更新准备
|
||||
- 备份重要数据
|
||||
- 了解更新内容
|
||||
- 测试新功能
|
||||
- 培训相关人员
|
||||
|
||||
---
|
||||
|
||||
*本用户手册会随系统版本更新而更新,请定期查看最新版本。如有任何问题或建议,请联系技术支持团队。*
|
||||
574
docs/运维文档.md
Normal file
574
docs/运维文档.md
Normal file
@@ -0,0 +1,574 @@
|
||||
# 运维文档
|
||||
|
||||
## 运维概述
|
||||
|
||||
AIOTAGRO 管理系统运维文档涵盖系统监控、性能优化、故障处理、安全维护等日常运维工作。本文档为运维团队提供完整的操作指南和最佳实践。
|
||||
|
||||
## 系统监控
|
||||
|
||||
### 监控指标
|
||||
|
||||
#### 1. 应用性能指标
|
||||
|
||||
| 指标 | 阈值 | 说明 | 监控工具 |
|
||||
|------|------|------|----------|
|
||||
| 响应时间 | < 2秒 | 页面加载时间 | Prometheus |
|
||||
| 错误率 | < 1% | HTTP 错误率 | Grafana |
|
||||
| 吞吐量 | > 1000 RPM | 请求处理能力 | New Relic |
|
||||
| 可用性 | > 99.9% | 系统可用性 | Uptime Robot |
|
||||
|
||||
#### 2. 服务器资源指标
|
||||
|
||||
| 指标 | 阈值 | 说明 | 监控工具 |
|
||||
|------|------|------|----------|
|
||||
| CPU 使用率 | < 80% | CPU 负载 | Node Exporter |
|
||||
| 内存使用率 | < 85% | 内存使用 | cAdvisor |
|
||||
| 磁盘使用率 | < 90% | 磁盘空间 | Disk Usage |
|
||||
| 网络流量 | 无限制 | 网络带宽 | NetData |
|
||||
|
||||
### 监控配置
|
||||
|
||||
#### 1. Prometheus 配置
|
||||
|
||||
```yaml
|
||||
# prometheus.yml
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'aiotagro-frontend'
|
||||
static_configs:
|
||||
- targets: ['localhost:3000']
|
||||
metrics_path: '/metrics'
|
||||
scrape_interval: 30s
|
||||
|
||||
- job_name: 'nginx'
|
||||
static_configs:
|
||||
- targets: ['localhost:9113']
|
||||
scrape_interval: 30s
|
||||
|
||||
- job_name: 'node-exporter'
|
||||
static_configs:
|
||||
- targets: ['localhost:9100']
|
||||
scrape_interval: 30s
|
||||
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- static_configs:
|
||||
- targets: ['localhost:9093']
|
||||
|
||||
rule_files:
|
||||
- "alerts.yml"
|
||||
```
|
||||
|
||||
#### 2. 告警规则
|
||||
|
||||
```yaml
|
||||
# alerts.yml
|
||||
groups:
|
||||
- name: aiotagro-frontend
|
||||
rules:
|
||||
- alert: HighErrorRate
|
||||
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "高错误率警报"
|
||||
description: "错误率超过 5%,当前值: {{ $value }}"
|
||||
|
||||
- alert: HighResponseTime
|
||||
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 2
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "高响应时间警报"
|
||||
description: "95% 响应时间超过 2 秒,当前值: {{ $value }}"
|
||||
|
||||
- alert: ServiceDown
|
||||
expr: up{job="aiotagro-frontend"} == 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "服务宕机警报"
|
||||
description: "AIOTAGRO 前端服务已宕机"
|
||||
```
|
||||
|
||||
### 监控仪表板
|
||||
|
||||
#### 1. Grafana 配置
|
||||
|
||||
```json
|
||||
{
|
||||
"dashboard": {
|
||||
"title": "AIOTAGRO 监控面板",
|
||||
"panels": [
|
||||
{
|
||||
"title": "响应时间",
|
||||
"type": "graph",
|
||||
"targets": [
|
||||
{
|
||||
"expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))",
|
||||
"legendFormat": "95% 响应时间"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "错误率",
|
||||
"type": "singlestat",
|
||||
"targets": [
|
||||
{
|
||||
"expr": "rate(http_requests_total{status=~\"5..\"}[5m]) / rate(http_requests_total[5m]) * 100",
|
||||
"format": "percent"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 前端优化
|
||||
|
||||
#### 代码分割配置
|
||||
|
||||
```javascript
|
||||
// vite.config.js
|
||||
export default defineConfig({
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vendor: ['vue', 'vue-router', 'pinia'],
|
||||
ui: ['ant-design-vue', '@ant-design/icons-vue'],
|
||||
utils: ['lodash', 'dayjs', 'axios'],
|
||||
charts: ['echarts']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### 缓存策略优化
|
||||
|
||||
```nginx
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Vary Accept-Encoding;
|
||||
|
||||
# 启用 Brotli 压缩
|
||||
brotli_static on;
|
||||
gzip_static on;
|
||||
}
|
||||
|
||||
# API 响应缓存
|
||||
location /api/ {
|
||||
proxy_cache api_cache;
|
||||
proxy_cache_valid 200 302 5m;
|
||||
proxy_cache_valid 404 1m;
|
||||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 服务器优化
|
||||
|
||||
#### Nginx 性能调优
|
||||
|
||||
```nginx
|
||||
# /etc/nginx/nginx.conf
|
||||
worker_processes auto;
|
||||
worker_cpu_affinity auto;
|
||||
worker_rlimit_nofile 100000;
|
||||
|
||||
events {
|
||||
worker_connections 4096;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
# 基础配置
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
keepalive_requests 1000;
|
||||
|
||||
# 缓冲区优化
|
||||
client_body_buffer_size 128k;
|
||||
client_max_body_size 100m;
|
||||
client_header_buffer_size 1k;
|
||||
large_client_header_buffers 4 4k;
|
||||
output_buffers 1 32k;
|
||||
postpone_output 1460;
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
}
|
||||
```
|
||||
|
||||
#### 系统内核优化
|
||||
|
||||
```bash
|
||||
# /etc/sysctl.conf
|
||||
# 网络优化
|
||||
net.core.somaxconn = 65535
|
||||
net.core.netdev_max_backlog = 65536
|
||||
net.ipv4.tcp_max_syn_backlog = 65536
|
||||
net.ipv4.tcp_syncookies = 1
|
||||
net.ipv4.tcp_tw_reuse = 1
|
||||
net.ipv4.tcp_tw_recycle = 0
|
||||
net.ipv4.tcp_fin_timeout = 30
|
||||
net.ipv4.tcp_keepalive_time = 1200
|
||||
|
||||
# 内存优化
|
||||
vm.swappiness = 10
|
||||
vm.dirty_ratio = 60
|
||||
vm.dirty_background_ratio = 2
|
||||
```
|
||||
|
||||
## 故障处理
|
||||
|
||||
### 1. 常见故障及解决方案
|
||||
|
||||
#### 服务不可用
|
||||
|
||||
**症状**: 网站无法访问,返回 502/503 错误
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 检查服务状态
|
||||
sudo systemctl status nginx
|
||||
sudo systemctl status node-exporter
|
||||
|
||||
# 检查端口占用
|
||||
sudo netstat -tlnp | grep :80
|
||||
sudo netstat -tlnp | grep :3000
|
||||
|
||||
# 重启服务
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
#### 性能下降
|
||||
|
||||
**症状**: 响应时间变慢,CPU/内存使用率高
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 查看系统资源
|
||||
top
|
||||
htop
|
||||
iotop
|
||||
|
||||
# 检查 Nginx 状态
|
||||
sudo nginx -t
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
|
||||
# 清理缓存
|
||||
echo 3 > /proc/sys/vm/drop_caches
|
||||
```
|
||||
|
||||
#### 磁盘空间不足
|
||||
|
||||
**症状**: 写入失败,系统告警
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 检查磁盘使用
|
||||
df -h
|
||||
du -sh /var/log/nginx/
|
||||
|
||||
# 清理日志文件
|
||||
sudo find /var/log/nginx -name "*.log" -mtime +7 -delete
|
||||
sudo truncate -s 0 /var/log/nginx/error.log
|
||||
|
||||
# 清理备份文件
|
||||
find /opt/aiotagro/backups -name "*.tar.gz" -mtime +30 -delete
|
||||
```
|
||||
|
||||
### 2. 故障排查流程
|
||||
|
||||
#### 快速诊断脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# diagnose.sh
|
||||
|
||||
echo "=== AIOTAGRO 系统诊断 ==="
|
||||
echo "检查时间: $(date)"
|
||||
|
||||
echo -e "\n1. 系统资源检查"
|
||||
echo "CPU 使用率: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')%"
|
||||
echo "内存使用率: $(free | grep Mem | awk '{printf "%.2f%", $3/$2 * 100}')"
|
||||
echo "磁盘使用率: $(df -h / | awk 'NR==2 {print $5}')"
|
||||
|
||||
echo -e "\n2. 服务状态检查"
|
||||
services=("nginx" "node-exporter" "prometheus")
|
||||
for service in "${services[@]}"; do
|
||||
status=$(systemctl is-active $service)
|
||||
echo "$service: $status"
|
||||
done
|
||||
|
||||
echo -e "\n3. 端口检查"
|
||||
ports=("80" "3000" "9100" "9090")
|
||||
for port in "${ports[@]}"; do
|
||||
if netstat -tln | grep ":$port " > /dev/null; then
|
||||
echo "端口 $port: 正常"
|
||||
else
|
||||
echo "端口 $port: 异常"
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "\n4. 日志检查"
|
||||
if sudo tail -n 10 /var/log/nginx/error.log | grep -i error; then
|
||||
echo "发现 Nginx 错误日志"
|
||||
else
|
||||
echo "Nginx 错误日志正常"
|
||||
fi
|
||||
|
||||
echo -e "\n诊断完成"
|
||||
```
|
||||
|
||||
## 安全维护
|
||||
|
||||
### 1. 安全扫描
|
||||
|
||||
#### 漏洞扫描配置
|
||||
|
||||
```yaml
|
||||
# .github/workflows/security-scan.yml
|
||||
name: Security Scan
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * 1' # 每周一凌晨2点
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
security-scan:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run security audit
|
||||
run: |
|
||||
npm audit --audit-level moderate
|
||||
pnpm audit
|
||||
|
||||
- name: Run SAST scan
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript
|
||||
|
||||
- name: Run SAST analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
- name: Run dependency check
|
||||
uses: dependency-check/Dependency-Check_Action@main
|
||||
with:
|
||||
project: 'AIOTAGRO Frontend'
|
||||
path: '.'
|
||||
format: 'HTML'
|
||||
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: security-reports
|
||||
path: reports/
|
||||
```
|
||||
|
||||
### 2. 安全更新
|
||||
|
||||
#### 自动更新脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# security-update.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "开始安全更新..."
|
||||
|
||||
# 更新系统包
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
|
||||
# 更新 Node.js 依赖
|
||||
pnpm update --latest
|
||||
|
||||
# 运行安全审计
|
||||
pnpm audit
|
||||
|
||||
# 修复安全漏洞
|
||||
if pnpm audit | grep -q "high"; then
|
||||
echo "发现高危漏洞,尝试修复..."
|
||||
pnpm audit fix
|
||||
fi
|
||||
|
||||
# 重新构建应用
|
||||
pnpm build:antd
|
||||
|
||||
# 重启服务
|
||||
sudo systemctl restart nginx
|
||||
|
||||
echo "安全更新完成"
|
||||
```
|
||||
|
||||
## 备份和恢复
|
||||
|
||||
### 1. 自动化备份
|
||||
|
||||
#### 完整备份脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# full-backup.sh
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_DIR="/opt/aiotagro/backups"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_FILE="aiotagro_full_backup_$TIMESTAMP.tar.gz"
|
||||
|
||||
echo "开始完整备份..."
|
||||
|
||||
# 创建备份目录
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# 备份应用代码
|
||||
echo "备份应用代码..."
|
||||
tar -czf "$BACKUP_DIR/app_$TIMESTAMP.tar.gz" \
|
||||
--exclude=node_modules \
|
||||
--exclude=dist \
|
||||
--exclude=.git \
|
||||
/opt/aiotagro/frontend
|
||||
|
||||
# 备份配置文件
|
||||
echo "备份配置文件..."
|
||||
tar -czf "$BACKUP_DIR/config_$TIMESTAMP.tar.gz" \
|
||||
/etc/nginx \
|
||||
/etc/systemd/system/aiotagro.service
|
||||
|
||||
# 备份数据库(如果有)
|
||||
# echo "备份数据库..."
|
||||
# pg_dump -U postgres aiotagro > "$BACKUP_DIR/db_$TIMESTAMP.sql"
|
||||
|
||||
# 创建完整备份包
|
||||
echo "创建完整备份包..."
|
||||
tar -czf "$BACKUP_DIR/$BACKUP_FILE" \
|
||||
"$BACKUP_DIR/app_$TIMESTAMP.tar.gz" \
|
||||
"$BACKUP_DIR/config_$TIMESTAMP.tar.gz"
|
||||
|
||||
# 清理临时文件
|
||||
rm -f "$BACKUP_DIR/app_$TIMESTAMP.tar.gz" \
|
||||
"$BACKUP_DIR/config_$TIMESTAMP.tar.gz"
|
||||
|
||||
# 上传到云存储(可选)
|
||||
# echo "上传到云存储..."
|
||||
# aws s3 cp "$BACKUP_DIR/$BACKUP_FILE" s3://aiotagro-backups/
|
||||
|
||||
# 清理旧备份(保留最近30天)
|
||||
find "$BACKUP_DIR" -name "aiotagro_full_backup_*.tar.gz" -mtime +30 -delete
|
||||
|
||||
echo "备份完成: $BACKUP_DIR/$BACKUP_FILE"
|
||||
```
|
||||
|
||||
### 2. 灾难恢复
|
||||
|
||||
#### 恢复流程
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# disaster-recovery.sh
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_FILE="$1"
|
||||
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
echo "用法: $0 <备份文件>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "开始灾难恢复..."
|
||||
|
||||
# 停止服务
|
||||
sudo systemctl stop nginx
|
||||
|
||||
# 解压备份文件
|
||||
tar -xzf "$BACKUP_FILE" -C /tmp/
|
||||
|
||||
# 恢复应用代码
|
||||
tar -xzf /tmp/app_*.tar.gz -C /
|
||||
|
||||
# 恢复配置文件
|
||||
tar -xzf /tmp/config_*.tar.gz -C /
|
||||
|
||||
# 重新加载系统配置
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# 启动服务
|
||||
sudo systemctl start nginx
|
||||
|
||||
# 验证恢复
|
||||
sleep 5
|
||||
if curl -f http://localhost/ > /dev/null 2>&1; then
|
||||
echo "恢复成功"
|
||||
else
|
||||
echo "恢复失败,请检查日志"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 清理临时文件
|
||||
rm -rf /tmp/app_*.tar.gz /tmp/config_*.tar.gz
|
||||
|
||||
echo "灾难恢复完成"
|
||||
```
|
||||
|
||||
## 日常维护
|
||||
|
||||
### 1. 维护检查清单
|
||||
|
||||
#### 每日检查
|
||||
- [ ] 系统资源使用情况
|
||||
- [ ] 服务运行状态
|
||||
- [ ] 错误日志检查
|
||||
- [ ] 备份状态验证
|
||||
- [ ] 安全告警检查
|
||||
|
||||
#### 每周检查
|
||||
- [ ] 性能指标分析
|
||||
- [ ] 安全漏洞扫描
|
||||
- [ ] 日志文件清理
|
||||
- [ ] 备份文件验证
|
||||
- [ ] 系统更新检查
|
||||
|
||||
#### 每月检查
|
||||
- [ ] 容量规划评估
|
||||
- [ ] 安全审计
|
||||
- [ ] 性能优化评估
|
||||
- [ ] 灾难恢复演练
|
||||
- [ ] 文档更新
|
||||
|
||||
通过以上运维配置和流程,AIOTAGRO 管理系统可以实现稳定、安全、高效的运维管理。
|
||||
767
docs/部署文档.md
Normal file
767
docs/部署文档.md
Normal file
@@ -0,0 +1,767 @@
|
||||
# 部署文档
|
||||
|
||||
## 部署概述
|
||||
|
||||
AIOTAGRO 管理系统支持多种部署方式,包括开发环境部署、测试环境部署和生产环境部署。本文档详细说明各种部署场景的配置和步骤。
|
||||
|
||||
## 环境要求
|
||||
|
||||
### 服务器要求
|
||||
|
||||
| 环境 | CPU | 内存 | 磁盘 | 网络 |
|
||||
|------|-----|------|------|------|
|
||||
| 开发环境 | 2核 | 4GB | 20GB | 10Mbps |
|
||||
| 测试环境 | 4核 | 8GB | 50GB | 50Mbps |
|
||||
| 生产环境 | 8核 | 16GB | 100GB | 100Mbps |
|
||||
|
||||
### 软件要求
|
||||
|
||||
| 软件 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| Node.js | 18.0.0+ | JavaScript 运行时 |
|
||||
| pnpm | 8.0.0+ | 包管理器 |
|
||||
| Nginx | 1.20.0+ | Web 服务器 |
|
||||
| Git | 2.30.0+ | 版本控制 |
|
||||
|
||||
## 开发环境部署
|
||||
|
||||
### 本地开发环境
|
||||
|
||||
#### 1. 环境准备
|
||||
|
||||
```bash
|
||||
# 安装 Node.js
|
||||
# 访问 https://nodejs.org/ 下载安装包
|
||||
|
||||
# 安装 pnpm
|
||||
npm install -g pnpm
|
||||
|
||||
# 验证安装
|
||||
node --version
|
||||
pnpm --version
|
||||
```
|
||||
|
||||
#### 2. 项目初始化
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone https://github.com/aiotagro/yudao-ui-admin-vben.git
|
||||
cd yudao-ui-admin-vben
|
||||
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 启动开发服务器
|
||||
pnpm dev:antd
|
||||
```
|
||||
|
||||
#### 3. 访问应用
|
||||
|
||||
打开浏览器访问: http://localhost:3000
|
||||
|
||||
### Docker 开发环境
|
||||
|
||||
#### 1. Dockerfile 配置
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile.dev
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 复制 package.json 和 pnpm-lock.yaml
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
|
||||
# 安装依赖
|
||||
RUN npm install -g pnpm && pnpm install
|
||||
|
||||
# 复制源代码
|
||||
COPY . .
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 3000
|
||||
|
||||
# 启动开发服务器
|
||||
CMD ["pnpm", "dev:antd"]
|
||||
```
|
||||
|
||||
#### 2. docker-compose 配置
|
||||
|
||||
```yaml
|
||||
# docker-compose.dev.yml
|
||||
version: '3.8'
|
||||
services:
|
||||
frontend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/node_modules
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
```
|
||||
|
||||
#### 3. 启动服务
|
||||
|
||||
```bash
|
||||
# 构建并启动服务
|
||||
docker-compose -f docker-compose.dev.yml up --build
|
||||
|
||||
# 后台运行
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
## 测试环境部署
|
||||
|
||||
### 手动部署
|
||||
|
||||
#### 1. 服务器准备
|
||||
|
||||
```bash
|
||||
# 登录服务器
|
||||
ssh user@test-server
|
||||
|
||||
# 创建项目目录
|
||||
mkdir -p /opt/aiotagro/frontend
|
||||
cd /opt/aiotagro/frontend
|
||||
|
||||
# 克隆代码
|
||||
git clone https://github.com/aiotagro/yudao-ui-admin-vben.git .
|
||||
```
|
||||
|
||||
#### 2. 环境配置
|
||||
|
||||
```bash
|
||||
# 安装 Node.js
|
||||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
# 安装 pnpm
|
||||
npm install -g pnpm
|
||||
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
```
|
||||
|
||||
#### 3. 构建应用
|
||||
|
||||
```bash
|
||||
# 构建生产版本
|
||||
pnpm build:antd
|
||||
|
||||
# 检查构建结果
|
||||
ls -la dist/
|
||||
```
|
||||
|
||||
#### 4. 配置 Nginx
|
||||
|
||||
```nginx
|
||||
# /etc/nginx/sites-available/aiotagro-test
|
||||
server {
|
||||
listen 80;
|
||||
server_name test.aiotagro.com;
|
||||
|
||||
root /opt/aiotagro/frontend/dist;
|
||||
index index.html;
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# SPA 路由支持
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# API 代理
|
||||
location /api/ {
|
||||
proxy_pass http://backend-server:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. 启用站点
|
||||
|
||||
```bash
|
||||
# 创建符号链接
|
||||
sudo ln -s /etc/nginx/sites-available/aiotagro-test /etc/nginx/sites-enabled/
|
||||
|
||||
# 测试配置
|
||||
sudo nginx -t
|
||||
|
||||
# 重启 Nginx
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
### 自动化部署脚本
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# deploy-test.sh
|
||||
|
||||
set -e
|
||||
|
||||
# 配置变量
|
||||
PROJECT_DIR="/opt/aiotagro/frontend"
|
||||
BACKUP_DIR="/opt/aiotagro/backups"
|
||||
BRANCH="test"
|
||||
|
||||
echo "开始部署 AIOTAGRO 测试环境..."
|
||||
|
||||
# 备份当前版本
|
||||
if [ -d "$PROJECT_DIR" ]; then
|
||||
echo "备份当前版本..."
|
||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
tar -czf "$BACKUP_DIR/frontend_$timestamp.tar.gz" -C "$PROJECT_DIR" .
|
||||
fi
|
||||
|
||||
# 更新代码
|
||||
cd "$PROJECT_DIR"
|
||||
git fetch origin
|
||||
git checkout "$BRANCH"
|
||||
git pull origin "$BRANCH"
|
||||
|
||||
# 安装依赖
|
||||
echo "安装依赖..."
|
||||
pnpm install
|
||||
|
||||
# 构建应用
|
||||
echo "构建应用..."
|
||||
pnpm build:antd
|
||||
|
||||
# 重启服务
|
||||
echo "重启服务..."
|
||||
sudo systemctl restart nginx
|
||||
|
||||
echo "部署完成!"
|
||||
```
|
||||
|
||||
## 生产环境部署
|
||||
|
||||
### 高可用架构
|
||||
|
||||
#### 1. 负载均衡配置
|
||||
|
||||
```nginx
|
||||
# /etc/nginx/nginx.conf
|
||||
upstream aiogatro_backend {
|
||||
server 10.0.1.10:8080 weight=3;
|
||||
server 10.0.1.11:8080 weight=2;
|
||||
server 10.0.1.12:8080 weight=2;
|
||||
keepalive 32;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name aiotagro.com www.aiotagro.com;
|
||||
|
||||
# 重定向到 HTTPS
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name aiotagro.com www.aiotagro.com;
|
||||
|
||||
# SSL 配置
|
||||
ssl_certificate /etc/ssl/certs/aiotagro.crt;
|
||||
ssl_certificate_key /etc/ssl/private/aiotagro.key;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
|
||||
|
||||
root /var/www/aiotagro/dist;
|
||||
index index.html;
|
||||
|
||||
# 安全头
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
# 静态资源
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Vary Accept-Encoding;
|
||||
}
|
||||
|
||||
# API 代理
|
||||
location /api/ {
|
||||
proxy_pass http://aiogatro_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# SPA 路由
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 容器化部署
|
||||
|
||||
#### 1. Docker 生产配置
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile.prod
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 复制依赖文件
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
||||
|
||||
# 复制源代码
|
||||
COPY . .
|
||||
|
||||
# 构建应用
|
||||
RUN pnpm build:antd
|
||||
|
||||
# 生产阶段
|
||||
FROM nginx:alpine
|
||||
|
||||
# 复制构建结果
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# 复制 Nginx 配置
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 启动 Nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
#### 2. Kubernetes 部署
|
||||
|
||||
```yaml
|
||||
# k8s/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: aiotagro-frontend
|
||||
namespace: production
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: aiotagro-frontend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: aiotagro-frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: frontend
|
||||
image: aiotagro/frontend:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "200m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 80
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 80
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: aiotagro-frontend-service
|
||||
namespace: production
|
||||
spec:
|
||||
selector:
|
||||
app: aiotagro-frontend
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
type: LoadBalancer
|
||||
```
|
||||
|
||||
### 自动化部署流程
|
||||
|
||||
#### 1. CI/CD 配置
|
||||
|
||||
```yaml
|
||||
# .github/workflows/deploy.yml
|
||||
name: Deploy to Production
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Build application
|
||||
run: pnpm build:antd
|
||||
|
||||
- name: Build Docker image
|
||||
run: |
|
||||
docker build -t $REGISTRY/$IMAGE_NAME:${{ github.sha }} .
|
||||
|
||||
- name: Push Docker image
|
||||
run: |
|
||||
echo ${{ secrets.GITHUB_TOKEN }} | docker login $REGISTRY -u ${{ github.actor }} --password-stdin
|
||||
docker push $REGISTRY/$IMAGE_NAME:${{ github.sha }}
|
||||
|
||||
- name: Deploy to production
|
||||
run: |
|
||||
# 部署到生产环境
|
||||
ssh deploy@production-server << EOF
|
||||
docker pull $REGISTRY/$IMAGE_NAME:${{ github.sha }}
|
||||
docker stop aiotagro-frontend || true
|
||||
docker rm aiotagro-frontend || true
|
||||
docker run -d --name aiotagro-frontend -p 80:80 $REGISTRY/$IMAGE_NAME:${{ github.sha }}
|
||||
EOF
|
||||
```
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 1. 应用监控配置
|
||||
|
||||
```javascript
|
||||
// src/utils/monitoring.js
|
||||
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'
|
||||
|
||||
export const initMonitoring = () => {
|
||||
// 性能监控
|
||||
getCLS(console.log)
|
||||
getFID(console.log)
|
||||
getFCP(console.log)
|
||||
getLCP(console.log)
|
||||
getTTFB(console.log)
|
||||
|
||||
// 错误监控
|
||||
window.addEventListener('error', (event) => {
|
||||
console.error('JavaScript Error:', event.error)
|
||||
// 发送到监控服务
|
||||
sendToMonitoringService({
|
||||
type: 'error',
|
||||
message: event.error.message,
|
||||
stack: event.error.stack,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
})
|
||||
|
||||
// 未处理的 Promise 拒绝
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
console.error('Unhandled Promise Rejection:', event.reason)
|
||||
sendToMonitoringService({
|
||||
type: 'promise_rejection',
|
||||
reason: event.reason,
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const sendToMonitoringService = (data) => {
|
||||
// 发送到监控服务
|
||||
fetch('/api/monitoring', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).catch(console.error)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 日志配置
|
||||
|
||||
```nginx
|
||||
# Nginx 日志配置
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'rt=$request_time uct="$upstream_connect_time" '
|
||||
'uht="$upstream_header_time" urt="$upstream_response_time"';
|
||||
|
||||
access_log /var/log/nginx/aiotagro-access.log main;
|
||||
error_log /var/log/nginx/aiotagro-error.log warn;
|
||||
```
|
||||
|
||||
## 备份和恢复
|
||||
|
||||
### 1. 备份策略
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# backup.sh
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_DIR="/opt/aiotagro/backups"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_FILE="aiotagro_backup_$TIMESTAMP.tar.gz"
|
||||
|
||||
echo "开始备份 AIOTAGRO 系统..."
|
||||
|
||||
# 备份应用代码
|
||||
tar -czf "$BACKUP_DIR/$BACKUP_FILE" \
|
||||
--exclude=node_modules \
|
||||
--exclude=dist \
|
||||
--exclude=.git \
|
||||
/opt/aiotagro/frontend
|
||||
|
||||
# 备份 Nginx 配置
|
||||
tar -czf "$BACKUP_DIR/nginx_config_$TIMESTAMP.tar.gz" /etc/nginx
|
||||
|
||||
# 清理旧备份(保留最近7天)
|
||||
find "$BACKUP_DIR" -name "aiotagro_backup_*.tar.gz" -mtime +7 -delete
|
||||
find "$BACKUP_DIR" -name "nginx_config_*.tar.gz" -mtime +7 -delete
|
||||
|
||||
echo "备份完成: $BACKUP_DIR/$BACKUP_FILE"
|
||||
```
|
||||
|
||||
### 2. 恢复策略
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# restore.sh
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_FILE="$1"
|
||||
|
||||
if [ -z "$BACKUP_FILE" ]; then
|
||||
echo "Usage: $0 <backup_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "开始恢复 AIOTAGRO 系统..."
|
||||
|
||||
# 停止服务
|
||||
sudo systemctl stop nginx
|
||||
|
||||
# 恢复应用代码
|
||||
tar -xzf "$BACKUP_FILE" -C /
|
||||
|
||||
# 恢复 Nginx 配置(可选)
|
||||
# tar -xzf "nginx_config_*.tar.gz" -C /
|
||||
|
||||
# 启动服务
|
||||
sudo systemctl start nginx
|
||||
|
||||
echo "恢复完成"
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
#### 1. 构建失败
|
||||
|
||||
**问题**: pnpm build 失败
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 清理缓存
|
||||
pnpm clean
|
||||
|
||||
# 重新安装依赖
|
||||
pnpm install --force
|
||||
|
||||
# 重新构建
|
||||
pnpm build:antd
|
||||
```
|
||||
|
||||
#### 2. Nginx 配置错误
|
||||
|
||||
**问题**: Nginx 启动失败
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 检查配置
|
||||
sudo nginx -t
|
||||
|
||||
# 查看错误日志
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
#### 3. 证书问题
|
||||
|
||||
**问题**: SSL 证书错误
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 检查证书权限
|
||||
sudo chmod 600 /etc/ssl/private/aiotagro.key
|
||||
|
||||
# 重新加载 Nginx
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 构建优化
|
||||
|
||||
```javascript
|
||||
// vite.config.js
|
||||
export default defineConfig({
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vendor: ['vue', 'vue-router', 'pinia'],
|
||||
ui: ['ant-design-vue', '@ant-design/icons-vue'],
|
||||
utils: ['lodash', 'dayjs', 'axios']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 2. 缓存策略
|
||||
|
||||
```nginx
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Vary Accept-Encoding;
|
||||
}
|
||||
|
||||
# API 缓存
|
||||
location /api/ {
|
||||
proxy_cache api_cache;
|
||||
proxy_cache_valid 200 302 5m;
|
||||
proxy_cache_valid 404 1m;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
}
|
||||
```
|
||||
|
||||
## 安全配置
|
||||
|
||||
### 1. 安全头设置
|
||||
|
||||
```nginx
|
||||
# 安全头配置
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'";
|
||||
```
|
||||
|
||||
### 2. 访问控制
|
||||
|
||||
```nginx
|
||||
# IP 限制
|
||||
location /admin/ {
|
||||
allow 192.168.1.0/24;
|
||||
allow 10.0.0.0/8;
|
||||
deny all;
|
||||
}
|
||||
|
||||
# 速率限制
|
||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||
|
||||
location /api/ {
|
||||
limit_req zone=api burst=20 nodelay;
|
||||
}
|
||||
```
|
||||
|
||||
## 更新和维护
|
||||
|
||||
### 1. 定期更新
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# update.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "开始更新 AIOTAGRO 系统..."
|
||||
|
||||
# 更新代码
|
||||
cd /opt/aiotagro/frontend
|
||||
git pull origin main
|
||||
|
||||
# 更新依赖
|
||||
pnpm install
|
||||
|
||||
# 构建应用
|
||||
pnpm build:antd
|
||||
|
||||
# 重启服务
|
||||
sudo systemctl restart nginx
|
||||
|
||||
echo "更新完成"
|
||||
```
|
||||
|
||||
### 2. 健康检查
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# health-check.sh
|
||||
|
||||
set -e
|
||||
|
||||
URL="https://aiotagro.com"
|
||||
TIMEOUT=10
|
||||
|
||||
response=$(curl -s -o /dev/null -w "%{http_code}" --max-time $TIMEOUT $URL)
|
||||
|
||||
if [ "$response" -eq 200 ]; then
|
||||
echo "健康检查通过: $URL"
|
||||
exit 0
|
||||
else
|
||||
echo "健康检查失败: $URL (状态码: $response)"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
通过以上配置和脚本,AIOTAGRO 管理系统可以实现稳定、安全、高效的部署和运维。
|
||||
286
docs/项目架构文档.md
Normal file
286
docs/项目架构文档.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# 项目架构文档
|
||||
|
||||
## 系统架构概述
|
||||
|
||||
yudao-ui-admin-vben 采用现代化的前端架构设计,基于 Vue3 + TypeScript + Monorepo 技术栈,提供可扩展、高性能的企业级管理系统解决方案。
|
||||
|
||||
## 整体架构
|
||||
|
||||
### 架构图
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A[用户界面] --> B[应用层]
|
||||
B --> C[业务逻辑层]
|
||||
C --> D[数据访问层]
|
||||
D --> E[后端API]
|
||||
|
||||
F[构建工具] --> G[打包优化]
|
||||
G --> H[部署发布]
|
||||
|
||||
I[开发工具] --> J[代码检查]
|
||||
J --> K[测试验证]
|
||||
```
|
||||
|
||||
### 技术栈分层
|
||||
|
||||
| 层级 | 技术栈 | 说明 |
|
||||
|------|--------|------|
|
||||
| 表现层 | Vue3 + TypeScript | 用户界面渲染 |
|
||||
| 应用层 | Vue Router + Pinia | 路由和状态管理 |
|
||||
| 工具层 | Vite + ESLint | 构建和代码检查 |
|
||||
| 基础设施 | Node.js + pnpm | 运行环境和包管理 |
|
||||
|
||||
## Monorepo 架构设计
|
||||
|
||||
### 项目结构
|
||||
|
||||
```
|
||||
yudao-ui-admin-vben/
|
||||
├── apps/ # 应用目录
|
||||
│ ├── web-antd/ # Ant Design 版本应用
|
||||
│ ├── web-ele/ # Element Plus 版本应用
|
||||
│ ├── web-naive/ # Naive UI 版本应用
|
||||
│ └── backend-mock/ # 后端模拟服务
|
||||
├── packages/ # 共享包目录
|
||||
│ ├── @core/ # 核心功能包
|
||||
│ ├── constants/ # 常量定义包
|
||||
│ ├── effects/ # 副作用管理包
|
||||
│ ├── icons/ # 图标库包
|
||||
│ ├── locales/ # 国际化资源包
|
||||
│ ├── stores/ # 状态管理包
|
||||
│ ├── styles/ # 样式文件包
|
||||
│ ├── types/ # 类型定义包
|
||||
│ └── utils/ # 工具函数包
|
||||
├── internal/ # 内部配置目录
|
||||
│ ├── lint-configs/ # 代码规范配置
|
||||
│ ├── tailwind-config/ # Tailwind 配置
|
||||
│ ├── tsconfig/ # TypeScript 配置
|
||||
│ └── vite-config/ # Vite 配置
|
||||
└── scripts/ # 脚本工具目录
|
||||
```
|
||||
|
||||
### 包依赖关系
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[apps/web-antd] --> B[packages/@core]
|
||||
A --> C[packages/stores]
|
||||
A --> D[packages/utils]
|
||||
|
||||
B --> E[packages/types]
|
||||
C --> E
|
||||
D --> E
|
||||
|
||||
F[apps/web-ele] --> B
|
||||
F --> C
|
||||
F --> D
|
||||
|
||||
G[apps/web-naive] --> B
|
||||
G --> C
|
||||
G --> D
|
||||
```
|
||||
|
||||
## 核心模块设计
|
||||
|
||||
### 1. 应用模块 (apps/)
|
||||
|
||||
#### 功能特性
|
||||
- **多主题支持**: 同一套业务逻辑,不同 UI 表现
|
||||
- **独立部署**: 每个应用可独立构建部署
|
||||
- **共享代码**: 通过 packages 共享公共逻辑
|
||||
|
||||
#### 技术实现
|
||||
- Vue3 Composition API
|
||||
- TypeScript 类型安全
|
||||
- Vite 快速构建
|
||||
- 热重载开发体验
|
||||
|
||||
### 2. 核心包模块 (packages/@core)
|
||||
|
||||
#### 基础功能
|
||||
- 基础组件封装
|
||||
- 工具函数集合
|
||||
- 类型定义扩展
|
||||
- 配置管理
|
||||
|
||||
#### 设计原则
|
||||
- 单一职责原则
|
||||
- 依赖倒置原则
|
||||
- 接口隔离原则
|
||||
- 开闭原则
|
||||
|
||||
### 3. 状态管理模块 (packages/stores)
|
||||
|
||||
#### 状态分类
|
||||
- 用户状态 (用户信息、权限)
|
||||
- 应用状态 (主题、语言、布局)
|
||||
- 业务状态 (页面数据、表单状态)
|
||||
|
||||
#### 技术实现
|
||||
- Pinia 状态管理
|
||||
- 持久化存储
|
||||
- 类型安全的状态访问
|
||||
|
||||
### 4. 工具模块 (packages/utils)
|
||||
|
||||
#### 工具分类
|
||||
- 数据处理工具
|
||||
- 日期时间工具
|
||||
- 表单验证工具
|
||||
- 网络请求工具
|
||||
|
||||
## 数据流设计
|
||||
|
||||
### 单向数据流
|
||||
|
||||
```
|
||||
用户操作 → 组件事件 → Action → Mutation → State → 组件更新
|
||||
```
|
||||
|
||||
### 异步数据流
|
||||
|
||||
```
|
||||
组件挂载 → 发起请求 → 加载状态 → 数据处理 → 更新状态 → 界面渲染
|
||||
```
|
||||
|
||||
## 路由设计
|
||||
|
||||
### 路由结构
|
||||
```
|
||||
/ # 首页
|
||||
/login # 登录页
|
||||
/dashboard # 仪表板
|
||||
/system # 系统管理
|
||||
/system/user # 用户管理
|
||||
/system/role # 角色管理
|
||||
/system/menu # 菜单管理
|
||||
```
|
||||
|
||||
### 路由守卫
|
||||
- 登录状态验证
|
||||
- 权限验证
|
||||
- 路由拦截
|
||||
- 页面标题设置
|
||||
|
||||
## 权限设计
|
||||
|
||||
### RBAC 权限模型
|
||||
- 用户 (User)
|
||||
- 角色 (Role)
|
||||
- 权限 (Permission)
|
||||
- 菜单 (Menu)
|
||||
|
||||
### 权限控制级别
|
||||
- 页面级权限
|
||||
- 按钮级权限
|
||||
- 数据级权限
|
||||
- 功能级权限
|
||||
|
||||
## 构建部署架构
|
||||
|
||||
### 开发环境
|
||||
- Vite 开发服务器
|
||||
- 热重载支持
|
||||
- Source Map 调试
|
||||
|
||||
### 生产环境
|
||||
- Vite 生产构建
|
||||
- 代码分割优化
|
||||
- 资源压缩处理
|
||||
- CDN 部署支持
|
||||
|
||||
### 部署策略
|
||||
- 静态资源部署
|
||||
- 多环境配置
|
||||
- 版本控制
|
||||
- 回滚机制
|
||||
|
||||
## 性能优化策略
|
||||
|
||||
### 构建优化
|
||||
- 代码分割
|
||||
- 树摇优化
|
||||
- 懒加载
|
||||
- 预加载
|
||||
|
||||
### 运行时优化
|
||||
- 虚拟滚动
|
||||
- 防抖节流
|
||||
- 缓存策略
|
||||
- 图片优化
|
||||
|
||||
## 安全架构
|
||||
|
||||
### 前端安全
|
||||
- XSS 防护
|
||||
- CSRF 防护
|
||||
- 数据加密
|
||||
- 输入验证
|
||||
|
||||
### 权限安全
|
||||
- JWT 令牌
|
||||
- 路由守卫
|
||||
- API 权限验证
|
||||
- 数据权限控制
|
||||
|
||||
## 扩展性设计
|
||||
|
||||
### 插件系统
|
||||
- 组件插件化
|
||||
- 功能模块化
|
||||
- 配置可扩展
|
||||
- 主题可定制
|
||||
|
||||
### 微前端支持
|
||||
- 模块联邦
|
||||
- 独立部署
|
||||
- 技术栈无关
|
||||
- 团队协作
|
||||
|
||||
## 监控运维
|
||||
|
||||
### 性能监控
|
||||
- 页面加载时间
|
||||
- 接口响应时间
|
||||
- 错误监控
|
||||
- 用户行为分析
|
||||
|
||||
### 日志系统
|
||||
- 操作日志
|
||||
- 错误日志
|
||||
- 性能日志
|
||||
- 安全日志
|
||||
|
||||
## 技术选型理由
|
||||
|
||||
### Vue3 优势
|
||||
- 更好的性能
|
||||
- 更好的 TypeScript 支持
|
||||
- 更小的包体积
|
||||
- 更好的开发体验
|
||||
|
||||
### Monorepo 优势
|
||||
- 代码共享方便
|
||||
- 版本管理统一
|
||||
- 构建优化明显
|
||||
- 团队协作高效
|
||||
|
||||
### Vite 优势
|
||||
- 极速的冷启动
|
||||
- 快速的热更新
|
||||
- 丰富的插件生态
|
||||
- 优化的生产构建
|
||||
|
||||
## 架构演进规划
|
||||
|
||||
### 短期目标
|
||||
- 完善现有功能
|
||||
- 优化性能体验
|
||||
- 丰富文档体系
|
||||
|
||||
### 长期目标
|
||||
- 微前端架构支持
|
||||
- 低代码平台集成
|
||||
- AI 辅助开发
|
||||
- 云原生部署
|
||||
143
docs/项目需求文档.md
Normal file
143
docs/项目需求文档.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 项目需求文档
|
||||
|
||||
## 项目概述
|
||||
|
||||
yudao-ui-admin-vben 是一个基于 Vue3 + TypeScript 的企业级管理系统框架,旨在为开发者提供快速构建现代化管理后台的完整解决方案。
|
||||
|
||||
## 业务需求
|
||||
|
||||
### 核心功能需求
|
||||
|
||||
#### 1. 用户管理
|
||||
- ✅ 用户登录/注册
|
||||
- ✅ 用户信息管理
|
||||
- ✅ 权限控制
|
||||
- ✅ 角色管理
|
||||
|
||||
#### 2. 系统管理
|
||||
- ✅ 菜单管理
|
||||
- ✅ 权限配置
|
||||
- ✅ 系统设置
|
||||
- ✅ 日志管理
|
||||
|
||||
#### 3. 数据管理
|
||||
- ✅ 数据表格展示
|
||||
- ✅ 数据增删改查
|
||||
- ✅ 数据导入导出
|
||||
- ✅ 数据筛选排序
|
||||
|
||||
#### 4. 界面管理
|
||||
- ✅ 多主题切换
|
||||
- ✅ 响应式布局
|
||||
- ✅ 国际化支持
|
||||
- ✅ 自定义配置
|
||||
|
||||
### 技术需求
|
||||
|
||||
#### 1. 前端技术栈
|
||||
- ✅ Vue3 + TypeScript
|
||||
- ✅ Vite 构建工具
|
||||
- ✅ Pinia 状态管理
|
||||
- ✅ Vue Router 路由管理
|
||||
|
||||
#### 2. UI 组件库
|
||||
- ✅ Ant Design Vue
|
||||
- ✅ Element Plus
|
||||
- ✅ Naive UI
|
||||
|
||||
#### 3. 开发工具
|
||||
- ✅ ESLint 代码检查
|
||||
- ✅ Prettier 代码格式化
|
||||
- ✅ TypeScript 类型检查
|
||||
- ✅ 单元测试支持
|
||||
|
||||
## 非功能性需求
|
||||
|
||||
### 性能需求
|
||||
- 页面加载时间 < 3秒
|
||||
- 首屏渲染时间 < 1秒
|
||||
- 支持 1000+ 数据量展示
|
||||
|
||||
### 安全性需求
|
||||
- XSS 攻击防护
|
||||
- CSRF 攻击防护
|
||||
- 数据加密传输
|
||||
- 权限验证机制
|
||||
|
||||
### 兼容性需求
|
||||
- 支持 Chrome 80+
|
||||
- 支持 Firefox 75+
|
||||
- 支持 Safari 13+
|
||||
- 支持 Edge 80+
|
||||
|
||||
## 项目范围
|
||||
|
||||
### 包含功能
|
||||
- 基础管理系统框架
|
||||
- 多主题 UI 组件
|
||||
- 完整的权限系统
|
||||
- 开发工具链配置
|
||||
- 文档系统
|
||||
|
||||
### 不包含功能
|
||||
- 具体业务逻辑实现
|
||||
- 后端 API 服务
|
||||
- 数据库设计
|
||||
- 部署运维服务
|
||||
|
||||
## 项目里程碑
|
||||
|
||||
### 第一阶段:基础框架
|
||||
- [x] 项目初始化
|
||||
- [x] 基础架构搭建
|
||||
- [x] 核心功能开发
|
||||
|
||||
### 第二阶段:功能完善
|
||||
- [x] 多主题支持
|
||||
- [x] 权限系统
|
||||
- [x] 国际化支持
|
||||
|
||||
### 第三阶段:优化发布
|
||||
- [x] 性能优化
|
||||
- [x] 文档完善
|
||||
- [x] 版本发布
|
||||
|
||||
## 验收标准
|
||||
|
||||
### 功能验收
|
||||
- 所有核心功能正常运行
|
||||
- 界面交互流畅无卡顿
|
||||
- 权限控制准确无误
|
||||
- 多主题切换正常
|
||||
|
||||
### 技术验收
|
||||
- 代码符合规范标准
|
||||
- 类型检查无错误
|
||||
- 测试覆盖率达标
|
||||
- 构建部署成功
|
||||
|
||||
## 风险分析
|
||||
|
||||
### 技术风险
|
||||
- 新技术栈学习成本
|
||||
- 浏览器兼容性问题
|
||||
- 性能优化挑战
|
||||
|
||||
### 管理风险
|
||||
- 项目进度控制
|
||||
- 需求变更管理
|
||||
- 团队协作效率
|
||||
|
||||
## 附录
|
||||
|
||||
### 术语表
|
||||
- **Monorepo**: 单一代码仓库管理多个项目
|
||||
- **Vite**: 下一代前端构建工具
|
||||
- **Pinia**: Vue 状态管理库
|
||||
- **TypeScript**: JavaScript 的超集,添加类型系统
|
||||
|
||||
### 参考资料
|
||||
- Vue3 官方文档
|
||||
- TypeScript 官方文档
|
||||
- Vite 官方文档
|
||||
- 各 UI 组件库文档
|
||||
Reference in New Issue
Block a user