diff --git a/backend/.env b/backend/.env index 93b4f89..c1469ea 100644 --- a/backend/.env +++ b/backend/.env @@ -5,18 +5,13 @@ DB_USERNAME=root DB_PASSWORD=aiotAiot123! DB_NAME=jiebandata -# Redis配置 -REDIS_HOST=localhost -REDIS_PORT=6379 -REDIS_PASSWORD= - # JWT配置 JWT_SECRET=niumall_jwt_secret_key_2024 JWT_EXPIRES_IN=24h # 应用配置 -NODE_ENV=development -PORT=3002 +NODE_ENV=production +PORT=4330 API_PREFIX=/api # 日志配置 diff --git a/backend/CLEANUP_GUIDE.md b/backend/CLEANUP_GUIDE.md new file mode 100644 index 0000000..2fc8496 --- /dev/null +++ b/backend/CLEANUP_GUIDE.md @@ -0,0 +1,123 @@ +# 活牛采购系统 - 后端文件清理指南 + +## 概述 +本指南用于清理后端项目中不需要的文件和依赖,以优化生产环境部署。根据系统需求,我们将移除与Redis和RabbitMQ相关的文件和配置。 + +## 需要清理的文件和依赖 + +### 1. 移除Redis相关依赖 +在`package.json`文件中,我们需要删除Redis相关的依赖: + +```javascript +// 移除前 +"dependencies": { + // ...其他依赖 + "redis": "^4.6.7", + // ...其他依赖 +} + +// 移除后 +"dependencies": { + // ...其他依赖(不包含redis) +} +``` + +### 2. 移除Redis相关配置 +在代码中,我们需要删除任何与Redis相关的导入和使用: + +```bash +# 查找并删除代码中的Redis相关引用 +# 在项目根目录下执行 +find . -type f -name "*.js" | xargs grep -l "redis" | xargs sed -i '' '/redis/d' +``` + +### 3. 其他可能需要删除的文件 +根据项目实际情况,以下是可能需要删除的文件: + +- 测试文件和测试相关配置(如果不需要在生产环境中保留) +- 开发环境专用的配置文件 +- 文档文件(如果不需要在生产环境中保留) +- 临时文件和日志文件 + +## 清理步骤 + +### 1. 删除Redis依赖 +在本地项目目录中执行: + +```bash +npm uninstall redis +``` + +### 2. 查找并清理Redis相关代码 +使用以下命令查找所有包含Redis引用的文件: + +```bash +# Linux/Mac系统 +grep -r "redis" . --include="*.js" + +# Windows系统(PowerShell) +Get-ChildItem -Recurse -Include *.js | Select-String -Pattern "redis" +``` + +找到包含Redis引用的文件后,手动编辑这些文件,删除Redis相关的代码。 + +### 3. 删除其他不需要的文件 +根据项目需求,删除不需要的文件: + +```bash +# 删除测试目录(如果有) +rm -rf tests/ + +# 删除开发环境专用配置 +rm -f .env.development + +# 删除临时文件 +rm -rf temp/ + +# 删除不必要的日志文件 +rm -f logs/*.log +``` + +### 4. 更新.env文件 +确保.env文件中不包含Redis相关配置: + +```ini +# 已在之前的步骤中更新,确保没有以下配置 +# REDIS_HOST=localhost +# REDIS_PORT=6379 +# REDIS_PASSWORD= +``` + +### 5. 更新models/index.js +确保数据库连接中没有Redis相关配置: + +```javascript +// 已更新,确保没有Redis相关代码 +``` + +### 6. 重新安装依赖 +在清理完不必要的文件和依赖后,重新安装项目依赖: + +```bash +rm -rf node_modules/ +rm -f package-lock.json +npm install --production +``` + +## 生产环境部署前检查清单 +在部署到生产环境前,请确保: + +- [ ] Redis相关依赖已删除 +- [ ] Redis相关配置已删除 +- [ ] 没有使用RabbitMQ相关功能 +- [ ] 数据库连接配置正确(使用生产环境MySQL) +- [ ] 端口配置为4330 +- [ ] NODE_ENV设置为production +- [ ] Swagger文档功能在生产环境中保持启用 +- [ ] PM2配置正确(ecosystem.config.js) +- [ ] Nginx配置正确(包含SSL配置) + +## 注意事项 +1. 在执行任何删除操作前,请确保已备份重要文件。 +2. 清理完成后,请在测试环境中验证系统功能是否正常。 +3. 如果在清理过程中遇到问题,请参考项目文档或联系技术支持。 \ No newline at end of file diff --git a/backend/README_DEPLOY.md b/backend/README_DEPLOY.md new file mode 100644 index 0000000..573f4ad --- /dev/null +++ b/backend/README_DEPLOY.md @@ -0,0 +1,227 @@ +# 活牛采购系统 - 后端部署文档 + +## 系统概述 +本部署文档详细说明如何部署活牛采购智能数字化系统的后端服务,包括环境配置、文件上传、服务启动和Nginx配置等。 + +## 技术栈 +- **Node.js**: >= 18.0.0 +- **数据库**: MySQL(直接使用生产环境数据库) +- **Web服务器**: Nginx(配置SSL) +- **进程管理**: PM2 +- **API文档**: Swagger 3.0(生产环境不禁用) + +## 服务器配置 +- **操作系统**: CentOS +- **服务器地址**: www.jiebanke.com +- **后端域名**: wapi.yunniushi.cn +- **服务器目录**: /data/nodejs/yunniushi/ +- **后端端口**: 4330 +- **用户名**: root +- **密码**: Aiotjkl$7jk58s&12 + +## 部署前准备 + +### 1. 环境安装 +在CentOS服务器上安装以下软件: + +```bash +# 更新系统 +sudo yum update -y + +# 安装Node.js 18 +curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash - +sudo yum install -y nodejs + +# 安装PM2(全局) +sudo npm install -g pm2 + +# 安装Nginx +sudo yum install -y nginx + +# 启动Nginx服务并设置开机自启 +sudo systemctl start nginx +sudo systemctl enable nginx + +# 安装Git(如果需要从代码仓库克隆代码) +sudo yum install -y git +``` + +### 2. 创建服务器目录结构 +```bash +# 创建项目根目录 +sudo mkdir -p /data/nodejs/yunniushi/ +sudo chown -R $USER:$USER /data/nodejs/yunniushi/ + +# 创建日志目录 +mkdir -p /data/nodejs/yunniushi/logs + +# 创建SSL证书目录 +mkdir -p /etc/nginx/ssl/wapi.yunniushi.cn/ +``` + +### 3. 上传SSL证书 +将SSL证书文件上传到服务器上的SSL证书目录: +- fullchain.pem -> /etc/nginx/ssl/wapi.yunniushi.cn/fullchain.pem +- privkey.pem -> /etc/nginx/ssl/wapi.yunniushi.cn/privkey.pem + +## 文件同步与部署 + +### 方法一:使用同步脚本(推荐) +在本地项目目录中执行同步脚本,将代码上传到服务器: + +```bash +# 给脚本添加执行权限 +chmod +x sync_to_server.sh + +# 执行同步脚本(脚本已预配置正确的服务器信息) +./sync_to_server.sh +``` + +### 方法二:手动上传文件 +如果不使用同步脚本,可以手动将以下文件上传到服务器的 `/data/nodejs/yunniushi/` 目录: +- app.js +- package.json +- package-lock.json +- .env +- ecosystem.config.js +- config/ 目录 +- models/ 目录 +- routes/ 目录 +- start_server.sh + +### SSH连接问题排查 +如果遇到SSH连接问题,可以使用专门的测试工具进行诊断: + +```bash +# 给测试脚本添加执行权限 +chmod +x test_ssh_connection.sh + +# 执行SSH连接测试脚本 +./test_ssh_connection.sh +``` + +此脚本会执行一系列测试,包括: +- DNS解析测试 +- 网络连通性测试 +- SSH端口开放测试 +- 详细的SSH连接测试 +- 提供故障排除建议 + +## 服务启动 + +### 在服务器上启动服务 +1. 登录到服务器: +```bash +ssh root@www.jiebanke.com +# 密码: Aiotjkl$7jk58s&12 +``` + +2. 进入项目目录: +```bash +cd /data/nodejs/yunniushi/ +``` + +3. 执行启动脚本: +```bash +# 给启动脚本添加执行权限 +chmod +x start_server.sh + +# 启动服务 +./start_server.sh +``` + +### 手动启动(备选方法) +如果启动脚本出现问题,可以手动执行以下命令: + +```bash +# 安装依赖 +npm install --production + +# 启动PM2管理的服务 +npm run pm2:start + +# 设置PM2开机自启 +pm2 startup +sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u $USER --hp $HOME + +# 保存PM2配置 +sudo pm2 save +``` + +## Nginx配置 + +### 复制并激活Nginx配置文件 +1. 复制Nginx配置文件到Nginx配置目录: +```bash +# 在服务器上执行 +cp /data/nodejs/yunniushi/nginx.conf /etc/nginx/conf.d/yunniushi_backend.conf +``` + +2. 测试Nginx配置是否正确: +```bash +sudo nginx -t +``` + +3. 重启Nginx服务: +```bash +sudo systemctl restart nginx +``` + +### 防火墙配置 +如果服务器启用了防火墙,需要开放相关端口: +```bash +# 开放HTTPS端口(443) +sudo firewall-cmd --permanent --add-service=https +sudo firewall-cmd --reload +``` + +## 服务管理命令 + +### PM2常用命令 +```bash +# 查看服务状态 +npm run pm2:start + +# 停止服务 +npm run pm2:stop + +# 重启服务 +npm run pm2:restart + +# 查看服务日志 +pm2 logs niumall-backend +``` + +### Nginx常用命令 +```bash +# 启动Nginx +sudo systemctl start nginx + +# 停止Nginx +sudo systemctl stop nginx + +# 重启Nginx +sudo systemctl restart nginx + +# 查看Nginx状态 +sudo systemctl status nginx + +# 查看Nginx日志 +sudo tail -f /var/log/nginx/access.log +sudo tail -f /var/log/nginx/error.log +``` + +## 访问测试 +部署完成后,可以通过以下地址访问系统: + +- **API文档**: https://wapi.yunniushi.cn/api/docs +- **健康检查**: https://wapi.yunniushi.cn/health +- **API接口**: https://wapi.yunniushi.cn/api/[接口路径] + +## 注意事项 +1. 确保服务器上的MySQL数据库已经正确配置,并且网络连接通畅。 +2. 根据实际情况修改.env文件中的数据库连接信息。 +3. 确保SSL证书文件路径与nginx.conf中的配置一致。 +4. 如果遇到端口冲突,需要修改配置文件中的端口号。 +5. 定期备份数据库和重要配置文件。 +6. 生产环境中,请确保JWT_SECRET和数据库密码等敏感信息安全。 \ No newline at end of file diff --git a/backend/app.js b/backend/app.js index d749312..0f05f04 100644 --- a/backend/app.js +++ b/backend/app.js @@ -4,6 +4,8 @@ const helmet = require('helmet') const morgan = require('morgan') const rateLimit = require('express-rate-limit') const compression = require('compression') +const swaggerJsdoc = require('swagger-jsdoc') +const swaggerUi = require('swagger-ui-express') require('dotenv').config() // 数据库连接 @@ -19,6 +21,75 @@ app.use(morgan('combined')) // 日志 app.use(express.json({ limit: '10mb' })) app.use(express.urlencoded({ extended: true, limit: '10mb' })) +// Swagger 配置 +const swaggerOptions = { + definition: { + openapi: '3.0.0', + info: { + title: '活牛采购智能数字化系统 API', + version: '1.0.0', + description: '活牛采购标准化操作流程系统接口文档', + contact: { + name: 'API支持', + email: 'support@niumall.com' + } + }, + servers: [ + { + url: 'http://localhost:4330/api', + description: '开发环境' + }, + { + url: 'https://wapi.yunniushi.cn/api', + description: '生产环境' + } + ], + components: { + securitySchemes: { + BearerAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT' + } + }, + schemas: { + ApiResponse: { + type: 'object', + properties: { + success: { type: 'boolean', description: '请求是否成功' }, + message: { type: 'string', description: '提示信息' }, + data: { type: 'object', description: '响应数据' }, + timestamp: { type: 'string', format: 'date-time', description: '时间戳' } + } + }, + PaginationParams: { + type: 'object', + properties: { + page: { type: 'integer', description: '当前页码' }, + limit: { type: 'integer', description: '每页数量' }, + sort: { type: 'string', description: '排序字段' }, + order: { type: 'string', enum: ['asc', 'desc'], description: '排序方向' } + } + }, + PaginatedResponse: { + type: 'object', + properties: { + items: { type: 'array', description: '数据列表' }, + total: { type: 'integer', description: '总记录数' }, + page: { type: 'integer', description: '当前页码' }, + limit: { type: 'integer', description: '每页数量' }, + totalPages: { type: 'integer', description: '总页数' } + } + } + } + } + }, + apis: ['./routes/*.js', './models/*.js'] // API路由文件路径 +}; + +const swaggerSpec = swaggerJsdoc(swaggerOptions); +app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); + // 限流 const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 分钟 diff --git a/backend/ecosystem.config.js b/backend/ecosystem.config.js new file mode 100644 index 0000000..870fa98 --- /dev/null +++ b/backend/ecosystem.config.js @@ -0,0 +1,17 @@ +module.exports = { + apps: [{ + name: 'niumall-backend', + script: 'app.js', + cwd: '/data/nodejs/yunniushi/', + instances: 'max', + exec_mode: 'cluster', + env: { + NODE_ENV: 'production', + PORT: 4330 + }, + error_file: '/data/nodejs/yunniushi/logs/backend-error.log', + out_file: '/data/nodejs/yunniushi/logs/backend-out.log', + log_file: '/data/nodejs/yunniushi/logs/backend.log', + time: true + }] +} \ No newline at end of file diff --git a/backend/logs/ssh_test_20250911_190517.log b/backend/logs/ssh_test_20250911_190517.log new file mode 100644 index 0000000..8e9c8d3 --- /dev/null +++ b/backend/logs/ssh_test_20250911_190517.log @@ -0,0 +1,205 @@ +debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling +debug3: channel_clear_timeouts: clearing +debug3: ssh_connect_direct: entering +debug1: Connecting to 1.13.156.49 [1.13.156.49] port 22. +debug3: set_sock_tos: set socket 3 IP_TOS 0x48 +debug2: fd 3 setting O_NONBLOCK +debug1: fd 3 clearing O_NONBLOCK +debug1: Connection established. +debug3: timeout: 15000 ms remain after connect +debug1: identity file /Users/aiotagro/.ssh/id_rsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_rsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519 type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa-cert type -1 +debug1: Local version string SSH-2.0-OpenSSH_9.9 +debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4 +debug1: compat_banner: match: OpenSSH_7.4 pat OpenSSH_7.4* compat 0x04000006 +debug2: fd 3 setting O_NONBLOCK +debug1: Authenticating to 1.13.156.49:22 as 'root' +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug3: order_hostkeyalgs: no algorithms matched; accept original +debug3: send packet: type 20 +debug1: SSH2_MSG_KEXINIT sent +debug3: receive packet: type 20 +debug1: SSH2_MSG_KEXINIT received +debug2: local client KEXINIT proposal +debug2: KEX algorithms: sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,mlkem768x25519-sha256,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,ext-info-c,kex-strict-c-v00@openssh.com +debug2: host key algorithms: ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,rsa-sha2-512,rsa-sha2-256 +debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com +debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com +debug2: MACs ctos: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 +debug2: MACs stoc: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 +debug2: compression ctos: none,zlib@openssh.com +debug2: compression stoc: none,zlib@openssh.com +debug2: languages ctos: +debug2: languages stoc: +debug2: first_kex_follows 0 +debug2: reserved 0 +debug2: peer server KEXINIT proposal +debug2: KEX algorithms: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256 +debug2: host key algorithms: ssh-rsa,rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp256,ssh-ed25519 +debug2: ciphers ctos: aes128-ctr,aes192-ctr,aes256-ctr +debug2: ciphers stoc: aes128-ctr,aes192-ctr,aes256-ctr +debug2: MACs ctos: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 +debug2: MACs stoc: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 +debug2: compression ctos: none,zlib@openssh.com +debug2: compression stoc: none,zlib@openssh.com +debug2: languages ctos: +debug2: languages stoc: +debug2: first_kex_follows 0 +debug2: reserved 0 +debug1: kex: algorithm: curve25519-sha256 +debug1: kex: host key algorithm: ssh-ed25519 +debug1: kex: server->client cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: kex: client->server cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug3: send packet: type 30 +debug1: expecting SSH2_MSG_KEX_ECDH_REPLY +debug3: receive packet: type 31 +debug1: SSH2_MSG_KEX_ECDH_REPLY received +debug1: Server host key: ssh-ed25519 SHA256:ONgY2i3Y/Gd0HjWKt1/pcN9RLkhpVTIotxT8KOrPrGA +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +Warning: Permanently added '1.13.156.49' (ED25519) to the list of known hosts. +debug3: send packet: type 21 +debug2: ssh_set_newkeys: mode 1 +debug1: rekey out after 4294967296 blocks +debug1: SSH2_MSG_NEWKEYS sent +debug1: expecting SSH2_MSG_NEWKEYS +debug3: receive packet: type 21 +debug1: SSH2_MSG_NEWKEYS received +debug2: ssh_set_newkeys: mode 0 +debug1: rekey in after 4294967296 blocks +debug2: KEX algorithms: sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,mlkem768x25519-sha256,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,ext-info-c,kex-strict-c-v00@openssh.com +debug2: host key algorithms: ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com,rsa-sha2-512,rsa-sha2-256 +debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com +debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com +debug2: MACs ctos: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 +debug2: MACs stoc: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 +debug2: compression ctos: none,zlib@openssh.com +debug2: compression stoc: none,zlib@openssh.com +debug2: languages ctos: +debug2: languages stoc: +debug2: first_kex_follows 0 +debug2: reserved 0 +debug3: send packet: type 5 +debug3: receive packet: type 7 +debug1: SSH2_MSG_EXT_INFO received +debug3: kex_input_ext_info: extension server-sig-algs +debug1: kex_ext_info_client_parse: server-sig-algs= +debug3: receive packet: type 6 +debug2: service_accept: ssh-userauth +debug1: SSH2_MSG_SERVICE_ACCEPT received +debug3: send packet: type 50 +debug3: receive packet: type 51 +debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password +debug3: start over, passed a different list publickey,gssapi-keyex,gssapi-with-mic,password +debug3: preferred publickey,keyboard-interactive,password +debug3: authmethod_lookup publickey +debug3: remaining preferred: keyboard-interactive,password +debug3: authmethod_is_enabled publickey +debug1: Next authentication method: publickey +debug3: ssh_get_authentication_socket_path: path '/private/tmp/com.apple.launchd.eXSXPPVBcF/Listeners' +debug1: get_agent_identities: bound agent to hostkey +debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities +debug1: Will attempt key: /Users/aiotagro/.ssh/id_rsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_xmss +debug1: Will attempt key: /Users/aiotagro/.ssh/id_dsa +debug2: pubkey_prepare: done +debug1: Trying private key: /Users/aiotagro/.ssh/id_rsa +debug3: no such identity: /Users/aiotagro/.ssh/id_rsa: No such file or directory +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa +debug3: no such identity: /Users/aiotagro/.ssh/id_ecdsa: No such file or directory +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug3: no such identity: /Users/aiotagro/.ssh/id_ecdsa_sk: No such file or directory +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519 +debug3: no such identity: /Users/aiotagro/.ssh/id_ed25519: No such file or directory +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519_sk +debug3: no such identity: /Users/aiotagro/.ssh/id_ed25519_sk: No such file or directory +debug1: Trying private key: /Users/aiotagro/.ssh/id_xmss +debug3: no such identity: /Users/aiotagro/.ssh/id_xmss: No such file or directory +debug1: Trying private key: /Users/aiotagro/.ssh/id_dsa +debug3: no such identity: /Users/aiotagro/.ssh/id_dsa: No such file or directory +debug2: we did not send a packet, disable method +debug3: authmethod_lookup password +debug3: remaining preferred: ,password +debug3: authmethod_is_enabled password +debug1: Next authentication method: password +debug3: send packet: type 50 +debug2: we sent a password packet, wait for reply +debug3: receive packet: type 52 +Authenticated to 1.13.156.49 ([1.13.156.49]:22) using "password". +debug2: fd 5 setting O_NONBLOCK +debug1: channel 0: new session [client-session] (inactive timeout: 0) +debug3: ssh_session2_open: channel_new: 0 +debug2: channel 0: send open +debug3: send packet: type 90 +debug1: Requesting no-more-sessions@openssh.com +debug3: send packet: type 80 +debug1: Entering interactive session. +debug1: pledge: network +debug3: client_repledge: enter +debug3: receive packet: type 80 +debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0 +debug3: receive packet: type 91 +debug2: channel_input_open_confirmation: channel 0: callback start +debug2: fd 3 setting TCP_NODELAY +debug3: set_sock_tos: set socket 3 IP_TOS 0x20 +debug2: client_session2_setup: id 0 +debug1: Sending command: exit +debug2: channel 0: request exec confirm 1 +debug3: send packet: type 98 +debug3: client_repledge: enter +debug1: pledge: fork +debug2: channel_input_open_confirmation: channel 0: callback done +debug2: channel 0: open confirm rwindow 0 rmax 32768 +debug2: channel 0: rcvd adjust 2097152 +debug3: receive packet: type 99 +debug2: channel_input_status_confirm: type 99 id 0 +debug2: exec request accepted on channel 0 +debug3: receive packet: type 98 +debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 +debug3: receive packet: type 98 +debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0 +debug2: channel 0: rcvd eow +debug2: chan_shutdown_read: channel 0: (i0 o0 sock -1 wfd 4 efd 6 [write]) +debug2: channel 0: input open -> closed +debug3: receive packet: type 96 +debug2: channel 0: rcvd eof +debug2: channel 0: output open -> drain +debug2: channel 0: obuf empty +debug2: chan_shutdown_write: channel 0: (i3 o1 sock -1 wfd 5 efd 6 [write]) +debug2: channel 0: output drain -> closed +debug3: receive packet: type 97 +debug2: channel 0: rcvd close +debug3: channel 0: will not send data after close +debug2: channel 0: almost dead +debug2: channel 0: gc: notify user +debug2: channel 0: gc: user detached +debug2: channel 0: send_close2 +debug2: channel 0: send close for remote id 0 +debug3: send packet: type 97 +debug2: channel 0: is dead +debug2: channel 0: garbage collecting +debug1: channel 0: free: client-session, nchannels 1 +debug3: channel 0: status: The following connections are open: + #0 client-session (t4 [session] r0 nm0 i3/0 o3/0 e[write]/0 fd -1/-1/6 sock -1 cc -1 nc0 io 0x00/0x00) + +debug3: send packet: type 1 +Transferred: sent 2048, received 1880 bytes, in 0.1 seconds +Bytes per second: sent 22324.7, received 20493.4 +debug1: Exit status 0 diff --git a/backend/logs/sync_log.txt b/backend/logs/sync_log.txt new file mode 100644 index 0000000..a6e380b --- /dev/null +++ b/backend/logs/sync_log.txt @@ -0,0 +1,426 @@ +2025-09-11 17:54:38 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 17:54:38 - 代码同步失败! +2025-09-11 17:57:49 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 17:57:49 - 代码同步失败! +2025-09-11 18:19:54 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:19:54 - 代码同步失败! +2025-09-11 18:20:45 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:20:45 - 代码同步失败! +2025-09-11 18:22:24 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:22:24 - 代码同步失败! +2025-09-11 18:23:18 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:18 - 代码同步失败! +2025-09-11 18:23:19 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:19 - 代码同步失败! +2025-09-11 18:23:20 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:20 - 代码同步失败! +2025-09-11 18:23:21 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:21 - 代码同步失败! +2025-09-11 18:23:22 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:22 - 代码同步失败! +2025-09-11 18:23:23 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:23 - 代码同步失败! +2025-09-11 18:23:24 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:24 - 代码同步失败! +2025-09-11 18:23:25 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:23:25 - 代码同步失败! +2025-09-11 18:24:25 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:24:25 - 代码同步失败! +2025-09-11 18:24:30 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:24:30 - 代码同步失败! +SSH连接测试失败,无法继续同步。 +SSH连接测试失败,无法继续同步。 +SSH连接测试失败,无法继续同步。 +SSH连接测试失败,无法继续同步。 +SSH连接测试失败,无法继续同步。 +SSH连接测试失败,无法继续同步。 +SSH连接测试失败,无法继续同步。 +2025-09-11 18:56:37 - 开始同步后端代码到服务器 www.jiebanke.com... +2025-09-11 18:56:37 - 代码同步失败! +文件同步失败,请查看日志获取详细信息。 +2025-09-11 19:03:02 - 开始同步后端代码到服务器 1.13.156.49... +2025-09-11 19:03:02 - 代码同步失败! +文件同步失败,请查看日志获取详细信息。 +2025-09-11 19:03:14 - 开始同步后端代码到服务器 1.13.156.49... +2025-09-11 19:03:14 - 代码同步失败! +文件同步失败,请查看日志获取详细信息。 +OpenSSH_9.9p2, LibreSSL 3.3.6 +debug1: Reading configuration data /etc/ssh/ssh_config +debug1: /etc/ssh/ssh_config line 21: include /etc/ssh/ssh_config.d/* matched no files +debug1: /etc/ssh/ssh_config line 54: Applying options for * +debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling +debug1: Connecting to 1.13.156.49 [1.13.156.49] port 22. +debug1: fd 3 clearing O_NONBLOCK +debug1: Connection established. +debug1: identity file /Users/aiotagro/.ssh/id_rsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_rsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519 type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa-cert type -1 +debug1: Local version string SSH-2.0-OpenSSH_9.9 +debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4 +debug1: compat_banner: match: OpenSSH_7.4 pat OpenSSH_7.4* compat 0x04000006 +debug1: Authenticating to 1.13.156.49:22 as 'root' +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: SSH2_MSG_KEXINIT sent +debug1: SSH2_MSG_KEXINIT received +debug1: kex: algorithm: curve25519-sha256 +debug1: kex: host key algorithm: ssh-ed25519 +debug1: kex: server->client cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: kex: client->server cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: expecting SSH2_MSG_KEX_ECDH_REPLY +debug1: SSH2_MSG_KEX_ECDH_REPLY received +debug1: Server host key: ssh-ed25519 SHA256:ONgY2i3Y/Gd0HjWKt1/pcN9RLkhpVTIotxT8KOrPrGA +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: Host '1.13.156.49' is known and matches the ED25519 host key. +debug1: Found key in /Users/aiotagro/.ssh/known_hosts:4 +debug1: rekey out after 4294967296 blocks +debug1: SSH2_MSG_NEWKEYS sent +debug1: expecting SSH2_MSG_NEWKEYS +debug1: SSH2_MSG_NEWKEYS received +debug1: rekey in after 4294967296 blocks +debug1: SSH2_MSG_EXT_INFO received +debug1: kex_ext_info_client_parse: server-sig-algs= +debug1: SSH2_MSG_SERVICE_ACCEPT received +debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password +debug1: Next authentication method: publickey +debug1: get_agent_identities: bound agent to hostkey +debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities +debug1: Will attempt key: /Users/aiotagro/.ssh/id_rsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_xmss +debug1: Will attempt key: /Users/aiotagro/.ssh/id_dsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_rsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_xmss +debug1: Trying private key: /Users/aiotagro/.ssh/id_dsa +debug1: Next authentication method: password +Authenticated to 1.13.156.49 ([1.13.156.49]:22) using "password". +debug1: channel 0: new session [client-session] (inactive timeout: 0) +debug1: Requesting no-more-sessions@openssh.com +debug1: Entering interactive session. +debug1: pledge: filesystem +debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0 +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts for 1.13.156.49 / (none) +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts2 for 1.13.156.49 / (none) +debug1: client_input_hostkeys: hostkeys file /Users/aiotagro/.ssh/known_hosts2 does not exist +debug1: client_input_hostkeys: host key found matching a different name/address, skipping UserKnownHostsFile update +debug1: Sending environment. +debug1: channel 0: setting env LANG = "zh_CN.UTF-8" +debug1: Sending command: exit +debug1: pledge: fork +debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 +debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0 +debug1: channel 0: free: client-session, nchannels 1 +Transferred: sent 2100, received 1880 bytes, in 0.1 seconds +Bytes per second: sent 25990.7, received 23267.9 +debug1: Exit status 0 +2025-09-11 19:08:49 - 开始同步后端代码到服务器 1.13.156.49... +2025-09-11 19:08:49 - 代码同步失败! +文件同步失败,请查看日志获取详细信息。 +OpenSSH_9.9p2, LibreSSL 3.3.6 +debug1: Reading configuration data /etc/ssh/ssh_config +debug1: /etc/ssh/ssh_config line 21: include /etc/ssh/ssh_config.d/* matched no files +debug1: /etc/ssh/ssh_config line 54: Applying options for * +debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling +debug1: Connecting to 1.13.156.49 [1.13.156.49] port 22. +debug1: fd 3 clearing O_NONBLOCK +debug1: Connection established. +debug1: identity file /Users/aiotagro/.ssh/id_rsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_rsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519 type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa-cert type -1 +debug1: Local version string SSH-2.0-OpenSSH_9.9 +debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4 +debug1: compat_banner: match: OpenSSH_7.4 pat OpenSSH_7.4* compat 0x04000006 +debug1: Authenticating to 1.13.156.49:22 as 'root' +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: SSH2_MSG_KEXINIT sent +debug1: SSH2_MSG_KEXINIT received +debug1: kex: algorithm: curve25519-sha256 +debug1: kex: host key algorithm: ssh-ed25519 +debug1: kex: server->client cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: kex: client->server cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: expecting SSH2_MSG_KEX_ECDH_REPLY +debug1: SSH2_MSG_KEX_ECDH_REPLY received +debug1: Server host key: ssh-ed25519 SHA256:ONgY2i3Y/Gd0HjWKt1/pcN9RLkhpVTIotxT8KOrPrGA +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: Host '1.13.156.49' is known and matches the ED25519 host key. +debug1: Found key in /Users/aiotagro/.ssh/known_hosts:4 +debug1: rekey out after 4294967296 blocks +debug1: SSH2_MSG_NEWKEYS sent +debug1: expecting SSH2_MSG_NEWKEYS +debug1: SSH2_MSG_NEWKEYS received +debug1: rekey in after 4294967296 blocks +debug1: SSH2_MSG_EXT_INFO received +debug1: kex_ext_info_client_parse: server-sig-algs= +debug1: SSH2_MSG_SERVICE_ACCEPT received +debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password +debug1: Next authentication method: publickey +debug1: get_agent_identities: bound agent to hostkey +debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities +debug1: Will attempt key: /Users/aiotagro/.ssh/id_rsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_xmss +debug1: Will attempt key: /Users/aiotagro/.ssh/id_dsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_rsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_xmss +debug1: Trying private key: /Users/aiotagro/.ssh/id_dsa +debug1: Next authentication method: password +Authenticated to 1.13.156.49 ([1.13.156.49]:22) using "password". +debug1: channel 0: new session [client-session] (inactive timeout: 0) +debug1: Requesting no-more-sessions@openssh.com +debug1: Entering interactive session. +debug1: pledge: filesystem +debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0 +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts for 1.13.156.49 / (none) +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts2 for 1.13.156.49 / (none) +debug1: client_input_hostkeys: hostkeys file /Users/aiotagro/.ssh/known_hosts2 does not exist +debug1: client_input_hostkeys: host key found matching a different name/address, skipping UserKnownHostsFile update +debug1: Sending environment. +debug1: channel 0: setting env LANG = "zh_CN.UTF-8" +debug1: Sending command: exit +debug1: pledge: fork +debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 +debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0 +debug1: channel 0: free: client-session, nchannels 1 +Transferred: sent 2100, received 1880 bytes, in 0.1 seconds +Bytes per second: sent 20501.8, received 18354.0 +debug1: Exit status 0 +2025-09-11 19:12:07 - 开始同步后端代码到服务器 1.13.156.49... +2025-09-11 19:13:10 - 代码同步成功! +2025-09-11 19:13:17 - 正在安装远程依赖... +2025-09-11 19:13:44 - 依赖安装成功! +2025-09-11 19:13:52 - 正在重启远程服务... +OpenSSH_9.9p2, LibreSSL 3.3.6 +debug1: Reading configuration data /etc/ssh/ssh_config +debug1: /etc/ssh/ssh_config line 21: include /etc/ssh/ssh_config.d/* matched no files +debug1: /etc/ssh/ssh_config line 54: Applying options for * +debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling +debug1: Connecting to 1.13.156.49 [1.13.156.49] port 22. +debug1: fd 3 clearing O_NONBLOCK +debug1: Connection established. +debug1: identity file /Users/aiotagro/.ssh/id_rsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_rsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519 type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa-cert type -1 +debug1: Local version string SSH-2.0-OpenSSH_9.9 +debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4 +debug1: compat_banner: match: OpenSSH_7.4 pat OpenSSH_7.4* compat 0x04000006 +debug1: Authenticating to 1.13.156.49:22 as 'root' +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: SSH2_MSG_KEXINIT sent +debug1: SSH2_MSG_KEXINIT received +debug1: kex: algorithm: curve25519-sha256 +debug1: kex: host key algorithm: ssh-ed25519 +debug1: kex: server->client cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: kex: client->server cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: expecting SSH2_MSG_KEX_ECDH_REPLY +debug1: SSH2_MSG_KEX_ECDH_REPLY received +debug1: Server host key: ssh-ed25519 SHA256:ONgY2i3Y/Gd0HjWKt1/pcN9RLkhpVTIotxT8KOrPrGA +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: Host '1.13.156.49' is known and matches the ED25519 host key. +debug1: Found key in /Users/aiotagro/.ssh/known_hosts:4 +debug1: rekey out after 4294967296 blocks +debug1: SSH2_MSG_NEWKEYS sent +debug1: expecting SSH2_MSG_NEWKEYS +debug1: SSH2_MSG_NEWKEYS received +debug1: rekey in after 4294967296 blocks +debug1: SSH2_MSG_EXT_INFO received +debug1: kex_ext_info_client_parse: server-sig-algs= +debug1: SSH2_MSG_SERVICE_ACCEPT received +debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password +debug1: Next authentication method: publickey +debug1: get_agent_identities: bound agent to hostkey +debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities +debug1: Will attempt key: /Users/aiotagro/.ssh/id_rsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_xmss +debug1: Will attempt key: /Users/aiotagro/.ssh/id_dsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_rsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_xmss +debug1: Trying private key: /Users/aiotagro/.ssh/id_dsa +debug1: Next authentication method: password +Authenticated to 1.13.156.49 ([1.13.156.49]:22) using "password". +debug1: channel 0: new session [client-session] (inactive timeout: 0) +debug1: Requesting no-more-sessions@openssh.com +debug1: Entering interactive session. +debug1: pledge: filesystem +debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0 +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts for 1.13.156.49 / (none) +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts2 for 1.13.156.49 / (none) +debug1: client_input_hostkeys: hostkeys file /Users/aiotagro/.ssh/known_hosts2 does not exist +debug1: client_input_hostkeys: host key found matching a different name/address, skipping UserKnownHostsFile update +debug1: Sending environment. +debug1: channel 0: setting env LANG = "zh_CN.UTF-8" +debug1: Sending command: exit +debug1: pledge: fork +debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 +debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0 +debug1: channel 0: free: client-session, nchannels 1 +Transferred: sent 2100, received 1880 bytes, in 0.1 seconds +Bytes per second: sent 20348.0, received 18216.3 +debug1: Exit status 0 +2025-09-11 19:15:42 - 开始同步后端代码到服务器 1.13.156.49... +2025-09-11 19:15:44 - 代码同步成功! +2025-09-11 19:15:47 - 正在安装远程依赖... +2025-09-11 19:15:52 - 依赖安装成功! +2025-09-11 19:15:57 - 正在重启远程服务... +2025-09-11 19:15:57 - 已提示用户手动重启服务。 +OpenSSH_9.9p2, LibreSSL 3.3.6 +debug1: Reading configuration data /etc/ssh/ssh_config +debug1: /etc/ssh/ssh_config line 21: include /etc/ssh/ssh_config.d/* matched no files +debug1: /etc/ssh/ssh_config line 54: Applying options for * +debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling +debug1: Connecting to 1.13.156.49 [1.13.156.49] port 22. +debug1: fd 3 clearing O_NONBLOCK +debug1: Connection established. +debug1: identity file /Users/aiotagro/.ssh/id_rsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_rsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ecdsa_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519 type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk type -1 +debug1: identity file /Users/aiotagro/.ssh/id_ed25519_sk-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss type -1 +debug1: identity file /Users/aiotagro/.ssh/id_xmss-cert type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa type -1 +debug1: identity file /Users/aiotagro/.ssh/id_dsa-cert type -1 +debug1: Local version string SSH-2.0-OpenSSH_9.9 +debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4 +debug1: compat_banner: match: OpenSSH_7.4 pat OpenSSH_7.4* compat 0x04000006 +debug1: Authenticating to 1.13.156.49:22 as 'root' +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: SSH2_MSG_KEXINIT sent +debug1: SSH2_MSG_KEXINIT received +debug1: kex: algorithm: curve25519-sha256 +debug1: kex: host key algorithm: ssh-ed25519 +debug1: kex: server->client cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: kex: client->server cipher: aes128-ctr MAC: umac-64-etm@openssh.com compression: none +debug1: expecting SSH2_MSG_KEX_ECDH_REPLY +debug1: SSH2_MSG_KEX_ECDH_REPLY received +debug1: Server host key: ssh-ed25519 SHA256:ONgY2i3Y/Gd0HjWKt1/pcN9RLkhpVTIotxT8KOrPrGA +debug1: load_hostkeys: fopen /Users/aiotagro/.ssh/known_hosts2: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory +debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory +debug1: Host '1.13.156.49' is known and matches the ED25519 host key. +debug1: Found key in /Users/aiotagro/.ssh/known_hosts:4 +debug1: rekey out after 4294967296 blocks +debug1: SSH2_MSG_NEWKEYS sent +debug1: expecting SSH2_MSG_NEWKEYS +debug1: SSH2_MSG_NEWKEYS received +debug1: rekey in after 4294967296 blocks +debug1: SSH2_MSG_EXT_INFO received +debug1: kex_ext_info_client_parse: server-sig-algs= +debug1: SSH2_MSG_SERVICE_ACCEPT received +debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password +debug1: Next authentication method: publickey +debug1: get_agent_identities: bound agent to hostkey +debug1: get_agent_identities: ssh_fetch_identitylist: agent contains no identities +debug1: Will attempt key: /Users/aiotagro/.ssh/id_rsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Will attempt key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Will attempt key: /Users/aiotagro/.ssh/id_xmss +debug1: Will attempt key: /Users/aiotagro/.ssh/id_dsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_rsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa +debug1: Trying private key: /Users/aiotagro/.ssh/id_ecdsa_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519 +debug1: Trying private key: /Users/aiotagro/.ssh/id_ed25519_sk +debug1: Trying private key: /Users/aiotagro/.ssh/id_xmss +debug1: Trying private key: /Users/aiotagro/.ssh/id_dsa +debug1: Next authentication method: password +Authenticated to 1.13.156.49 ([1.13.156.49]:22) using "password". +debug1: channel 0: new session [client-session] (inactive timeout: 0) +debug1: Requesting no-more-sessions@openssh.com +debug1: Entering interactive session. +debug1: pledge: filesystem +debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0 +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts for 1.13.156.49 / (none) +debug1: client_input_hostkeys: searching /Users/aiotagro/.ssh/known_hosts2 for 1.13.156.49 / (none) +debug1: client_input_hostkeys: hostkeys file /Users/aiotagro/.ssh/known_hosts2 does not exist +debug1: client_input_hostkeys: host key found matching a different name/address, skipping UserKnownHostsFile update +debug1: Sending environment. +debug1: channel 0: setting env LANG = "zh_CN.UTF-8" +debug1: Sending command: exit +debug1: pledge: fork +debug1: client_input_channel_req: channel 0 rtype exit-status reply 0 +debug1: client_input_channel_req: channel 0 rtype eow@openssh.com reply 0 +debug1: channel 0: free: client-session, nchannels 1 +Transferred: sent 2100, received 1880 bytes, in 0.1 seconds +Bytes per second: sent 22521.1, received 20161.7 +debug1: Exit status 0 +2025-09-11 19:39:29 - 开始同步后端代码到服务器 1.13.156.49... +2025-09-11 19:39:32 - 代码同步成功! +2025-09-11 19:39:37 - 正在安装远程依赖... +2025-09-11 19:39:43 - 依赖安装成功! +2025-09-11 19:39:49 - 正在重启远程服务... +2025-09-11 19:39:49 - 已提示用户手动重启服务。 diff --git a/backend/nginx.conf b/backend/nginx.conf new file mode 100644 index 0000000..bab1bf2 --- /dev/null +++ b/backend/nginx.conf @@ -0,0 +1,121 @@ +# 活牛采购系统Nginx配置文件 +# 此配置文件用于配置Nginx作为反向代理服务器,提供HTTPS访问 + +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log; +pid /run/nginx.pid; + +# 加载动态模块 +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # 开启gzip压缩 + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # 虚拟主机配置 - 活牛采购系统后端API + server { + # 监听HTTP端口,重定向到HTTPS + listen 80; + server_name wapi.yunniushi.cn; + return 301 https://$server_name$request_uri; + } + + server { + # 监听HTTPS端口 + listen 443 ssl http2; + server_name wapi.yunniushi.cn; + + # SSL证书配置 + ssl_certificate /etc/nginx/ssl/wapi.yunniushi.cn/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/wapi.yunniushi.cn/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers off; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + + # HSTS配置 + add_header Strict-Transport-Security "max-age=63072000" always; + + # 安全头部配置 + add_header X-Frame-Options DENY; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + + # 反向代理配置 + location / { + # 代理到Node.js后端服务 + proxy_pass http://localhost:4330; + 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; + + # 增加代理超时 + proxy_connect_timeout 600s; + proxy_send_timeout 600s; + proxy_read_timeout 600s; + } + + # 静态文件服务配置(如果需要) + # location /public { + # alias /data/nodejs/yunniushi/public; + # expires 30d; + # } + + # 健康检查端点 + location /health { + proxy_pass http://localhost:4330; + proxy_http_version 1.1; + proxy_set_header Host $host; + access_log off; + } + + # API文档端点 + location /api/docs { + proxy_pass http://localhost:4330; + proxy_http_version 1.1; + proxy_set_header Host $host; + } + + # 错误页面配置 + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + } + + # 加载其他配置文件 + include /etc/nginx/conf.d/*.conf; +} \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 794c5b5..36469b3 100644 --- a/backend/package.json +++ b/backend/package.json @@ -46,9 +46,10 @@ "morgan": "^1.10.1", "multer": "^1.4.5-lts.1", "mysql2": "^3.6.0", - "redis": "^4.6.7", "sequelize": "^6.32.1", "socket.io": "^4.7.2", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.0", "uuid": "^9.0.0", "winston": "^3.10.0" }, diff --git a/backend/start_server.sh b/backend/start_server.sh new file mode 100755 index 0000000..66960a0 --- /dev/null +++ b/backend/start_server.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# 结伴客后端服务器启动脚本 +# 适用于CentOS生产环境 +# 服务器目录: /data/nodejsjiebanke/ + +set -e + +# 配置参数 +APP_NAME="yunniushi-backend" +APP_DIR="/data/nodejs/yunniushi" +PORT="4330" +LOG_DIR="$APP_DIR/logs" + +cd "$APP_DIR" + +echo "🚀 开始启动 $APP_NAME 服务..." +echo "📋 工作目录: $APP_DIR" +echo "🔌 服务端口: $PORT" +echo "📊 日志目录: $LOG_DIR" +echo "" + +# 创建日志目录 +if [ ! -d "$LOG_DIR" ]; then + mkdir -p "$LOG_DIR" + echo "✅ 创建日志目录: $LOG_DIR" +fi + +# 检查Node.js环境 +echo "🔍 检查Node.js环境..." +if ! command -v node &> /dev/null; then + echo "❌ Node.js未安装,请先安装Node.js" + exit 1 +fi + +if ! command -v npm &> /dev/null; then + echo "❌ npm未安装,请先安装npm" + exit 1 +fi + +if ! command -v pm2 &> /dev/null; then + echo "❌ pm2未安装,正在安装pm2..." + npm install -g pm2 + echo "✅ pm2安装完成" +fi + +echo "✅ Node.js版本: $(node -v)" +echo "✅ npm版本: $(npm -v)" +echo "✅ pm2版本: $(pm2 -v)" + +# 安装依赖 +echo "" +echo "📦 安装项目依赖..." +npm install --production + +# 停止现有服务(如果存在) +echo "" +echo "🛑 停止现有服务..." +pm2 delete "$APP_NAME" 2>/dev/null || true +pm2 flush "$APP_NAME" 2>/dev/null || true + +# 启动服务 +echo "" +echo "🚀 启动服务..." +NODE_ENV=production PORT=$PORT pm2 start ecosystem.config.js --name "$APP_NAME" + +# 保存pm2配置 +echo "" +echo "💾 保存pm2配置..." +pm2 save + +# 设置开机自启 +echo "" +echo "🔧 设置开机自启..." +pm2 startup 2>/dev/null || echo "⚠️ 开机自启设置可能需要手动执行: pm2 startup" + +# 显示服务状态 +echo "" +echo "📊 服务状态:" +pm2 status "$APP_NAME" + +echo "" +echo "✅ $APP_NAME 服务启动成功!" +echo "🌐 服务地址: http://localhost:$PORT" +echo "📋 启动时间: $(date)" +echo "" +echo "💡 常用命令:" +echo " 查看日志: pm2 logs $APP_NAME" +echo " 重启服务: pm2 restart $APP_NAME" +echo " 停止服务: pm2 stop $APP_NAME" +echo " 服务状态: pm2 status" \ No newline at end of file diff --git a/backend/sync_to_server.sh b/backend/sync_to_server.sh new file mode 100755 index 0000000..55c09fe --- /dev/null +++ b/backend/sync_to_server.sh @@ -0,0 +1,221 @@ +#!/bin/bash + +# 活牛采购系统后端代码同步脚本 +# 此脚本用于将本地后端代码同步到远程服务器 + +# 设置脚本执行选项:发生错误时退出,命令出错时退出(移除了-u选项,因为密码中包含$字符可能导致未绑定变量错误) +set -eo pipefail + +# 服务器配置 +SERVER=1.13.156.49 +SERVER_DIR=/data/nodejs/yunniushi/ +SSH_PORT=22 +SSH_USER="root" + +# 本地目录配置 +LOCAL_DIR=$(pwd) + +# 日志配置 +LOG_FILE=sync_log.txt +LOG_DIR="$LOCAL_DIR/logs" + +# 检查必要的工具是否安装 +check_dependencies() { + echo "检查必要工具..." + if ! command -v rsync &> /dev/null; then + echo "错误: rsync命令未安装,请先安装rsync!" + echo "在Mac上: brew install rsync" + echo "在Ubuntu上: sudo apt-get install rsync" + echo "在CentOS上: sudo yum install rsync" + exit 1 + fi + if ! command -v ssh &> /dev/null; then + echo "错误: ssh命令未安装,请先安装ssh!" + exit 1 + fi + echo "所有必要工具已安装" +} + +# 创建日志目录(如果不存在) +create_log_directory() { + if [ ! -d "$LOG_DIR" ]; then + echo "创建日志目录: $LOG_DIR" + mkdir -p "$LOG_DIR" + fi +} + +# 显示脚本配置信息 +show_config() { + echo "\n===== 同步配置信息 =====" + echo "本地目录: $LOCAL_DIR" + echo "远程服务器: $SERVER" + echo "远程目录: $SERVER_DIR" + echo "SSH端口: $SSH_PORT" + echo "SSH用户: $SSH_USER" + echo "服务器类型: CentOS" + echo "日志文件: $LOG_DIR/$LOG_FILE" + echo "======================\n" +} + +# 测试SSH连接 +test_ssh_connection() { + echo "测试SSH连接到 $SERVER..." + echo "命令格式: ssh -p $SSH_PORT $SSH_USER@$SERVER" + echo "服务器类型: CentOS,用户名: root,密码: Aiotjkl$7jk58s&12" + + # 尝试使用详细模式连接,显示更多信息 + echo "\n正在尝试SSH连接测试(详细模式)..." + ssh -v -p $SSH_PORT -o ConnectTimeout=10 $SSH_USER@$SERVER 'exit' 2>&1 | tee -a "$LOG_DIR/$LOG_FILE" + + # 检查连接结果 + if [ $? -eq 0 ]; then + echo "SSH连接成功!" + return 0 + else + echo "\n错误: SSH连接失败,请检查以下可能的原因:" + echo "1. 服务器地址是否正确: $SERVER" + echo "2. 服务器是否在线,网络连接是否通畅" + echo "3. SSH端口是否正确: $SSH_PORT" + echo "4. 用户名是否正确: $SSH_USER" + echo "5. 密码是否正确: Aiotjkl$7jk58s&12" + echo "6. 服务器防火墙是否允许SSH连接" + echo "7. 本地网络是否有防火墙限制" + echo "\n排查建议:" + echo "- 手动执行以下命令测试连接:ssh -p $SSH_PORT $SSH_USER@$SERVER" + echo "- 如果使用密钥认证,请确保密钥已正确配置" + echo "- 如果是首次连接,可能需要手动接受服务器指纹" + echo "- 检查服务器的SSH服务是否正常运行" + return 1 + fi +} + +# 同步文件到服务器 +sync_files() { + echo "$(date +'%Y-%m-%d %H:%M:%S') - 开始同步后端代码到服务器 $SERVER..." | tee -a "$LOG_DIR/$LOG_FILE" + + # 排除列表 + EXCLUDE_LIST=( + --exclude='node_modules/' + --exclude='.git/' + --exclude='logs/' + --exclude='.env' + --exclude='.DS_Store' + --exclude='CLEANUP_GUIDE.md' + --exclude='README_DEPLOY.md' + ) + + # 执行rsync同步 + rsync -avz --delete \ + "${EXCLUDE_LIST[@]}" \ + --progress \ + -e "ssh -p $SSH_PORT" \ + "$LOCAL_DIR/" \ + "$SSH_USER@$SERVER:$SERVER_DIR" + + # 检查同步结果 + if [ $? -eq 0 ]; then + echo "$(date +'%Y-%m-%d %H:%M:%S') - 代码同步成功!" | tee -a "$LOG_DIR/$LOG_FILE" + return 0 + else + echo "$(date +'%Y-%m-%d %H:%M:%S') - 代码同步失败!" | tee -a "$LOG_DIR/$LOG_FILE" + return 1 + fi +} + +# 安装远程依赖 +install_dependencies() { + echo "$(date +'%Y-%m-%d %H:%M:%S') - 正在安装远程依赖..." | tee -a "$LOG_DIR/$LOG_FILE" + + ssh -p $SSH_PORT "$SSH_USER@$SERVER" "cd $SERVER_DIR && npm install --production" + + if [ $? -eq 0 ]; then + echo "$(date +'%Y-%m-%d %H:%M:%S') - 依赖安装成功!" | tee -a "$LOG_DIR/$LOG_FILE" + return 0 + else + echo "$(date +'%Y-%m-%d %H:%M:%S') - 依赖安装失败,请手动检查!" | tee -a "$LOG_DIR/$LOG_FILE" + return 1 + fi +} + +# 重启远程服务 +restart_service() { + echo "$(date +'%Y-%m-%d %H:%M:%S') - 正在重启远程服务..." | tee -a "$LOG_DIR/$LOG_FILE" + + echo "\n警告:在CentOS系统上,以root用户直接运行Node.js应用程序可能会遇到权限问题。" + echo "建议在服务器上手动执行以下命令重启服务:" + echo "ssh -p $SSH_PORT $SSH_USER@$SERVER 'cd $SERVER_DIR && npm run pm2:restart'" + echo "如果遇到权限问题,可以尝试:" + echo "1. 使用非root用户运行PM2" + echo "2. 或者执行:ssh -p $SSH_PORT $SSH_USER@$SERVER 'cd $SERVER_DIR && pm2 start ecosystem.config.js'" + echo "3. 或者参考PM2的文档配置正确的权限" + + # 由于权限问题,我们不再自动执行重启命令,而是让用户手动操作 + echo "$(date +'%Y-%m-%d %H:%M:%S') - 已提示用户手动重启服务。" | tee -a "$LOG_DIR/$LOG_FILE" + return 0 +} + +# 显示完成信息 +show_completion_message() { + echo "\n===== 同步完成 =====" + echo "代码已成功同步到服务器 $SERVER" + echo "服务器类型: CentOS" + echo "用户名: $SSH_USER" + echo "\n您可以通过以下方式验证服务状态:" + echo "1. 检查服务日志: ssh -p $SSH_PORT $SSH_USER@$SERVER 'pm2 logs niumall-backend'" + echo "2. 访问健康检查: https://wapi.yunniushi.cn/health" + echo "3. 查看API文档: https://wapi.yunniushi.cn/api/docs" + echo "\n如果需要手动重启服务,请执行:" + echo "ssh -p $SSH_PORT $SSH_USER@$SERVER 'cd $SERVER_DIR && npm run pm2:restart'" + echo "=====================\n" +} + +# 主函数 +main() { + # 1. 检查依赖 + check_dependencies + + # 2. 创建日志目录 + create_log_directory + + # 3. 显示配置信息 + show_config + + # 4. 询问是否跳过SSH连接测试(用于调试) + read -p "是否跳过SSH连接测试?(y/N): " SKIP_SSH_TEST + if [ "$SKIP_SSH_TEST" != "y" ] && [ "$SKIP_SSH_TEST" != "Y" ]; then + # 测试SSH连接 + if ! test_ssh_connection; then + echo "\nSSH连接测试失败!" + read -p "是否强制继续同步?(y/N): " FORCE_CONTINUE + if [ "$FORCE_CONTINUE" != "y" ] && [ "$FORCE_CONTINUE" != "Y" ]; then + echo "同步已取消。" | tee -a "$LOG_DIR/$LOG_FILE" + exit 1 + fi + echo "强制继续同步..." | tee -a "$LOG_DIR/$LOG_FILE" + fi + fi + + # 5. 同步文件 + if ! sync_files; then + echo "文件同步失败,请查看日志获取详细信息。" | tee -a "$LOG_DIR/$LOG_FILE" + exit 1 + fi + + # 6. 询问是否安装依赖 + read -p "是否在服务器上安装依赖?(y/n): " INSTALL_DEP + if [ "$INSTALL_DEP" = "y" ] || [ "$INSTALL_DEP" = "Y" ]; then + install_dependencies + fi + + # 7. 询问是否重启服务 + read -p "是否重启服务器上的服务?(y/n): " RESTART_SVC + if [ "$RESTART_SVC" = "y" ] || [ "$RESTART_SVC" = "Y" ]; then + restart_service + fi + + # 8. 显示完成信息 + show_completion_message +} + +# 执行主函数 +main \ No newline at end of file diff --git a/backend/test_ssh_connection.sh b/backend/test_ssh_connection.sh new file mode 100755 index 0000000..613e976 --- /dev/null +++ b/backend/test_ssh_connection.sh @@ -0,0 +1,189 @@ +#!/bin/bash + +# SSH连接测试脚本 +# 此脚本用于诊断和测试SSH连接问题 + +# 设置脚本执行选项 +export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' +set -eo pipefail # 移除了-u选项,因为密码中包含$字符可能导致未绑定变量错误 + +# 服务器配置 +SERVER=1.13.156.49 +SSH_PORT=22 +SSH_USER="root" + +# 日志配置 +LOG_DIR="$(pwd)/logs" +LOG_FILE="ssh_test_$(date +'%Y%m%d_%H%M%S').log" + +# 创建日志目录 +if [ ! -d "$LOG_DIR" ]; then + echo "创建日志目录: $LOG_DIR" + mkdir -p "$LOG_DIR" +fi + +# 显示配置信息 +show_config() { + echo "\n===== SSH连接测试配置 =====" + echo "服务器地址: $SERVER" + echo "SSH端口: $SSH_PORT" + echo "用户名: $SSH_USER" + echo "服务器类型: CentOS" + echo "密码: Aiotjkl$7jk58s&12" + echo "日志文件: $LOG_DIR/$LOG_FILE" + echo "=========================\n" +} + +# 检查必要工具 +check_tools() { + echo "检查必要工具..." + if ! command -v ssh &> /dev/null; then + echo "错误: ssh命令未安装,请先安装ssh!" + exit 1 + fi + if ! command -v ping &> /dev/null; then + echo "错误: ping命令未安装,请先安装!" + exit 1 + fi + if ! command -v nc &> /dev/null; then + echo "错误: nc命令未安装,请先安装!" + echo "在Mac上: brew install netcat" + echo "在Ubuntu上: sudo apt-get install netcat" + echo "在CentOS上: sudo yum install nc" + exit 1 + fi + echo "所有必要工具已安装\n" +} + +# 测试网络连接 +test_network() { + echo "===== 测试网络连接 =====" + echo "测试服务器可达性 (ping)..." + ping -c 4 $SERVER || echo "警告: ping测试失败,但SSH仍可能工作" + echo "\n测试SSH端口开放情况..." + nc -zv $SERVER $SSH_PORT 2>&1 || { + echo "错误: 无法连接到 $SERVER 的 $SSH_PORT 端口" + echo "可能的原因:" + echo "1. 服务器未启动或网络不可达" + echo "2. 服务器防火墙阻止了该端口" + echo "3. SSH服务未运行" + echo "4. 端口号配置错误" + return 1 + } + echo "SSH端口测试通过!\n" + return 0 +} + +# 测试DNS解析 +test_dns() { + echo "===== 测试DNS解析 =====" + echo "解析服务器地址..." + IP_ADDRESS=$(dig +short $SERVER || getent hosts $SERVER | awk '{print $1}') + if [ -z "$IP_ADDRESS" ]; then + echo "错误: 无法解析服务器地址 $SERVER" + echo "请检查DNS配置或确认服务器地址是否正确" + return 1 + fi + echo "服务器IP地址: $IP_ADDRESS\n" + return 0 +} + +# 详细的SSH连接测试 +test_ssh_connection() { + echo "===== 详细SSH连接测试 =====" + echo "正在尝试SSH连接(详细模式)..." + echo "命令: ssh -v -p $SSH_PORT $SSH_USER@$SERVER" + + # 创建一个临时的SSH配置文件,禁用一些可能导致问题的选项 + TEMP_SSH_CONFIG=$(mktemp) + cat > "$TEMP_SSH_CONFIG" << EOF +Host test-connection + HostName $SERVER + Port $SSH_PORT + User $SSH_USER + StrictHostKeyChecking no + UserKnownHostsFile /dev/null + ConnectTimeout 15 + LogLevel DEBUG3 +EOF + + echo "\nSSH详细连接日志(保存到 $LOG_DIR/$LOG_FILE):" + ssh -F "$TEMP_SSH_CONFIG" test-connection 'exit' 2>&1 | tee "$LOG_DIR/$LOG_FILE" + + # 清理临时文件 + rm -f "$TEMP_SSH_CONFIG" + + # 检查连接结果 + if [ ${PIPESTATUS[0]} -eq 0 ]; then + echo "\nSSH连接成功!" + return 0 + else + echo "\nSSH连接失败!请查看日志 $LOG_DIR/$LOG_FILE 获取详细信息" + return 1 + fi +} + +# 显示故障排除指南 +display_troubleshooting() { + echo "\n===== SSH连接故障排除指南 =====" + echo "\n常见问题和解决方案:" + echo "\n1. 服务器地址或端口错误" + echo " - 确认服务器地址: $SERVER" + echo " - 确认SSH端口: $SSH_PORT" + echo "\n2. 认证问题" + echo " - 确认用户名: $SSH_USER" + echo " - 确认密码: Aiotjkl$7jk58s&12" + echo " - 注意密码中的特殊字符可能需要转义" + echo " - 检查是否启用了密钥认证而不是密码认证" + echo "\n3. 防火墙问题" + echo " - 服务器防火墙是否允许SSH连接(端口 $SSH_PORT)" + echo " - 本地网络防火墙是否允许出站SSH连接" + echo " - 可能需要联系网络管理员开放相关端口" + echo "\n4. SSH服务问题" + echo " - 确认服务器上的SSH服务是否正在运行" + echo " - 服务器的SSH配置是否允许密码认证" + echo "\n5. 其他解决方案" + echo " - 尝试手动连接:ssh -p $SSH_PORT $SSH_USER@$SERVER" + echo " - 如果是首次连接,手动接受服务器指纹" + echo " - 检查本地SSH配置文件 (~/.ssh/config) 是否有冲突的设置" + echo " - 尝试使用IP地址而不是域名连接" + echo "\n如果以上方法都无法解决问题,请联系服务器管理员获取帮助。" +echo "======================================\n" +} + +# 主函数 +main() { + echo "SSH连接测试工具 v1.0" + echo "测试与 $SERVER 的SSH连接...\n" + + # 1. 显示配置信息 + show_config + + # 2. 检查必要工具 + check_tools + + # 3. 测试DNS解析 + if ! test_dns; then + echo "DNS解析测试失败,无法继续。" + display_troubleshooting + exit 1 + fi + + # 4. 测试网络连接 + if ! test_network; then + echo "网络连接测试失败,无法继续。" + display_troubleshooting + exit 1 + fi + + # 5. 详细的SSH连接测试 + if test_ssh_connection; then + echo "\n恭喜!SSH连接测试成功。您可以使用sync_to_server.sh脚本进行代码同步。" + else + display_troubleshooting + exit 1 + fi +} + +# 执行主函数 +main \ No newline at end of file diff --git a/docs/开发计划.md b/docs/开发计划.md new file mode 100644 index 0000000..be84b35 --- /dev/null +++ b/docs/开发计划.md @@ -0,0 +1,251 @@ +# 活牛采购智能数字化系统 - 开发计划 + +## 版本历史 +| 版本 | 日期 | 作者 | 说明 | +|------|------|------|------| +| v1.0 | 2024-05-15 | 系统架构师 | 基于现有项目状态制定开发计划 | + +## 1. 项目概述 + +基于当前项目状态,活牛采购智能数字化系统已完成基础架构搭建和部分功能的模拟实现。为确保系统按时、高质量交付,特制定本开发计划。 + +### 1.1 项目目标 +- 完成活牛采购全流程的数字化管理 +- 实现四类用户角色(采购人、贸易商、供应商、司机)的完整功能 +- 确保系统性能、安全和可靠性满足需求 +- 实现与第三方服务(支付、地图等)的集成 + +### 1.2 项目范围 +根据PRD,本次开发覆盖以下范围: +- 采购订单管理 +- 牛只核验管理 +- 运输跟踪管理 +- 到货验收管理 +- 结算支付管理 +- 异常处理 + +## 2. 开发团队构成 + +| 角色 | 人数 | 职责描述 | +|------|------|----------| +| 项目经理 | 1 | 整体项目管理、进度控制、风险管理 | +| 产品经理 | 1 | 需求分析、产品设计、用户体验 | +| 系统架构师 | 1 | 技术架构设计、技术选型、系统优化 | +| 前端开发工程师 | 2 | 管理后台、小程序开发、用户界面实现 | +| 后端开发工程师 | 2 | API接口开发、业务逻辑实现、数据库设计 | +| 测试工程师 | 1 | 功能测试、性能测试、自动化测试 | +| UI/UX设计师 | 1 | 界面设计、交互设计、用户体验优化 | + +## 3. 开发方法论 + +采用敏捷开发方法论,通过迭代开发快速交付可用功能,持续优化和改进产品。 + +### 3.1 迭代周期 +- 每2周为一个迭代周期 +- 每个迭代包含需求分析、设计、开发、测试和评审环节 +- 迭代结束后进行成果演示和回顾 + +### 3.2 开发流程 +1. 需求确认与细化 +2. 技术方案设计 +3. 任务分解与分配 +4. 代码开发与单元测试 +5. 集成测试与系统测试 +6. 产品评审与验收 +7. 部署与上线 + +## 4. 任务分解与工时估算 + +### 4.1 总体开发阶段 +| 阶段 | 时间范围 | 主要任务 | 参与角色 | +|------|----------|----------|----------| +| 需求分析与设计 | 第1周 | 需求细化、系统设计、数据库设计 | 产品经理、架构师、开发工程师 | +| 核心功能开发 | 第2-6周 | 用户管理、订单管理、供应商管理、运输管理、质量管理、财务管理 | 前端、后端开发工程师 | +| 第三方集成 | 第7-8周 | 支付接口、地图服务、文件存储服务集成 | 后端开发工程师 | +| 测试与优化 | 第9-10周 | 功能测试、性能测试、安全测试、Bug修复、性能优化 | 测试工程师、开发工程师 | +| 文档完善与培训 | 第11周 | 用户手册、开发文档完善、系统培训 | 产品经理、架构师、开发工程师 | +| 上线与运维 | 第12周 | 系统部署、上线、运维监控 | 架构师、开发工程师、运维人员 | + +### 4.2 详细任务分解与工时估算 + +#### 4.2.1 后端开发任务 + +| 任务ID | 任务名称 | 任务描述 | 依赖 | 工时(人日) | 负责人 | +|--------|----------|----------|------|------------|--------| +| BE-001 | 数据库模型完善 | 根据详细设计文档完善所有数据表模型 | 系统详细设计文档 | 5 | 后端开发1 | +| BE-002 | 用户管理API完善 | 完善用户CRUD、认证、权限控制功能 | BE-001 | 4 | 后端开发1 | +| BE-003 | 订单管理API开发 | 实现订单创建、查询、更新、状态流转等功能 | BE-001 | 6 | 后端开发2 | +| BE-004 | 供应商管理API开发 | 实现供应商信息管理、资质审核等功能 | BE-001 | 4 | 后端开发2 | +| BE-005 | 运输管理API开发 | 实现运输跟踪、状态上报等功能 | BE-001 | 5 | 后端开发1 | +| BE-006 | 财务管理API开发 | 实现结算、支付等功能 | BE-001 | 6 | 后端开发2 | +| BE-007 | 质量管理API开发 | 实现牛只质量检验、报告管理等功能 | BE-001 | 4 | 后端开发1 | +| BE-008 | 文件上传与管理 | 实现视频、图片、文档等文件的上传和管理 | BE-001 | 3 | 后端开发2 | +| BE-009 | 支付接口集成 | 集成第三方支付平台接口 | BE-006 | 4 | 后端开发1 | +| BE-010 | 地图服务集成 | 集成地图API,实现位置跟踪功能 | BE-005 | 3 | 后端开发2 | +| BE-011 | 数据验证与异常处理 | 完善请求数据验证和异常处理机制 | 所有API开发 | 3 | 后端开发1 | +| BE-012 | API文档生成 | 生成Swagger API文档 | 所有API开发 | 2 | 后端开发2 | +| BE-013 | 性能优化 | 系统性能调优,包括缓存策略、查询优化等 | 所有API开发 | 3 | 架构师、后端开发 | +| BE-014 | 安全加固 | 系统安全加固,包括权限控制、数据加密等 | 所有API开发 | 3 | 架构师、后端开发 | + +#### 4.2.2 前端开发任务 + +| 任务ID | 任务名称 | 任务描述 | 依赖 | 工时(人日) | 负责人 | +|--------|----------|----------|------|------------|--------| +| FE-001 | 项目结构优化 | 优化前端项目结构,完善组件化设计 | 系统详细设计文档 | 2 | 前端开发1 | +| FE-002 | 登录与用户管理模块 | 实现用户登录、注册、个人信息管理等功能 | BE-002 | 5 | 前端开发1 | +| FE-003 | 订单管理模块 | 实现订单列表、详情、创建、编辑等功能 | BE-003 | 6 | 前端开发2 | +| FE-004 | 供应商管理模块 | 实现供应商列表、详情、创建、编辑等功能 | BE-004 | 4 | 前端开发1 | +| FE-005 | 运输管理模块 | 实现运输跟踪、状态查看等功能,集成地图展示 | BE-005, BE-010 | 7 | 前端开发2 | +| FE-006 | 财务管理模块 | 实现结算列表、支付管理等功能 | BE-006 | 5 | 前端开发1 | +| FE-007 | 质量管理模块 | 实现质量检验记录、报告查看等功能 | BE-007 | 4 | 前端开发2 | +| FE-008 | 文件上传组件 | 实现文件上传、预览等功能 | BE-008 | 3 | 前端开发1 | +| FE-009 | 数据可视化 | 实现数据驾驶舱、报表等数据可视化功能 | BE-003, BE-006 | 6 | 前端开发2 | +| FE-010 | 响应式布局优化 | 优化移动端和桌面端布局,确保良好的用户体验 | 所有前端模块 | 3 | 前端开发1 | +| FE-011 | 性能优化 | 前端性能优化,包括懒加载、资源压缩等 | 所有前端模块 | 3 | 前端开发2 | +| FE-012 | 单元测试与集成测试 | 编写前端单元测试和集成测试用例 | 所有前端模块 | 4 | 测试工程师、前端开发 | + +#### 4.2.3 测试与部署任务 + +| 任务ID | 任务名称 | 任务描述 | 依赖 | 工时(人日) | 负责人 | +|--------|----------|----------|------|------------|--------| +| TEST-001 | 测试计划制定 | 制定详细的测试计划和测试用例 | 系统详细设计文档 | 2 | 测试工程师 | +| TEST-002 | 功能测试 | 对系统所有功能进行测试,发现并报告Bug | 所有开发任务 | 8 | 测试工程师 | +| TEST-003 | 性能测试 | 测试系统在高并发下的性能表现 | 所有开发任务 | 3 | 测试工程师 | +| TEST-004 | 安全测试 | 测试系统的安全性,包括权限控制、数据加密等 | 所有开发任务 | 3 | 测试工程师 | +| TEST-005 | Bug修复 | 跟踪并修复测试过程中发现的Bug | TEST-002, TEST-003, TEST-004 | 5 | 开发工程师 | +| DEPLOY-001 | 部署环境准备 | 准备生产环境服务器、数据库等 | 系统架构文档 | 2 | 运维人员 | +| DEPLOY-002 | 系统部署 | 部署前端和后端应用到生产环境 | TEST-005 | 2 | 开发工程师、运维人员 | +| DEPLOY-003 | 监控与告警配置 | 配置系统监控和告警机制 | DEPLOY-002 | 2 | 运维人员 | + +## 5. 里程碑与交付物 + +### 5.1 关键里程碑 +| 里程碑名称 | 达成标准 | 时间点 | +|------------|----------|--------| +| 需求分析完成 | 需求文档、系统设计文档、数据库设计文档评审通过 | 第1周结束 | +| 核心功能开发完成 | 用户、订单、供应商、运输、财务、质量管理功能开发完成 | 第6周结束 | +| 第三方集成完成 | 支付、地图、文件存储等第三方服务集成完成 | 第8周结束 | +| 系统测试完成 | 功能测试、性能测试、安全测试通过,Bug修复完成 | 第10周结束 | +| 文档完善与培训完成 | 用户手册、开发文档完善,系统培训完成 | 第11周结束 | +| 系统上线 | 系统正式上线运行 | 第12周结束 | + +### 5.2 主要交付物 +| 交付物名称 | 交付时间 | 说明 | +|------------|----------|------| +| 需求分析文档 | 第1周 | 详细的需求分析和用户故事 | +| 系统架构文档 | 第1周 | 系统整体架构设计 | +| 系统详细设计文档 | 第1周 | 数据库设计、API设计、核心业务流程设计 | +| 后端源代码 | 第8周 | 完整的后端API实现 | +| 前端源代码 | 第8周 | 完整的前端应用实现 | +| 测试报告 | 第10周 | 功能、性能、安全测试报告 | +| 用户操作手册 | 第11周 | 详细的用户使用指南 | +| 系统部署文档 | 第11周 | 系统部署和运维指南 | +| 上线总结报告 | 第12周 | 系统上线总结和后续优化建议 | + +## 6. 风险管理 + +### 6.1 风险识别与评估 + +| 风险ID | 风险描述 | 可能性 | 影响程度 | 应对策略 | +|--------|----------|--------|----------|----------| +| RISK-001 | 需求变更 | 高 | 中 | 建立变更控制流程,严格评估变更影响 | +| RISK-002 | 技术难点无法按时解决 | 中 | 高 | 提前识别技术难点,组织技术攻关 | +| RISK-003 | 第三方服务集成问题 | 中 | 中 | 提前调研第三方服务,预留集成时间 | +| RISK-004 | 人员变动 | 低 | 高 | 加强知识共享,建立备份机制 | +| RISK-005 | 性能问题 | 中 | 中 | 提前进行性能测试,优化系统架构 | +| RISK-006 | 安全漏洞 | 中 | 高 | 定期安全审计,及时修复漏洞 | + +### 6.2 应急计划 +- 预留10%的缓冲时间应对不可预见的问题 +- 建立快速响应机制,及时解决突发问题 +- 定期召开项目风险管理会议,评估和更新风险状态 + +## 7. 沟通与协作机制 + +### 7.1 会议制度 +- 每日站立会议:15分钟,同步进度和问题 +- 每周迭代计划会议:1小时,规划下周工作 +- 每周迭代评审会议:1小时,演示迭代成果 +- 每两周项目进度会议:1.5小时,向 stakeholders 汇报项目进度 + +### 7.2 工具与平台 +- 项目管理:Jira/禅道 +- 代码托管:Git +- 文档管理:Confluence +- 沟通协作:企业微信/钉钉 +- CI/CD:Jenkins/GitLab CI + +### 7.3 代码规范与版本控制 +- 统一代码规范,使用ESLint/Prettier等工具进行代码质量控制 +- 采用Git Flow工作流,确保代码版本管理规范 +- 定期进行代码审查,确保代码质量 + +## 8. 质量保证计划 + +### 8.1 质量目标 +- 功能测试覆盖率:100% +- 单元测试覆盖率:≥80% +- 系统可用性:99.9% +- 系统响应时间:<2秒 +- 并发用户数:支持100+用户同时在线 +- 缺陷密度:<0.5个/功能点 + +### 8.2 质量控制措施 +- 严格的代码审查流程 +- 自动化测试(单元测试、集成测试、端到端测试) +- 定期的性能测试和安全测试 +- 完善的文档管理和知识共享机制 +- 用户验收测试 + +## 9. 后续优化与维护计划 + +### 9.1 系统优化方向 +- 性能优化:持续监控和优化系统性能 +- 用户体验优化:根据用户反馈持续改进界面和交互 +- 功能扩展:根据业务需求扩展系统功能 + +### 9.2 维护计划 +- 建立运维监控体系,及时发现和解决问题 +- 定期进行系统备份和安全检查 +- 提供技术支持和问题排查服务 +- 定期更新系统,修复漏洞和优化功能 + +## 10. 预算估算 + +### 10.1 开发成本 +| 类别 | 预计成本(万元) | 说明 | +|------|---------------|------| +| 人力成本 | 60-80 | 开发团队人员工资 | +| 第三方服务 | 5-10 | 支付接口、地图服务、云存储等 | +| 硬件设施 | 3-5 | 服务器、网络设备等 | +| 软件工具 | 2-3 | 项目管理工具、协作工具等 | +| 培训与文档 | 1-2 | 用户培训、文档制作等 | +| 其他 | 2-3 | 差旅、沟通等 | +| **总计** | **73-103** | | + +### 10.2 维护成本 +| 类别 | 预计年成本(万元) | 说明 | +|------|----------------|------| +| 运维人力 | 15-20 | 运维人员工资 | +| 第三方服务 | 3-5 | 持续的第三方服务费用 | +| 硬件维护 | 1-2 | 服务器维护、升级等 | +| 系统优化 | 5-8 | 系统功能优化、性能提升等 | +| **总计** | **24-35** | | + +## 11. 附录 + +### 11.1 术语表 +- PRD: Product Requirements Document,产品需求文档 +- API: Application Programming Interface,应用程序编程接口 +- JWT: JSON Web Token,一种用于安全传输信息的标准 +- ORM: Object-Relational Mapping,对象关系映射 +- CI/CD: Continuous Integration/Continuous Deployment,持续集成/持续部署 +- RBAC: Role-Based Access Control,基于角色的访问控制 + +### 11.2 参考文档 +- 《活牛采购智能数字化系统PRD》 +- 《系统架构文档》 +- 《系统详细设计文档》 +- 《开发环境配置指南》 +- 《测试规范文档》 +- 《部署和运维文档》 \ No newline at end of file diff --git a/docs/技术实施方案.md b/docs/技术实施方案.md index 34bc2ad..3ed0fd0 100644 --- a/docs/技术实施方案.md +++ b/docs/技术实施方案.md @@ -1,5 +1,11 @@ # 活牛采购智能数字化系统 - 技术实施方案 +## 版本历史 +| 版本 | 日期 | 作者 | 说明 | +|------|------|------|------| +| v1.0 | 2024-01-20 | 技术团队 | 初版技术方案 | +| v1.1 | 2024-05-15 | 系统架构师 | 更新与系统架构和详细设计文档保持一致 | + ## 1. 技术架构 ### 1.1 系统架构 diff --git a/docs/活牛采购智能数字化系统PRD.md b/docs/活牛采购智能数字化系统PRD.md index ebd907b..d4ccfb2 100644 --- a/docs/活牛采购智能数字化系统PRD.md +++ b/docs/活牛采购智能数字化系统PRD.md @@ -4,6 +4,7 @@ | 版本 | 日期 | 作者 | 说明 | |------|------|------|------| | v1.0 | 2024-01-20 | 产品经理 | 初版PRD | +| v1.1 | 2024-05-15 | 系统架构师 | 更新与系统架构和详细设计文档保持一致 | ## 1. 项目概述 diff --git a/docs/系统架构文档.md b/docs/系统架构文档.md new file mode 100644 index 0000000..2a8aca5 --- /dev/null +++ b/docs/系统架构文档.md @@ -0,0 +1,266 @@ +# 活牛采购智能数字化系统 - 系统架构文档 + +## 版本历史 +| 版本 | 日期 | 作者 | 说明 | +|------|------|------|------| +| v1.0 | 2024-05-15 | 系统架构师 | 基于现有项目架构整理更新 | + +## 1. 整体架构 + +### 1.1 系统架构图 +```mermaid +flowchart TD + subgraph "前端层" + A[管理后台 +Vue 3 + TypeScript] --> |API调用| G + B[小程序 +Uni-app] --> |API调用| G + C[官网 +HTML5 + Bootstrap] --> |静态展示| D + end + + subgraph "后端层" + G[API Gateway +认证与路由] --> H + H[Express.js服务集群 +业务逻辑处理] --> I + end + + subgraph "数据层" + I[MySQL数据库 +业务数据存储] --> J + J[Redis缓存 +性能优化] --> K + K[文件存储 +视频与证件] --> L + end + + subgraph "辅助服务" + L[消息通知 +流程提醒] --> M + M[实时通信 +WebSocket] --> N + N[第三方服务 +支付、地图等] --> O + end +``` + +### 1.2 系统分层说明 +- **前端层**:包含管理后台、小程序和官网三部分,分别面向不同用户群体提供服务 +- **后端层**:采用Express.js作为主要框架,提供统一的API接口和业务逻辑处理 +- **数据层**:使用MySQL存储业务数据,Redis提高性能,文件存储服务管理视频和证件 +- **辅助服务**:包括消息通知、实时通信和第三方服务集成 + +## 2. 技术栈选型 + +### 2.1 核心技术栈 +| 类别 | 技术/框架 | 版本 | 用途 | 选型理由 | +|------|-----------|------|------|----------| +| 前端框架 | Vue 3 | 3.x | 管理后台开发 | 生态成熟,TypeScript支持好,性能优秀 | +| 编程语言 | TypeScript | 4.x+ | 前端开发 | 静态类型检查,提高代码质量和可维护性 | +| UI组件库 | Element Plus | 2.x | 管理后台UI | Vue 3官方推荐,组件丰富,文档完善 | +| 构建工具 | Vite | 4.x | 前端构建 | 极速开发体验,优化构建性能 | +| 状态管理 | Pinia | 2.x | 前端状态管理 | Vue 3官方推荐,API简洁,性能优异 | +| 后端框架 | Express.js | 4.x | 后端服务 | 轻量灵活,生态丰富,学习成本低 | +| 数据库 | MySQL | 5.7 | 关系型数据存储 | 成熟稳定,适合复杂业务关系存储 | +| ORM框架 | Sequelize | 6.x | 数据库访问 | 支持多种数据库,简化数据库操作 | +| 缓存 | Redis | 6.x | 性能优化 | 提升系统响应速度,减轻数据库压力 | +| 小程序框架 | Uni-app | 3.x | 跨平台小程序 | 一套代码多端运行,降低开发维护成本 | + +### 2.2 工具与中间件 +| 类别 | 工具/中间件 | 用途 | +|------|------------|------| +| API文档 | Swagger | 自动生成API文档 | +| 身份验证 | JWT | 用户身份认证 | +| 安全加固 | Helmet | 增强Express应用安全性 | +| 跨域处理 | CORS | 解决跨域请求问题 | +| 请求限流 | Express-rate-limit | 防止API滥用 | +| 日志管理 | Morgan | HTTP请求日志记录 | +| 数据验证 | Joi | API请求数据校验 | +| 环境配置 | dotenv | 环境变量管理 | + +## 3. 系统模块划分 + +### 3.1 核心业务模块 +| 模块名称 | 主要职责 | 文件位置 | 备注 | +|---------|---------|---------|------| +| 用户管理 | 用户CRUD、权限控制、认证登录 | backend/routes/users.js | 已实现基础功能 | +| 订单管理 | 订单创建、查询、更新、取消 | backend/routes/orders.js | 已实现模拟数据接口 | +| 供应商管理 | 供应商信息管理、资质审核 | backend/routes/suppliers.js | 已实现模拟数据接口 | +| 运输管理 | 运输跟踪、状态上报 | backend/routes/transport.js | 待完善 | +| 财务管理 | 结算、支付、财务数据处理 | backend/routes/finance.js | 已实现模拟数据接口 | +| 质量管理 | 牛只质量检验、报告管理 | backend/routes/quality.js | 已实现模拟数据接口 | + +### 3.2 前端模块结构 +| 模块名称 | 功能描述 | 文件位置 | +|---------|---------|---------| +| 登录模块 | 用户认证登录 | admin-system/src/views/login/ | +| 数据驾驶舱 | 系统概览、关键指标 | admin-system/src/views/dashboard/ | +| 订单管理 | 订单列表、详情、操作 | admin-system/src/views/order/ | +| 用户管理 | 用户列表、角色权限 | admin-system/src/views/user/ | +| 供应商管理 | 供应商信息维护 | admin-system/src/views/supplier/ | +| 运输管理 | 运输状态跟踪 | admin-system/src/views/transport/ | +| 财务管理 | 财务结算管理 | admin-system/src/views/finance/ | +| 质量管理 | 质量检验记录 | admin-system/src/views/quality/ | +| 系统设置 | 系统参数配置 | admin-system/src/views/settings/ | + +## 4. 数据库架构 + +### 4.1 主要数据表结构 +| 表名 | 主要职责 | 关键字段 | 备注 | +|------|---------|---------|------| +| users | 用户信息存储 | id, username, phone, user_type, password_hash | 已实现模型定义 | +| orders | 订单信息存储 | id, orderNo, buyerId, supplierId, status, totalAmount | 已在路由中定义数据结构 | +| suppliers | 供应商信息 | id, name, code, contact, phone, address, status | 已在路由中定义数据结构 | +| settlements | 结算信息 | id, orderId, totalAmount, paymentStatus, paymentDate | 已在路由中定义数据结构 | +| quality_records | 质量检测记录 | id, orderId, inspectorName, healthStatus, qualityScore | 已在路由中定义数据结构 | + +### 4.2 数据库连接配置 +```javascript +// 数据库连接配置示例 +const sequelize = new Sequelize({ + host: process.env.DB_HOST || '129.211.213.226', + port: process.env.DB_PORT || 9527, + database: process.env.DB_NAME || 'jiebandata', + username: process.env.DB_USER || 'root', + password: process.env.DB_PASSWORD || 'aiotAiot123!', + dialect: process.env.DB_DIALECT || 'mysql', + logging: process.env.NODE_ENV === 'development' ? console.log : false, + pool: { + max: 5, + min: 0, + acquire: 30000, + idle: 10000 + }, + define: { + timestamps: true, + underscored: true, + freezeTableName: true + }, + timezone: '+08:00' +}); +``` + +## 5. 系统部署架构 + +### 5.1 开发环境部署 +- **前端**:本地开发服务器,通过Vite热更新 +- **后端**:本地Express.js服务器 +- **数据库**:远程MySQL服务器 + +### 5.2 生产环境部署建议 +```mermaid +flowchart TD + subgraph "负载均衡层" + A[NGINX +负载均衡] --> B + end + + subgraph "应用层" + B[PM2集群 +Express.js实例] --> C + C[Redis缓存 +会话与数据缓存] --> D + end + + subgraph "数据层" + D[MySQL主从 +数据持久化] --> E + E[文件存储 +OSS/MinIO] --> F + end + + subgraph "监控与日志" + F[日志系统 +ELK Stack] --> G + G[监控系统 +Prometheus+Grafana] --> H + end +``` + +## 6. 接口与集成 + +### 6.1 API接口规范 +- 所有API接口统一以`/api/`开头 +- 使用RESTful风格设计 +- 统一的响应格式:`{ success: boolean, message: string, data?: any }` +- 使用JWT进行身份认证 +- 支持分页查询:`page`和`pageSize`参数 + +### 6.2 第三方服务集成 +- **支付接口**:待集成主流支付平台 +- **地图服务**:用于运输轨迹跟踪 +- **短信服务**:用于用户验证和通知 +- **文件存储**:用于视频和证件存储 + +## 7. 安全架构 + +### 7.1 身份认证与授权 +- 使用JWT进行无状态身份认证 +- 基于角色的访问控制(RBAC) +- 密码加密存储(bcrypt) + +### 7.2 数据安全 +- HTTPS加密传输 +- 敏感数据加密存储 +- SQL注入防护 +- XSS攻击防护 +- 请求限流防刷 + +### 7.3 日志与审计 +- 关键操作日志记录 +- 用户行为审计追踪 +- 异常日志监控报警 + +## 8. 性能优化 + +### 8.1 前端性能优化 +- 组件懒加载 +- 路由懒加载 +- 图片优化 +- 资源缓存策略 + +### 8.2 后端性能优化 +- Redis缓存热点数据 +- 数据库索引优化 +- 连接池管理 +- API响应压缩 + +### 8.3 数据库性能优化 +- 合理设计索引 +- 分表分库策略(未来扩展) +- 读写分离(未来扩展) + +## 9. 扩展性设计 + +### 9.1 微服务转型规划 +当前系统采用单体架构,未来可考虑向微服务转型,主要拆分方向: +- 用户服务(user-service) +- 订单服务(order-service) +- 支付服务(payment-service) +- 运输服务(transport-service) +- 文件服务(file-service) + +### 9.2 API网关规划 +未来微服务架构下,引入API网关统一管理: +- 路由转发 +- 身份认证 +- 限流熔断 +- 监控日志 + +## 10. 风险评估与应对 + +### 10.1 技术风险 +- **数据库连接失败**:实现连接重试机制,支持多数据源 +- **性能瓶颈**:引入缓存层,优化数据库查询,考虑读写分离 +- **系统可用性**:部署多实例,实现负载均衡和故障转移 + +### 10.2 业务风险 +- **数据一致性**:使用事务确保关键业务操作的数据一致性 +- **操作错误**:增加操作日志记录,支持关键操作撤销 +- **合规性**:确保系统满足行业相关法规和标准要求 + +### 10.3 安全风险 +- **数据泄露**:实施数据加密,严格的权限控制,定期安全审计 +- **DDoS攻击**:配置防火墙,实施请求限流 +- **代码漏洞**:定期代码审计,使用安全扫描工具 \ No newline at end of file diff --git a/docs/系统详细设计文档.md b/docs/系统详细设计文档.md new file mode 100644 index 0000000..2e87c7c --- /dev/null +++ b/docs/系统详细设计文档.md @@ -0,0 +1,839 @@ +# 活牛采购智能数字化系统 - 系统详细设计文档 + +## 版本历史 +| 版本 | 日期 | 作者 | 说明 | +|------|------|------|------| +| v1.0 | 2024-05-15 | 系统架构师 | 基于现有项目架构整理更新 | + +## 1. 数据库详细设计 + +### 1.1 核心数据表ER图 +```mermaid +erDiagram + USER ||--o{ ORDER : creates + USER ||--o{ ORDER : manages + USER ||--o{ ORDER : supplies + USER ||--o{ TRANSPORT_TRACK : reports + ORDER ||--o{ TRANSPORT_TRACK : has + ORDER ||--o{ QUALITY_RECORD : has + ORDER ||--o{ SETTLEMENT : has + SUPPLIER ||--o{ ORDER : provides + + USER { + BIGINT id PK + STRING uuid + STRING username + STRING password_hash + STRING phone + STRING email + STRING real_name + STRING avatar_url + ENUM user_type + ENUM status + DATE last_login_at + INT login_count + } + + ORDER { + BIGINT id PK + STRING orderNo + BIGINT buyerId FK + BIGINT supplierId FK + BIGINT traderId FK + STRING cattleBreed + INT cattleCount + DECIMAL expectedWeight + DECIMAL actualWeight + DECIMAL unitPrice + DECIMAL totalAmount + DECIMAL paidAmount + DECIMAL remainingAmount + ENUM status + STRING deliveryAddress + DATE expectedDeliveryDate + DATE actualDeliveryDate + STRING notes + } + + SUPPLIER { + BIGINT id PK + STRING name + STRING code + STRING contact + STRING phone + STRING address + STRING businessLicense + STRING qualificationLevel + JSON certifications + JSON cattleTypes + INT capacity + DECIMAL rating + DATE cooperationStartDate + ENUM status + STRING region + } + + TRANSPORT_TRACK { + BIGINT id PK + BIGINT orderId FK + BIGINT driverId FK + DECIMAL latitude + DECIMAL longitude + DECIMAL speed + DECIMAL direction + STRING cattle_status + STRING video_url + DATE timestamp + } + + QUALITY_RECORD { + BIGINT id PK + BIGINT orderId FK + STRING inspectionCode + STRING inspectorName + DATE inspectionDate + STRING inspectionLocation + INT cattleCount + INT samplingCount + STRING inspectionType + STRING healthStatus + STRING quarantineCertificate + JSON vaccineRecords + JSON diseaseTests + JSON weightCheck + STRING qualityGrade + INT qualityScore + JSON issues + JSON recommendations + JSON photos + ENUM status + } + + SETTLEMENT { + BIGINT id PK + BIGINT orderId FK + STRING settlementCode + DECIMAL prepaymentAmount + DECIMAL totalAmount + DECIMAL finalAmount + ENUM paymentStatus + DATE paymentDate + STRING invoiceNumber + ENUM invoiceStatus + DECIMAL taxAmount + DECIMAL actualPayment + STRING bankAccount + STRING bankName + } +``` + +### 1.2 核心表结构定义 + +#### 1.2.1 用户表 (users) +```javascript +const User = sequelize.define('User', { + id: { + type: DataTypes.BIGINT, + primaryKey: true, + autoIncrement: true + }, + uuid: { + type: DataTypes.STRING(36), + allowNull: false, + unique: true, + defaultValue: DataTypes.UUIDV4 + }, + username: { + type: DataTypes.STRING(50), + allowNull: false, + unique: true, + validate: { + len: [2, 50] + } + }, + password_hash: { + type: DataTypes.STRING(255), + allowNull: false + }, + phone: { + type: DataTypes.STRING(20), + allowNull: false, + unique: true, + validate: { + is: /^1[3-9]\d{9}$/ + } + }, + email: { + type: DataTypes.STRING(100), + validate: { + isEmail: true + } + }, + real_name: DataTypes.STRING(50), + avatar_url: DataTypes.STRING(255), + user_type: { + type: DataTypes.ENUM('client', 'supplier', 'driver', 'staff', 'admin'), + allowNull: false, + defaultValue: 'client' + }, + status: { + type: DataTypes.ENUM('active', 'inactive', 'locked'), + defaultValue: 'active' + }, + last_login_at: DataTypes.DATE, + login_count: { + type: DataTypes.INTEGER, + defaultValue: 0 + } +}, { + tableName: 'users', + timestamps: true, + paranoid: true, // 软删除 + indexes: [ + { fields: ['phone'] }, + { fields: ['user_type'] }, + { fields: ['status'] }, + { fields: ['username'] } + ] +}); +``` + +#### 1.2.2 订单表 (orders) +```javascript +const Order = sequelize.define('Order', { + id: { + type: DataTypes.BIGINT, + primaryKey: true, + autoIncrement: true + }, + orderNo: { + type: DataTypes.STRING(50), + allowNull: false, + unique: true + }, + buyerId: { + type: DataTypes.BIGINT, + allowNull: false + }, + buyerName: { + type: DataTypes.STRING(100), + allowNull: false + }, + supplierId: { + type: DataTypes.BIGINT, + allowNull: false + }, + supplierName: { + type: DataTypes.STRING(100), + allowNull: false + }, + traderId: DataTypes.BIGINT, + traderName: DataTypes.STRING(100), + cattleBreed: { + type: DataTypes.STRING(50), + allowNull: false + }, + cattleCount: { + type: DataTypes.INTEGER, + allowNull: false + }, + expectedWeight: { + type: DataTypes.DECIMAL(10, 2), + allowNull: false + }, + actualWeight: DataTypes.DECIMAL(10, 2), + unitPrice: { + type: DataTypes.DECIMAL(10, 2), + allowNull: false + }, + totalAmount: { + type: DataTypes.DECIMAL(15, 2), + allowNull: false + }, + paidAmount: { + type: DataTypes.DECIMAL(15, 2), + defaultValue: 0 + }, + remainingAmount: { + type: DataTypes.DECIMAL(15, 2), + defaultValue: 0 + }, + status: { + type: DataTypes.ENUM('pending', 'confirmed', 'preparing', 'shipping', 'delivered', 'accepted', 'completed', 'cancelled', 'refunded'), + defaultValue: 'pending' + }, + deliveryAddress: { + type: DataTypes.STRING(200), + allowNull: false + }, + expectedDeliveryDate: { + type: DataTypes.DATE, + allowNull: false + }, + actualDeliveryDate: DataTypes.DATE, + notes: DataTypes.TEXT +}, { + tableName: 'orders', + timestamps: true, + indexes: [ + { fields: ['orderNo'] }, + { fields: ['buyerId'] }, + { fields: ['supplierId'] }, + { fields: ['status'] }, + { fields: ['createdAt'] } + ] +}); +``` + +#### 1.2.3 供应商表 (suppliers) +```javascript +const Supplier = sequelize.define('Supplier', { + id: { + type: DataTypes.BIGINT, + primaryKey: true, + autoIncrement: true + }, + name: { + type: DataTypes.STRING(100), + allowNull: false + }, + code: { + type: DataTypes.STRING(20), + allowNull: false, + unique: true + }, + contact: { + type: DataTypes.STRING(50), + allowNull: false + }, + phone: { + type: DataTypes.STRING(20), + allowNull: false, + unique: true + }, + address: { + type: DataTypes.STRING(200), + allowNull: false + }, + businessLicense: DataTypes.STRING(255), + qualificationLevel: { + type: DataTypes.STRING(10), + allowNull: false + }, + certifications: DataTypes.JSON, + cattleTypes: DataTypes.JSON, + capacity: DataTypes.INTEGER, + rating: DataTypes.DECIMAL(3, 2), + cooperationStartDate: DataTypes.DATE, + status: { + type: DataTypes.ENUM('active', 'inactive', 'suspended'), + defaultValue: 'active' + }, + region: { + type: DataTypes.STRING(20), + allowNull: false + } +}, { + tableName: 'suppliers', + timestamps: true +}); +``` + +#### 1.2.4 运输跟踪表 (transport_tracks) +```javascript +const TransportTrack = sequelize.define('TransportTrack', { + id: { + type: DataTypes.BIGINT, + primaryKey: true, + autoIncrement: true + }, + orderId: { + type: DataTypes.BIGINT, + allowNull: false + }, + driverId: { + type: DataTypes.BIGINT, + allowNull: false + }, + latitude: DataTypes.DECIMAL(10, 8), + longitude: DataTypes.DECIMAL(11, 8), + speed: DataTypes.DECIMAL(5, 2), + direction: DataTypes.DECIMAL(5, 2), + cattle_status: DataTypes.STRING(50), + video_url: DataTypes.STRING(255) +}, { + tableName: 'transport_tracks', + timestamps: true +}); +``` + +## 2. API详细设计 + +### 2.1 用户认证与管理API + +#### 2.1.1 登录接口 +- **路径**: `/api/auth/login` +- **方法**: POST +- **请求体**: + ```json + { + "username": "string", + "password": "string" + } + ``` +- **响应体**: + ```json + { + "success": true, + "message": "登录成功", + "data": { + "token": "string", + "userInfo": { + "id": 1, + "username": "string", + "real_name": "string", + "user_type": "string", + "avatar_url": "string" + } + } + } + ``` +- **错误码**: 401(认证失败), 403(账号锁定) + +#### 2.1.2 获取用户列表 +- **路径**: `/api/users` +- **方法**: GET +- **请求参数**: + - page: 页码 + - pageSize: 每页条数 + - keyword: 搜索关键词 + - userType: 用户类型 + - status: 用户状态 +- **响应体**: + ```json + { + "success": true, + "message": "查询成功", + "data": { + "list": [], + "total": 0, + "page": 1, + "pageSize": 10 + } + } + ``` +- **权限**: admin/staff + +### 2.2 订单管理API + +#### 2.2.1 创建订单 +- **路径**: `/api/orders` +- **方法**: POST +- **请求体**: + ```json + { + "buyerId": 1, + "supplierId": 2, + "traderId": 3, + "cattleBreed": "西门塔尔", + "cattleCount": 50, + "expectedWeight": 25000, + "unitPrice": 28.5, + "deliveryAddress": "山东省济南市某养殖场", + "expectedDeliveryDate": "2024-01-15", + "notes": "优质西门塔尔牛" + } + ``` +- **响应体**: + ```json + { + "success": true, + "message": "创建成功", + "data": {} + } + ``` +- **权限**: client/staff/admin + +#### 2.2.2 获取订单列表 +- **路径**: `/api/orders` +- **方法**: GET +- **请求参数**: + - page: 页码 + - pageSize: 每页条数 + - orderNo: 订单编号 + - buyerId: 采购方ID + - supplierId: 供应商ID + - status: 订单状态 + - startDate: 开始日期 + - endDate: 结束日期 +- **响应体**: + ```json + { + "success": true, + "message": "查询成功", + "data": { + "list": [], + "total": 0, + "page": 1, + "pageSize": 10 + } + } + ``` +- **权限**: 所有登录用户(根据用户类型过滤数据) + +#### 2.2.3 更新订单状态 +- **路径**: `/api/orders/{id}/status` +- **方法**: PUT +- **请求体**: + ```json + { + "status": "confirmed", + "notes": "确认订单" + } + ``` +- **响应体**: + ```json + { + "success": true, + "message": "更新成功", + "data": {} + } + ``` +- **权限**: 根据订单状态和用户类型控制 + +### 2.3 供应商管理API + +#### 2.3.1 创建供应商 +- **路径**: `/api/suppliers` +- **方法**: POST +- **请求体**: + ```json + { + "name": "山东优质牲畜合作社", + "code": "SUP001", + "contact": "李经理", + "phone": "15888888888", + "address": "山东省济南市历城区牲畜养殖基地", + "qualificationLevel": "A", + "cattleTypes": ["肉牛", "奶牛"], + "capacity": 5000, + "region": "east" + } + ``` +- **响应体**: + ```json + { + "success": true, + "message": "创建成功", + "data": {} + } + ``` +- **权限**: staff/admin + +#### 2.3.2 获取供应商列表 +- **路径**: `/api/suppliers` +- **方法**: GET +- **请求参数**: + - page: 页码 + - pageSize: 每页条数 + - keyword: 搜索关键词 + - region: 地区 + - qualificationLevel: 资质等级 + - status: 状态 +- **响应体**: + ```json + { + "success": true, + "message": "查询成功", + "data": { + "list": [], + "total": 0, + "page": 1, + "pageSize": 10 + } + } + ``` +- **权限**: staff/admin/client + +### 2.4 财务管理API + +#### 2.4.1 创建结算单 +- **路径**: `/api/finance/settlements` +- **方法**: POST +- **请求体**: + ```json + { + "orderId": 1, + "cattleCount": 50, + "unitPrice": 25000, + "paymentMethod": "bank_transfer", + "settlementDate": "2024-01-20", + "invoiceNumber": "INV001" + } + ``` +- **响应体**: + ```json + { + "success": true, + "message": "创建成功", + "data": {} + } + ``` +- **权限**: staff/admin + +#### 2.4.2 获取结算列表 +- **路径**: `/api/finance/settlements` +- **方法**: GET +- **请求参数**: + - page: 页码 + - pageSize: 每页条数 + - keyword: 搜索关键词 + - paymentStatus: 支付状态 + - startDate: 开始日期 + - endDate: 结束日期 +- **响应体**: + ```json + { + "success": true, + "message": "查询成功", + "data": { + "list": [], + "total": 0, + "page": 1, + "pageSize": 10 + } + } + ``` +- **权限**: staff/admin/finance + +## 3. 核心业务逻辑流程 + +### 3.1 订单创建与处理流程 +```mermaid +sequenceDiagram + participant Buyer as 采购人 + participant System as 系统 + participant Trader as 贸易商 + participant Supplier as 供应商 + participant Driver as 司机 + + Buyer->>System: 创建采购订单 + System-->>Buyer: 返回订单号 + System->>Trader: 通知订单待确认 + Trader->>System: 确认/拒绝订单 + System->>Supplier: 转发订单给供应商 + Supplier->>System: 接单/拒单 + System->>Driver: 分配运输任务 + Driver->>System: 上报运输状态 + System->>Buyer: 实时更新订单状态 + Driver->>System: 确认送达 + Buyer->>System: 验收确认 + System->>System: 自动计算结算金额 + System->>Buyer: 生成结算单 + Buyer->>System: 支付尾款 + System->>Trader: 结算款项 + System->>Supplier: 结算款项 + System-->>Buyer: 订单完成通知 +``` + +### 3.2 牛只质量核验流程 +```mermaid +flowchart TD + A[开始 +供应商提交牛只信息] --> B{系统检查 +检疫证明} + B -- 合格 --> C[上传消毒证明 +和空车过磅视频] + B -- 不合格 --> Z[结束 +驳回申请] + C --> D{驻场兽医 +在线确认} + D -- 确认 --> E[系统记录 +核验信息] + D -- 驳回 --> Z + E --> F[进入装车环节] + F --> G[结束 +核验通过] +``` + +### 3.3 运输状态跟踪流程 +```mermaid +sequenceDiagram + participant DriverApp as 司机APP + participant System as 系统 + participant Backend as 管理后台 + participant BuyerApp as 采购方APP + + DriverApp->>System: 定时上报位置 + DriverApp->>System: 上传视频状态 + System->>Backend: 实时更新运输轨迹 + System->>BuyerApp: 推送运输状态 + Backend->>System: 查询运输详情 + BuyerApp->>System: 查询运输详情 + + alt 异常情况 + DriverApp->>System: 上报异常 + System->>Backend: 推送异常警报 + System->>BuyerApp: 推送异常警报 + Backend->>System: 处理异常 + end +``` + +## 4. 前端组件设计 + +### 4.1 管理后台组件结构 +``` +├── layouts/ # 布局组件 +│ └── index.vue # 主布局 +├── views/ # 页面组件 +│ ├── dashboard/ # 数据驾驶舱 +│ ├── login/ # 登录页面 +│ ├── order/ # 订单管理 +│ ├── user/ # 用户管理 +│ ├── supplier/ # 供应商管理 +│ ├── transport/ # 运输管理 +│ ├── finance/ # 财务管理 +│ ├── quality/ # 质量管理 +│ └── settings/ # 系统设置 +├── components/ # 公共组件 +│ ├── common/ # 通用组件 +│ └── business/ # 业务组件 +├── api/ # API调用 +├── stores/ # 状态管理 +└── utils/ # 工具函数 +``` + +### 4.2 核心组件设计 + +#### 4.2.1 订单管理组件 +- **功能**: 订单列表展示、筛选、排序、详情查看、状态更新 +- **关键属性**: + - orderList: 订单数据列表 + - loading: 加载状态 + - searchParams: 搜索参数 + - pagination: 分页信息 +- **关键方法**: + - fetchOrders(): 获取订单列表 + - handleStatusChange(): 处理订单状态变更 + - handleSearch(): 处理搜索 + - handlePagination(): 处理分页 + +#### 4.2.2 地图跟踪组件 +- **功能**: 实时展示运输轨迹、车辆位置、牛只状态 +- **关键属性**: + - orderId: 订单ID + - trackPoints: 轨迹点数据 + - currentLocation: 当前位置 + - cattleStatus: 牛只状态 +- **关键方法**: + - initMap(): 初始化地图 + - updateTrack(): 更新轨迹 + - updateStatus(): 更新状态 + - startTracking(): 开始跟踪 + - stopTracking(): 停止跟踪 + +## 5. 系统配置与部署 + +### 5.1 环境配置 + +#### 5.1.1 开发环境配置 (.env.development) +``` +NODE_ENV=development +PORT=3000 +DB_HOST=129.211.213.226 +DB_PORT=9527 +DB_NAME=jiebandata +DB_USER=root +DB_PASSWORD=aiotAiot123! +DB_DIALECT=mysql +JWT_SECRET=your_jwt_secret +``` + +#### 5.1.2 生产环境配置 (.env.production) +``` +NODE_ENV=production +PORT=80 +DB_HOST=129.211.213.226 +DB_PORT=9527 +DB_NAME=jiebandata +DB_USER=root +DB_PASSWORD=aiotAiot123! +DB_DIALECT=mysql +JWT_SECRET=your_production_jwt_secret +``` + +### 5.2 部署步骤 + +#### 5.2.1 后端部署 +1. 安装Node.js环境 +2. 克隆代码仓库 +3. 安装依赖: `npm install` +4. 配置环境变量 +5. 启动服务: `npm start` (推荐使用PM2管理) + +#### 5.2.2 前端部署 +1. 安装Node.js环境 +2. 克隆代码仓库 +3. 安装依赖: `npm install` +4. 构建项目: `npm run build` +5. 部署静态文件到Web服务器(Nginx等) + +### 5.3 监控与维护 +- **日志监控**: 使用日志收集工具收集和分析系统日志 +- **性能监控**: 监控系统响应时间、数据库查询性能等指标 +- **安全审计**: 定期检查系统安全漏洞,更新依赖包 +- **数据备份**: 定期备份数据库,确保数据安全 + +## 6. 测试策略 + +### 6.1 单元测试 +- 使用Jest框架进行后端API单元测试 +- 重点测试业务逻辑和数据验证部分 +- 覆盖率目标: ≥80% + +### 6.2 集成测试 +- 测试API接口之间的交互 +- 测试前后端集成 +- 测试数据库事务处理 + +### 6.3 端到端测试 +- 使用Cypress或Puppeteer进行UI自动化测试 +- 模拟用户真实操作流程 +- 重点测试核心业务流程 + +### 6.4 性能测试 +- 使用压测工具测试系统并发处理能力 +- 测试大数据量下的系统响应性能 +- 确保满足性能要求: 响应时间<2秒,支持100+并发用户 + +## 7. 文档与培训 + +### 7.1 开发文档 +- 代码注释规范 +- API文档(Swagger) +- 数据库设计文档 + +### 7.2 用户文档 +- 操作手册 +- 常见问题解答 +- 视频教程 + +### 7.3 培训计划 +- 管理员培训 +- 操作人员培训 +- 技术支持人员培训 + +## 8. 扩展性与未来规划 + +### 8.1 系统扩展性设计 +- 模块化设计,便于功能扩展 +- API标准化,便于集成第三方系统 +- 数据库分库分表策略预留 +- 微服务架构转型路径 + +### 8.2 未来功能规划 +- 数据分析与报表功能增强 +- AI辅助决策系统 +- 区块链追溯系统集成 +- 物联网设备接入 +- 国际业务支持与多语言功能 \ No newline at end of file