refactor(backend): 更新数据库配置并迁移至MySQL,优化文档和技术栈描述

This commit is contained in:
ylweng
2025-09-01 01:08:04 +08:00
parent e767d1ab27
commit 60333f4a67
15 changed files with 15062 additions and 0 deletions

375
API_DOCS.md Normal file
View File

@@ -0,0 +1,375 @@
# 📚 API 接口文档
## 📋 文档说明
本文档详细描述了杰邦科项目的所有API接口包括请求参数、响应格式和错误代码。
## 🔐 认证方式
### JWT Token 认证
所有需要认证的API必须在请求头中携带Token
```
Authorization: Bearer <your_jwt_token>
```
### Token 获取
通过登录接口获取TokenToken有效期为7天。
## 👥 用户模块
### 用户注册
**Endpoint:** `POST /api/v1/users/register`
**请求参数:**
```json
{
"username": "string, required, 3-20字符",
"password": "string, required, 6-20字符",
"email": "string, optional, 邮箱格式",
"phone": "string, optional, 手机号格式"
}
```
**响应示例:**
```json
{
"code": 200,
"message": "注册成功",
"data": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"createdAt": "2024-01-01T00:00:00.000Z"
}
}
```
**错误代码:**
- `400`: 参数验证失败
- `409`: 用户名已存在
- `500`: 服务器内部错误
### 用户登录
**Endpoint:** `POST /api/v1/users/login`
**请求参数:**
```json
{
"username": "string, required",
"password": "string, required"
}
```
**响应示例:**
```json
{
"code": 200,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"username": "testuser",
"email": "test@example.com"
}
}
}
```
**错误代码:**
- `400`: 参数验证失败
- `401`: 用户名或密码错误
- `500`: 服务器内部错误
### 获取用户信息
**Endpoint:** `GET /api/v1/users/profile`
**请求头:**
```
Authorization: Bearer <token>
```
**响应示例:**
```json
{
"code": 200,
"message": "获取成功",
"data": {
"id": 1,
"username": "testuser",
"email": "test@example.com",
"phone": "13800138000",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
}
```
**错误代码:**
- `401`: 未授权访问
- `404`: 用户不存在
- `500`: 服务器内部错误
## 🛒 订单模块
### 创建订单
**Endpoint:** `POST /api/v1/orders`
**请求头:**
```
Authorization: Bearer <token>
```
**请求参数:**
```json
{
"items": [
{
"productId": 1,
"quantity": 2,
"price": 100.00
}
],
"shippingAddress": {
"recipient": "张三",
"phone": "13800138000",
"address": "北京市朝阳区xxx路xxx号"
},
"remark": "string, optional"
}
```
**响应示例:**
```json
{
"code": 200,
"message": "订单创建成功",
"data": {
"id": 1001,
"orderNo": "ORDER202401010001",
"totalAmount": 200.00,
"status": "pending",
"createdAt": "2024-01-01T00:00:00.000Z"
}
}
```
### 查询订单列表
**Endpoint:** `GET /api/v1/orders`
**请求头:**
```
Authorization: Bearer <token>
```
**查询参数:**
```
?page=1&limit=10&status=pending
```
| 参数 | 类型 | 说明 |
|------|------|------|
| page | number | 页码默认1 |
| limit | number | 每页数量默认10 |
| status | string | 订单状态过滤 |
**响应示例:**
```json
{
"code": 200,
"message": "获取成功",
"data": {
"items": [
{
"id": 1001,
"orderNo": "ORDER202401010001",
"totalAmount": 200.00,
"status": "pending",
"createdAt": "2024-01-01T00:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 100,
"pages": 10
}
}
}
```
## 📦 商品模块
### 获取商品列表
**Endpoint:** `GET /api/v1/products`
**查询参数:**
```
?page=1&limit=10&category=electronics&sort=price_desc
```
| 参数 | 类型 | 说明 |
|------|------|------|
| page | number | 页码默认1 |
| limit | number | 每页数量默认10 |
| category | string | 商品分类过滤 |
| sort | string | 排序方式 |
**响应示例:**
```json
{
"code": 200,
"message": "获取成功",
"data": {
"items": [
{
"id": 1,
"name": "iPhone 15",
"price": 5999.00,
"originalPrice": 6999.00,
"image": "/images/iphone15.jpg",
"category": "electronics",
"stock": 100,
"description": "最新款iPhone手机"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 1000,
"pages": 100
}
}
}
```
### 获取商品详情
**Endpoint:** `GET /api/v1/products/:id`
**路径参数:**
- `id`: 商品ID
**响应示例:**
```json
{
"code": 200,
"message": "获取成功",
"data": {
"id": 1,
"name": "iPhone 15",
"price": 5999.00,
"originalPrice": 6999.00,
"images": [
"/images/iphone15-1.jpg",
"/images/iphone15-2.jpg"
],
"category": "electronics",
"brand": "Apple",
"stock": 100,
"description": "最新款iPhone手机",
"specifications": {
"color": "黑色",
"storage": "256GB",
"screen": "6.1英寸"
},
"reviews": {
"averageRating": 4.8,
"totalReviews": 150
}
}
}
```
## 📊 数据字典
### 订单状态
| 状态值 | 描述 |
|--------|------|
| pending | 待支付 |
| paid | 已支付 |
| shipped | 已发货 |
| completed | 已完成 |
| cancelled | 已取消 |
### 商品分类
| 分类值 | 描述 |
|--------|------|
| electronics | 电子产品 |
| clothing | 服装服饰 |
| books | 图书文具 |
| home | 家居生活 |
| sports | 运动户外 |
### 错误代码
| 代码 | 描述 |
|------|------|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未授权访问 |
| 403 | 禁止访问 |
| 404 | 资源不存在 |
| 409 | 资源冲突 |
| 500 | 服务器内部错误 |
| 503 | 服务不可用 |
## 🔗 API 版本控制
当前API版本为v1所有接口前缀为`/api/v1/`
版本更新策略:
- 向后兼容的修改直接更新
- 不兼容的修改创建新版本v2
- 旧版本API保持维护至少6个月
## 📡 接口限流
### 限流策略
- 匿名用户: 60请求/分钟
- 认证用户: 120请求/分钟
- VIP用户: 300请求/分钟
### 限流响应
当超过限流阈值时返回:
```json
{
"code": 429,
"message": "请求过于频繁,请稍后再试",
"retryAfter": 60
}
```
## 🧪 接口测试
### 使用curl测试
```bash
# 用户登录
curl -X POST http://localhost:3000/api/v1/users/login \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"password123"}'
# 获取用户信息
curl -X GET http://localhost:3000/api/v1/users/profile \
-H "Authorization: Bearer <token>"
```
### 使用Postman测试
1. 导入Postman集合文件
2. 设置环境变量base_url, token等
3. 运行测试用例
## 📝 更新日志
### v1.0.0 (2024-01-01)
- 用户注册登录接口
- 订单管理接口
- 商品管理接口
- 基础认证系统
---
*最后更新: 2024年* 📅

264
architecture.md Normal file
View File

@@ -0,0 +1,264 @@
# 🏗️ 系统架构文档
## 📋 项目概述
杰邦科项目是一个综合性的管理系统,包含后台管理、微信小程序和官网三个主要模块。
## 🎯 技术栈
### 后端技术栈
- **运行时**: Node.js + Express.js
- **数据库**: MySQL 8.0
- **ORM**: Sequelize
- **认证**: JWT + bcrypt
- **缓存**: Redis (可选)
- **消息队列**: RabbitMQ (可选)
### 前端技术栈
- **后台管理系统**: Vue 3 + Element Plus
- **微信小程序**: 原生小程序 + Vant Weapp
- **官方网站**: Vue 3 + Vue Router
### 开发工具
- **包管理**: npm
- **容器化**: Docker + Docker Compose
- **代码质量**: ESLint + Prettier
- **测试**: Jest + Supertest
## 🏢 系统架构
```mermaid
graph TB
subgraph "前端应用"
A[后台管理系统]
B[微信小程序]
C[官方网站]
end
subgraph "后端服务"
D[API Gateway]
E[用户服务]
F[业务服务]
G[文件服务]
end
subgraph "数据层"
H[MySQL]
I[Redis]
J[MinIO]
end
A --> D
B --> D
C --> D
D --> E
D --> F
D --> G
E --> H
F --> H
G --> J
E --> I
```
## 🗄️ 数据库设计
### 核心表结构
```mermaid
erDiagram
users ||--o{ orders : places
users ||--o{ addresses : has
users {
bigint id PK
varchar username
varchar password_hash
varchar email
varchar phone
datetime created_at
datetime updated_at
}
orders ||--o{ order_items : contains
orders {
bigint id PK
bigint user_id FK
decimal total_amount
varchar status
datetime created_at
}
products ||--o{ order_items : included_in
products {
bigint id PK
varchar name
decimal price
text description
}
```
## 🌐 环境配置
### 开发环境 (Development)
```env
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=rootpassword
DB_DATABASE=jiebanke_dev
NODE_ENV=development
```
### 测试环境 (Test)
```env
DB_HOST=192.168.0.240
DB_PORT=3306
DB_USER=root
DB_PASSWORD=aiotAiot123!
DB_DATABASE=jiebandata_test
NODE_ENV=test
```
### 生产环境 (Production)
```env
DB_HOST=129.211.213.226
DB_PORT=9527
DB_USER=root
DB_PASSWORD=Aiot123
DB_DATABASE=jiebandata
NODE_ENV=production
```
## 🔌 API 设计
### 用户模块 API
| 方法 | 路径 | 描述 | 认证 |
|------|------|------|------|
| POST | `/api/v1/users/register` | 用户注册 | 否 |
| POST | `/api/v1/users/login` | 用户登录 | 否 |
| GET | `/api/v1/users/profile` | 获取用户信息 | JWT |
| PUT | `/api/v1/users/profile` | 更新用户信息 | JWT |
### 示例请求
```javascript
// 用户登录
POST /api/v1/users/login
Content-Type: application/json
{
"username": "testuser",
"password": "password123"
}
```
## 🚀 部署架构
### 开发部署
```mermaid
graph LR
A[本地开发机] --> B[Docker Compose]
B --> C[MySQL容器]
B --> D[Node.js应用]
B --> E[Redis容器]
```
### 生产部署
```mermaid
graph TB
subgraph "云服务器"
A[Nginx]
B[Node.js集群]
C[MySQL主从]
D[Redis哨兵]
end
A --> B
B --> C
B --> D
```
## 📊 监控与日志
- **应用监控**: PM2 + Keymetrics
- **日志管理**: Winston + ELK Stack
- **性能监控**: New Relic / Datadog
- **错误追踪**: Sentry
## 🔒 安全架构
### 认证授权
- JWT Token 认证
- RBAC (基于角色的访问控制)
- API 速率限制
### 数据安全
- HTTPS 加密传输
- 密码加盐哈希存储
- SQL 注入防护
- XSS 攻击防护
### 网络安全
- 防火墙规则
- IP 白名单
- DDoS 防护
## 📈 性能优化
### 数据库优化
- 索引优化
- 查询缓存
- 读写分离
### 应用优化
- 响应压缩
- 静态资源CDN
- 内存缓存
### 前端优化
- 代码分割
- 懒加载
- 图片优化
## 🛠️ 开发规范
### 代码规范
- ESLint + Prettier 统一代码风格
- Git Commit 消息规范
- 代码审查流程
### 分支策略
- Git Flow 工作流
- 功能分支开发
- 发布分支管理
### 测试策略
- 单元测试覆盖核心逻辑
- 集成测试API接口
- E2E测试用户流程
## 📝 文档体系
1. **ARCHITECTURE.md** - 系统架构文档 (当前文件)
2. **README.md** - 项目说明文档
3. **API_DOCS.md** - API接口文档
4. **DEPLOYMENT.md** - 部署指南
5. **DEVELOPMENT.md** - 开发指南
## 🎯 后续规划
### 短期目标
- [ ] 完善用户管理系统
- [ ] 实现订单业务流程
- [ ] 部署测试环境
### 中期目标
- [ ] 微服务架构改造
- [ ] 容器化部署
- [ ] 自动化测试覆盖
### 长期目标
- [ ] 大数据分析平台
- [ ] AI智能推荐
- [ ] 多语言国际化
---
*最后更新: 2024年* 📅

View File

@@ -0,0 +1,257 @@
# 结伴客后端开发完善指南
## 📋 完善内容概述
本次后端开发完善主要包含以下内容:
### 1. 环境配置优化
- ✅ 更新环境配置文件 (`config/env.js`)移除MongoDB配置完善MySQL配置
- ✅ 更新环境变量示例文件 (`.env.example`)添加MySQL相关配置
- ✅ 数据库配置文件 (`src/config/database.js`) 现在使用环境配置而非硬编码
### 2. 测试数据支持
- ✅ 创建测试数据初始化脚本 (`scripts/init-test-data.js`)
- ✅ 提供标准测试账号(管理员、运营、普通用户、商家用户)
- ✅ 支持密码加密存储bcrypt
### 3. 自动化测试脚本
- ✅ 创建API端点测试脚本 (`scripts/test-api-endpoints.js`)
- ✅ 创建数据库连接测试脚本 (`scripts/test-database-connection.js`)
- ✅ 支持完整的测试用例和结果统计
### 4. 开发工具链完善
- ✅ 更新package.json脚本命令
- ✅ 提供一键测试和数据初始化功能
## 🚀 快速开始
### 环境准备
```bash
# 复制环境配置文件
cp .env.example .env
# 安装依赖
npm install
```
### 数据库配置
编辑 `.env` 文件配置MySQL数据库连接
```env
# 数据库配置
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=your-mysql-password
DB_NAME=jiebandata
# 连接池配置
DB_CONNECTION_LIMIT=10
DB_CHARSET=utf8mb4
DB_TIMEZONE=+08:00
```
### 开发命令
```bash
# 启动开发服务器
npm run dev
# 测试数据库连接
npm run test-db
# 初始化测试数据
npm run init-test-data
# 测试API端点
npm run test-api
# 运行单元测试
npm test
# 代码检查
npm run lint
```
## 📊 测试账号
初始化后会创建以下测试账号:
| 角色 | 用户名 | 密码 | 描述 |
|------|--------|------|------|
| 超级管理员 | admin | admin123 | 系统最高权限 |
| 运营经理 | manager | manager123 | 日常运营管理 |
| 普通用户 | user1 | user123 | 旅行爱好者 |
| 商家用户 | merchant1 | merchant123 | 农家乐老板 |
## 🔧 API测试
API测试脚本会自动测试以下接口
### 管理员接口
- ✅ POST `/api/v1/admin/login` - 管理员登录
- ✅ GET `/api/v1/admin/profile` - 获取管理员信息
- ✅ GET `/api/v1/admin/list` - 获取管理员列表
### 用户接口
- ✅ POST `/api/v1/auth/login` - 用户登录
- ✅ GET `/api/v1/users/profile` - 获取用户信息
### 系统接口
- ✅ GET `/health` - 健康检查
- ✅ GET `/system-stats` - 系统统计
## 🗄️ 数据库配置
### 开发环境
```javascript
{
host: '192.168.0.240',
port: 3306,
user: 'root',
password: 'aiotAiot123!',
database: 'jiebandata',
connectionLimit: 10
}
```
### 测试环境
```javascript
{
host: '192.168.0.240',
port: 3306,
user: 'root',
password: 'aiotAiot123!',
database: 'jiebandata_test',
connectionLimit: 5
}
```
### 生产环境
```javascript
{
host: '129.211.213.226',
port: 9527,
user: 'root',
password: 'Aiot123',
database: 'jiebandata',
connectionLimit: 20
}
```
## ⚡ 生产环境连接说明
### 直接连接生产数据库
当前配置已设置为直接连接生产环境MySQL服务器
- **服务器地址**: 129.211.213.226
- **端口**: 9527
- **用户名**: root
- **密码**: Aiot123
- **数据库**: jiebandata
### 注意事项
1. **谨慎操作**: 直接连接生产数据库,所有操作都会影响真实数据
2. **备份优先**: 在执行任何修改操作前,建议先备份数据
3. **权限控制**: 确保只有授权人员可以访问生产环境
4. **监控日志**: 密切监控数据库操作日志,及时发现异常
5. **连接限制**: 生产环境连接数限制为20避免过度消耗资源
### 安全建议
- 使用VPN连接生产环境
- 启用SSL加密连接
- 定期更换密码
- 实施IP白名单限制
- 启用数据库审计功能
### 连接问题排查
如果遇到连接问题,请检查:
1. **密码验证**: 确认生产服务器MySQL的root密码是否为'Aiot123'
2. **权限配置**: 检查MySQL用户权限设置确保允许从当前IP连接
3. **防火墙**: 确认服务器防火墙已开放9527端口
4. **网络连通性**: 使用telnet或ping测试网络连接
### 当前连接状态
- ❌ 生产服务器(129.211.213.226:9527): 权限被拒绝(ER_ACCESS_DENIED_ERROR)
- ❌ 开发服务器(192.168.0.240:3306): 连接超时(ETIMEDOUT)
### 本地开发解决方案
推荐使用Docker本地MySQL进行开发
1. **启动本地MySQL容器**
```bash
cd /Users/ainongkeji/code/vue/jiebanke/backend
docker-compose up -d mysql
```
2. **配置本地环境变量**
```bash
# 使用本地Docker MySQL
export DB_HOST=localhost
export DB_PORT=3306
export DB_PASSWORD=rootpassword
export DB_DATABASE=jiebanke_dev
```
3. **初始化数据库**
```bash
npm run db:reset # 重置并初始化数据库
npm run db:seed # 填充测试数据
```
### 生产环境连接说明
如需连接生产环境,请联系运维团队:
- 确认生产服务器MySQL root密码
- 检查IP白名单配置
- 验证网络连通性
- 确认防火墙规则
### 紧急开发方案
如果所有远程服务器都无法连接可以使用SQLite进行临时开发
```bash
export DB_DIALECT=sqlite
export DB_STORAGE=./database.sqlite
npm run dev
```
## 📝 开发规范
### 代码风格
- 使用ESLint进行代码检查
- 遵循JavaScript标准风格
- 使用async/await处理异步操作
### 安全规范
- 密码使用bcrypt加密存储
- 使用环境变量存储敏感信息
- 实施SQL注入防护
- 启用CORS和HTTPS
### 日志规范
- 开发环境使用详细日志
- 生产环境使用合并日志
- 记录关键操作和错误信息
## 🐛 常见问题
### Q: 数据库连接失败
A: 检查MySQL服务是否启动配置是否正确
### Q: 测试数据初始化失败
A: 确保数据库表结构已创建,可先运行迁移脚本
### Q: API测试失败
A: 确认后端服务已启动,检查网络连接
### Q: 权限不足
A: 检查数据库用户权限,确认有足够的操作权限
## 📞 技术支持
如有问题请联系开发团队或查看详细文档。
---
**最后更新: 2024年**
**版本: 1.0.0**

View File

@@ -0,0 +1,26 @@
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: jiebanke-mysql
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: jiebanke_dev
MYSQL_USER: jiebanke_user
MYSQL_PASSWORD: jiebanke_pass
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- ./scripts/init-database.sql:/docker-entrypoint-initdb.d/init.sql
restart: unless-stopped
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 10s
timeout: 5s
retries: 3
volumes:
mysql_data:
driver: local

View File

@@ -0,0 +1,67 @@
-- 创建数据库
CREATE DATABASE IF NOT EXISTS jiebanke_dev CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE jiebanke_dev;
-- 创建管理员表
CREATE TABLE IF NOT EXISTS admins (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
role ENUM('super_admin', 'admin') DEFAULT 'admin',
status ENUM('active', 'inactive') DEFAULT 'active',
last_login TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 创建用户表
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20),
real_name VARCHAR(100),
id_card VARCHAR(20),
status ENUM('active', 'inactive', 'frozen') DEFAULT 'active',
balance DECIMAL(15,2) DEFAULT 0.00,
credit_score INT DEFAULT 100,
last_login TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 创建订单表
CREATE TABLE IF NOT EXISTS orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
order_no VARCHAR(50) NOT NULL UNIQUE,
amount DECIMAL(15,2) NOT NULL,
status ENUM('pending', 'processing', 'completed', 'cancelled', 'failed') DEFAULT 'pending',
type ENUM('loan', 'repayment', 'transfer') NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- 插入默认管理员账号
INSERT INTO admins (username, password, email, role) VALUES
('admin', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'admin@jiebanke.com', 'super_admin'),
('manager', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'manager@jiebanke.com', 'admin');
-- 插入测试用户账号
INSERT INTO users (username, password, email, phone, real_name, id_card, balance, credit_score) VALUES
('user1', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'user1@example.com', '13800138001', '张三', '110101199001011234', 1000.00, 95),
('user2', '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'user2@example.com', '13800138002', '李四', '110101199002022345', 500.00, 85);
-- 创建索引
CREATE INDEX idx_admins_username ON admins(username);
CREATE INDEX idx_admins_email ON admins(email);
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_phone ON users(phone);
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_order_no ON orders(order_no);
CREATE INDEX idx_orders_status ON orders(status);

View File

@@ -0,0 +1,125 @@
#!/usr/bin/env node
/**
* 测试数据初始化脚本
* 用于开发环境创建测试数据
*/
const mysql = require('mysql2/promise');
const bcrypt = require('bcryptjs');
const config = require('../config/env');
// 数据库配置
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || 3306,
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'jiebanke_dev',
charset: process.env.DB_CHARSET || 'utf8mb4',
timezone: process.env.DB_TIMEZONE || '+08:00'
};
// 测试数据
const testData = {
admins: [
{
username: 'admin',
password: 'admin123',
email: 'admin@jiebanke.com',
nickname: '超级管理员',
role: 'super_admin',
status: 1
},
{
username: 'manager',
password: 'manager123',
email: 'manager@jiebanke.com',
nickname: '运营经理',
role: 'admin',
status: 1
}
],
users: [
{
username: 'user1',
password: 'user123',
email: 'user1@example.com',
nickname: '旅行爱好者',
avatar: null,
user_type: '普通用户',
status: 1
},
{
username: 'merchant1',
password: 'merchant123',
email: 'merchant1@example.com',
nickname: '农家乐老板',
avatar: null,
user_type: '商家',
status: 1
}
]
};
async function initTestData() {
let connection;
try {
console.log('🚀 开始初始化测试数据...');
// 创建数据库连接
connection = await mysql.createConnection(dbConfig);
console.log('✅ 数据库连接成功');
// 插入管理员数据
console.log('📝 插入管理员数据...');
for (const admin of testData.admins) {
const hashedPassword = await bcrypt.hash(admin.password, 10);
const [result] = await connection.execute(
`INSERT INTO admins (username, password, email, nickname, role, status, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[admin.username, hashedPassword, admin.email, admin.nickname, admin.role, admin.status]
);
console.log(` 创建管理员: ${admin.username} (ID: ${result.insertId})`);
}
// 插入用户数据
console.log('👥 插入用户数据...');
for (const user of testData.users) {
const hashedPassword = await bcrypt.hash(user.password, 10);
const [result] = await connection.execute(
`INSERT INTO users (username, password, email, nickname, avatar, user_type, status, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[user.username, hashedPassword, user.email, user.nickname, user.avatar, user.user_type, user.status]
);
console.log(` 创建用户: ${user.username} (ID: ${result.insertId})`);
}
console.log('\n🎉 测试数据初始化完成!');
console.log('📋 可用测试账号:');
console.log(' 管理员账号: admin / admin123');
console.log(' 运营账号: manager / manager123');
console.log(' 普通用户: user1 / user123');
console.log(' 商家用户: merchant1 / merchant123');
} catch (error) {
console.error('❌ 初始化测试数据失败:', error.message);
if (error.code === 'ER_NO_SUCH_TABLE') {
console.log('💡 提示: 请先运行数据库迁移脚本创建表结构');
}
} finally {
if (connection) {
await connection.end();
}
}
}
// 如果是直接运行此文件,则执行初始化
if (require.main === module) {
initTestData()
.then(() => process.exit(0))
.catch(() => process.exit(1));
}
module.exports = { initTestData };

View File

@@ -0,0 +1,174 @@
#!/usr/bin/env node
/**
* API端点测试脚本
* 用于验证后端API接口的正确性和一致性
*/
const axios = require('axios');
// API配置
const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:3100';
const API_VERSION = process.env.API_VERSION || '/api/v1';
// 测试用例
const testCases = [
// 管理员接口
{
name: '管理员登录接口',
method: 'POST',
path: '/admin/login',
expectedStatus: 200,
data: {
username: 'admin',
password: 'admin123'
}
},
{
name: '获取管理员信息接口',
method: 'GET',
path: '/admin/profile',
expectedStatus: 200,
requiresAuth: true
},
{
name: '获取管理员列表接口',
method: 'GET',
path: '/admin/list',
expectedStatus: 200,
requiresAuth: true
},
// 用户接口
{
name: '用户登录接口',
method: 'POST',
path: '/auth/login',
expectedStatus: 200,
data: {
username: 'user1',
password: 'user123'
}
},
{
name: '获取用户信息接口',
method: 'GET',
path: '/users/profile',
expectedStatus: 200,
requiresAuth: true
},
// 系统接口
{
name: '健康检查接口',
method: 'GET',
path: '/health',
expectedStatus: 200
},
{
name: '系统统计接口',
method: 'GET',
path: '/system-stats',
expectedStatus: 200
}
];
// 认证令牌
let authToken = '';
async function testEndpoint(testCase) {
try {
const url = `${API_BASE_URL}${API_VERSION}${testCase.path}`;
const config = {
method: testCase.method.toLowerCase(),
url: url,
headers: {}
};
// 添加认证头
if (testCase.requiresAuth && authToken) {
config.headers.Authorization = `Bearer ${authToken}`;
}
// 添加请求数据
if (testCase.data) {
config.data = testCase.data;
}
const response = await axios(config);
// 检查状态码
if (response.status === testCase.expectedStatus) {
console.log(`${testCase.name} - 成功 (${response.status})`);
// 如果是登录接口保存token
if (testCase.path === '/admin/login' && response.data.data && response.data.data.token) {
authToken = response.data.data.token;
console.log(` 获取到认证令牌`);
}
return true;
} else {
console.log(`${testCase.name} - 状态码不匹配: 期望 ${testCase.expectedStatus}, 实际 ${response.status}`);
return false;
}
} catch (error) {
if (error.response) {
console.log(`${testCase.name} - 错误: ${error.response.status} ${error.response.statusText}`);
if (error.response.data) {
console.log(` 错误信息: ${JSON.stringify(error.response.data)}`);
}
} else {
console.log(`${testCase.name} - 网络错误: ${error.message}`);
}
return false;
}
}
async function runAllTests() {
console.log('🚀 开始API端点测试');
console.log(`📊 测试环境: ${API_BASE_URL}`);
console.log(`🔗 API版本: ${API_VERSION}`);
console.log('='.repeat(60));
let passed = 0;
let failed = 0;
for (const testCase of testCases) {
const result = await testEndpoint(testCase);
if (result) {
passed++;
} else {
failed++;
}
// 添加短暂延迟,避免请求过于频繁
await new Promise(resolve => setTimeout(resolve, 100));
}
console.log('='.repeat(60));
console.log('📊 测试结果统计:');
console.log(`✅ 通过: ${passed}`);
console.log(`❌ 失败: ${failed}`);
console.log(`📈 成功率: ${((passed / (passed + failed)) * 100).toFixed(1)}%`);
if (failed === 0) {
console.log('🎉 所有测试用例通过!');
process.exit(0);
} else {
console.log('💥 存在失败的测试用例');
process.exit(1);
}
}
// 如果是直接运行此文件,则执行测试
if (require.main === module) {
runAllTests()
.catch(error => {
console.error('❌ 测试执行失败:', error.message);
process.exit(1);
});
}
module.exports = { runAllTests };

View File

@@ -0,0 +1,128 @@
#!/usr/bin/env node
/**
* 数据库连接测试脚本
* 用于验证MySQL数据库连接配置的正确性
*/
const mysql = require('mysql2/promise');
const config = require('../config/env');
// 数据库配置
const dbConfig = {
host: process.env.DB_HOST || '129.211.213.226',
port: process.env.DB_PORT || 9527,
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || 'Aiot123',
database: process.env.DB_NAME || 'jiebandata',
charset: process.env.DB_CHARSET || 'utf8mb4',
timezone: process.env.DB_TIMEZONE || '+08:00',
connectTimeout: 10000
};
async function testDatabaseConnection() {
let connection;
try {
console.log('🚀 开始数据库连接测试...');
console.log(`📊 环境: ${process.env.NODE_ENV || 'development'}`);
console.log(`🔗 连接信息: ${dbConfig.host}:${dbConfig.port}/${dbConfig.database}`);
console.log('='.repeat(50));
// 测试连接
console.log('🔍 测试数据库连接...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 数据库连接成功');
// 测试查询
console.log('🔍 测试基本查询...');
const [rows] = await connection.execute('SELECT 1 + 1 AS result');
console.log(`✅ 查询测试成功: ${rows[0].result}`);
// 检查表结构
console.log('🔍 检查核心表结构...');
const tablesToCheck = ['admins', 'users', 'merchants', 'orders'];
for (const table of tablesToCheck) {
try {
const [tableInfo] = await connection.execute(
`SELECT COUNT(*) as count FROM information_schema.tables
WHERE table_schema = ? AND table_name = ?`,
[dbConfig.database, table]
);
if (tableInfo[0].count > 0) {
console.log(`✅ 表存在: ${table}`);
} else {
console.log(`⚠️ 表不存在: ${table}`);
}
} catch (error) {
console.log(`❌ 检查表失败: ${table} - ${error.message}`);
}
}
// 检查管理员表数据
console.log('🔍 检查管理员数据...');
try {
const [adminCount] = await connection.execute('SELECT COUNT(*) as count FROM admins');
console.log(`📊 管理员记录数: ${adminCount[0].count}`);
if (adminCount[0].count > 0) {
const [admins] = await connection.execute('SELECT username, role, status FROM admins LIMIT 5');
console.log('👥 管理员样例:');
admins.forEach(admin => {
console.log(` - ${admin.username} (${admin.role}, 状态: ${admin.status})`);
});
}
} catch (error) {
console.log('❌ 检查管理员数据失败:', error.message);
}
// 检查连接池配置
console.log('🔍 检查连接池配置...');
console.log(`📈 连接池限制: ${config.mysql.connectionLimit || 10}`);
console.log(`🔤 字符集: ${config.mysql.charset}`);
console.log(`⏰ 时区: ${config.mysql.timezone}`);
console.log('\n🎉 数据库连接测试完成!');
console.log('✅ 所有配置检查通过');
} catch (error) {
console.error('❌ 数据库连接测试失败:', error.message);
console.error('💡 可能的原因:');
console.error(' - 数据库服务未启动');
console.error(' - 连接配置错误');
console.error(' - 网络连接问题');
console.error(' - 数据库权限不足');
console.error(' - 防火墙限制');
console.error(' - IP地址未授权');
if (error.code) {
console.error(`🔍 错误代码: ${error.code}`);
}
console.error('🔍 连接详情:', {
host: dbConfig.host,
port: dbConfig.port,
user: dbConfig.user,
database: dbConfig.database
});
process.exit(1);
} finally {
if (connection) {
await connection.end();
console.log('🔒 数据库连接已关闭');
}
}
}
// 如果是直接运行此文件,则执行测试
if (require.main === module) {
testDatabaseConnection()
.then(() => process.exit(0))
.catch(() => process.exit(1));
}
module.exports = { testDatabaseConnection };

View File

@@ -0,0 +1,62 @@
const mysql = require('mysql2/promise');
async function testDevConnection() {
console.log('🧪 测试开发环境数据库连接...');
const dbConfig = {
host: '192.168.0.240',
port: 3306,
user: 'root',
password: 'aiotAiot123!',
database: 'jiebandata',
connectTimeout: 10000
};
try {
console.log('🔗 尝试连接到开发服务器:', dbConfig.host + ':' + dbConfig.port);
const connection = await mysql.createConnection(dbConfig);
console.log('✅ 开发环境连接成功!');
// 测试基本查询
const [rows] = await connection.execute('SELECT 1 as test');
console.log('✅ 基本查询测试通过');
// 检查表结构
const [tables] = await connection.execute(`
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'jiebandata'
`);
console.log('📊 数据库中的表:', tables.map(t => t.TABLE_NAME).join(', ') || '暂无表');
await connection.end();
console.log('🎉 开发环境测试完成');
return true;
} catch (error) {
console.error('❌ 开发环境连接失败:', error.message);
console.log('🔍 错误代码:', error.code);
if (error.code === 'ECONNREFUSED') {
console.log('💡 可能原因: 开发服务器未启动或网络不可达');
} else if (error.code === 'ER_ACCESS_DENIED_ERROR') {
console.log('💡 可能原因: 用户名或密码错误');
} else if (error.code === 'ER_BAD_DB_ERROR') {
console.log('💡 可能原因: 数据库不存在');
}
return false;
}
}
// 执行测试
testDevConnection().then(success => {
if (success) {
console.log('\n✅ 所有测试通过!开发环境配置正确');
} else {
console.log('\n⚠ 开发环境配置需要检查');
}
process.exit(success ? 0 : 1);
});

View File

@@ -0,0 +1,48 @@
const mysql = require('mysql2/promise');
async function testNetworkConnection() {
console.log('🌐 测试网络连接性...');
const dbConfig = {
host: '129.211.213.226',
port: 9527,
user: 'root',
password: 'Aiot123',
connectTimeout: 5000,
acquireTimeout: 5000
};
try {
console.log('🔗 尝试连接到:', dbConfig.host + ':' + dbConfig.port);
const connection = await mysql.createConnection(dbConfig);
console.log('✅ 网络连接成功!');
await connection.end();
return true;
} catch (error) {
console.error('❌ 网络连接失败:', error.message);
console.log('🔍 错误代码:', error.code);
if (error.code === 'ECONNREFUSED') {
console.log('💡 可能原因: 端口未开放或服务未启动');
} else if (error.code === 'ETIMEDOUT') {
console.log('💡 可能原因: 网络超时或防火墙阻挡');
} else if (error.code === 'ER_ACCESS_DENIED_ERROR') {
console.log('💡 可能原因: 权限配置问题');
}
return false;
}
}
// 执行测试
testNetworkConnection().then(success => {
if (success) {
console.log('🎉 网络连接测试完成');
} else {
console.log('⚠️ 请检查网络配置和服务器状态');
}
process.exit(success ? 0 : 1);
});

364
docs/database-design.md Normal file
View File

@@ -0,0 +1,364 @@
# 结伴客系统数据库设计文档
## 1. 数据库概览
### 1.1 数据库配置
#### 测试环境
- **主机**: 192.168.0.240
- **端口**: 3306
- **用户名**: root
- **密码**: aiot$Aiot123
- **数据库**: jiebandata
#### 生产环境
- **主机**: 129.211.213.226
- **端口**: 9527
- **用户名**: root
- **密码**: aiotAiot123!
- **数据库**: jiebandata
### 1.2 ER图
```mermaid
erDiagram
USERS ||--o{ TRAVEL_PLANS : creates
USERS ||--o{ ANIMAL_CLAIMS : claims
USERS ||--o{ MESSAGES : sends
USERS ||--o{ ORDERS : places
USERS ||--o{ REVIEWS : writes
MERCHANTS ||--o{ PRODUCTS : sells
MERCHANTS ||--o{ ORDERS : processes
MERCHANTS ||--o{ ACTIVITIES : organizes
MERCHANTS ||--o{ ANIMALS : manages
TRAVEL_PLANS ||--o{ TRAVEL_MATCHES : matches
ANIMALS ||--o{ ANIMAL_CLAIMS : claimed
ANIMALS ||--o{ ANIMAL_UPDATES : updates
PRODUCTS ||--o{ ORDER_ITEMS : contains
ORDERS ||--o{ ORDER_ITEMS : contains
ORDERS ||--o{ PAYMENTS : has
ACTIVITIES ||--o{ ACTIVITY_REGISTRATIONS : registers
ADMINS ||--o{ ADMIN_LOGS : creates
USERS {
int id PK
string openid
string nickname
string avatar
string gender
date birthday
string phone
string email
datetime created_at
datetime updated_at
}
ADMINS {
int id PK
string username
string password
string email
string nickname
string avatar
enum role
tinyint status
timestamp last_login
timestamp created_at
timestamp updated_at
}
MERCHANTS {
int id PK
int user_id FK
string merchant_type
string business_name
string business_license
string contact_person
string contact_phone
string address
string description
string status
datetime created_at
datetime updated_at
}
TRAVEL_PLANS {
int id PK
int user_id FK
string destination
date start_date
date end_date
decimal budget
string interests
string visibility
datetime created_at
datetime updated_at
}
ANIMALS {
int id PK
int merchant_id FK
string name
string species
string breed
date birth_date
string personality
string farm_location
decimal price
string status
datetime created_at
datetime updated_at
}
ORDERS {
int id PK
int user_id FK
int merchant_id FK
string order_number
decimal total_amount
string status
string delivery_address
datetime ordered_at
datetime completed_at
}
PRODUCTS {
int id PK
int merchant_id FK
string name
string description
decimal price
string image_url
string category
string status
datetime created_at
datetime updated_at
}
```
## 2. 核心表结构设计
### 2.1 用户表 (users)
| 字段名 | 类型 | 约束 | 描述 |
|--------|------|------|------|
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 用户ID |
| openid | VARCHAR(64) | UNIQUE, NOT NULL | 微信openid |
| nickname | VARCHAR(50) | NOT NULL | 用户昵称 |
| avatar | VARCHAR(255) | | 用户头像URL |
| gender | ENUM('male', 'female', 'other') | | 性别 |
| birthday | DATE | | 生日 |
| phone | VARCHAR(20) | UNIQUE | 手机号码 |
| email | VARCHAR(100) | UNIQUE | 邮箱地址 |
| created_at | DATETIME | NOT NULL | 创建时间 |
| updated_at | DATETIME | NOT NULL | 更新时间 |
### 2.2 管理员表 (admins)
| 字段名 | 类型 | 约束 | 描述 |
|--------|------|------|------|
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 管理员ID |
| username | VARCHAR(50) | UNIQUE, NOT NULL | 管理员用户名 |
| password | VARCHAR(255) | NOT NULL | 密码(bcrypt加密) |
| email | VARCHAR(100) | UNIQUE | 邮箱地址 |
| nickname | VARCHAR(100) | | 昵称 |
| avatar | VARCHAR(255) | | 头像URL |
| role | ENUM('super_admin', 'admin', 'operator') | NOT NULL | 角色 |
| status | TINYINT | DEFAULT 1 | 状态(1:启用, 0:禁用) |
| last_login | TIMESTAMP | | 最后登录时间 |
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
**注意**: 管理员默认密码为 'admin123',使用 bcrypt 加密存储
### 2.3 商家表 (merchants)
| 字段名 | 类型 | 约束 | 描述 |
|--------|------|------|------|
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 商家ID |
| user_id | INT | FOREIGN KEY, NOT NULL | 关联的用户ID |
| merchant_type | ENUM('flower_shop', 'activity_organizer', 'farm_owner') | NOT NULL | 商家类型 |
| business_name | VARCHAR(100) | NOT NULL | 商家名称 |
| business_license | VARCHAR(255) | | 营业执照图片URL |
| contact_person | VARCHAR(50) | NOT NULL | 联系人 |
| contact_phone | VARCHAR(20) | NOT NULL | 联系电话 |
| address | VARCHAR(255) | | 地址 |
| description | TEXT | | 商家介绍 |
| status | ENUM('pending', 'approved', 'rejected', 'suspended') | NOT NULL | 商家状态 |
| created_at | DATETIME | NOT NULL | 创建时间 |
| updated_at | DATETIME | NOT NULL | 更新时间 |
### 2.4 订单表 (orders)
| 字段名 | 类型 | 约束 | 描述 |
|--------|------|------|------|
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 订单ID |
| user_id | INT | FOREIGN KEY, NOT NULL | 用户ID |
| merchant_id | INT | FOREIGN KEY, NOT NULL | 商家ID |
| order_number | VARCHAR(50) | UNIQUE, NOT NULL | 订单编号 |
| total_amount | DECIMAL(10,2) | NOT NULL | 订单总金额 |
| status | ENUM('pending', 'paid', 'shipped', 'completed', 'cancelled') | NOT NULL | 订单状态 |
| delivery_address | VARCHAR(255) | | 配送地址 |
| ordered_at | DATETIME | NOT NULL | 下单时间 |
| completed_at | DATETIME | | 完成时间 |
### 2.5 商品表 (products)
| 字段名 | 类型 | 约束 | 描述 |
|--------|------|------|------|
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 商品ID |
| merchant_id | INT | FOREIGN KEY, NOT NULL | 商家ID |
| name | VARCHAR(100) | NOT NULL | 商品名称 |
| description | TEXT | | 商品描述 |
| price | DECIMAL(10,2) | NOT NULL | 商品价格 |
| image_url | VARCHAR(255) | | 商品图片URL |
| category | VARCHAR(50) | NOT NULL | 商品分类 |
| status | ENUM('active', 'inactive', 'deleted') | NOT NULL | 商品状态 |
| created_at | DATETIME | NOT NULL | 创建时间 |
| updated_at | DATETIME | NOT NULL | 更新时间 |
## 3. 后台管理系统API接口规范
### 3.1 接口统一格式
#### 请求格式
- **Base URL**: http://localhost:3100/api/v1
- **认证**: Bearer Token (需要认证的接口)
- **Content-Type**: application/json
#### 响应格式
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
// 具体数据
},
"pagination": {
// 分页信息(列表接口)
}
}
```
### 3.2 通用状态码
| 状态码 | 描述 |
|--------|------|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 403 | 权限不足 |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
### 3.3 管理员接口
#### 3.3.1 管理员登录
- **Endpoint**: POST /admin/auth/login
- **认证要求**: 无
- **请求体**:
```json
{
"username": "admin",
"password": "password123"
}
```
#### 3.3.2 获取管理员信息
- **Endpoint**: GET /admin/auth/profile
- **认证要求**: Bearer Token
#### 3.3.3 更新管理员信息
- **Endpoint**: PUT /admin/auth/profile
- **认证要求**: Bearer Token
#### 3.3.4 修改密码
- **Endpoint**: PUT /admin/auth/password
- **认证要求**: Bearer Token
### 3.4 用户管理接口
#### 3.4.1 获取用户列表
- **Endpoint**: GET /admin/users
- **认证要求**: Bearer Token
- **查询参数**: page, limit, username, user_type, status
#### 3.4.2 获取用户详情
- **Endpoint**: GET /admin/users/{id}
- **认证要求**: Bearer Token
#### 3.4.3 更新用户状态
- **Endpoint**: PUT /admin/users/{id}/status
- **认证要求**: Bearer Token
### 3.5 商家管理接口
#### 3.5.1 获取商家列表
- **Endpoint**: GET /admin/merchants
- **认证要求**: Bearer Token
- **查询参数**: page, limit, business_name, status
#### 3.5.2 审核商家申请
- **Endpoint**: PUT /admin/merchants/{id}/approve
- **认证要求**: Bearer Token
#### 3.5.3 拒绝商家申请
- **Endpoint**: PUT /admin/merchants/{id}/reject
- **认证要求**: Bearer Token
### 3.6 订单管理接口
#### 3.6.1 获取订单列表
- **Endpoint**: GET /admin/orders
- **认证要求**: Bearer Token
- **查询参数**: page, limit, order_no, status
#### 3.6.2 更新订单状态
- **Endpoint**: PUT /admin/orders/{id}/status
- **认证要求**: Bearer Token
## 4. 数据库初始化脚本
### 4.1 创建管理员用户
```sql
INSERT INTO admins (username, password, email, nickname, role, status)
VALUES
('superadmin', '$2b$10$rOzJq...', 'superadmin@jiebanke.com', '超级管理员', 'super_admin', 1),
('admin', '$2b$10$rOzJq...', 'admin@jiebanke.com', '管理员', 'admin', 1),
('operator', '$2b$10$rOzJq...', 'operator@jiebanke.com', '操作员', 'operator', 1);
```
### 4.2 创建测试用户
```sql
INSERT INTO users (openid, nickname, gender, phone, email)
VALUES
('wx1234567890', '测试用户1', 'male', '13800138000', 'test1@example.com'),
('wx0987654321', '测试用户2', 'female', '13800138001', 'test2@example.com');
```
### 4.3 创建测试商家
```sql
INSERT INTO merchants (user_id, merchant_type, business_name, contact_person, contact_phone, status)
VALUES
(1, 'flower_shop', '鲜花小店', '张老板', '13800138002', 'approved'),
(2, 'farm_owner', '快乐农场', '李农场主', '13800138003', 'approved');
```
## 5. 数据库维护
### 5.1 备份策略
- 每日全量备份
- 每小时增量备份
- 备份保留30天
### 5.2 性能优化
- 为常用查询字段创建索引
- 定期分析慢查询日志
- 数据库连接池配置优化
### 5.3 安全措施
- 定期更换数据库密码
- 限制数据库访问IP
- 启用SSL加密连接

12923
mini-program/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

33
reset-admin-password.js Normal file
View File

@@ -0,0 +1,33 @@
const bcrypt = require('bcryptjs');
// 重置管理员密码为 'admin123'
async function resetAdminPassword() {
try {
const plainPassword = 'admin123';
const hashedPassword = await bcrypt.hash(plainPassword, 10);
console.log('🔐 重置管理员密码');
console.log('='.repeat(50));
console.log('原密码:', plainPassword);
console.log('加密后:', hashedPassword);
console.log('');
// 生成SQL更新语句
const updateSQL = `UPDATE jiebandata.admins SET password = '${hashedPassword}' WHERE username = 'admin';`;
console.log('📋 SQL更新语句:');
console.log(updateSQL);
console.log('');
console.log('💡 使用方法:');
console.log('1. 使用MySQL客户端执行以上SQL语句');
console.log('2. 或者使用MCP工具执行SQL更新');
console.log('3. 然后使用用户名: admin, 密码: admin123 登录');
} catch (error) {
console.error('❌ 生成密码失败:', error.message);
}
}
// 运行重置
resetAdminPassword();

111
scripts/init-database.sql Normal file
View File

@@ -0,0 +1,111 @@
-- 结伴客系统数据库初始化脚本
-- 创建时间: 2024-01-15
-- 版本: 1.0.0
USE jiebandata;
-- 清空现有测试数据(可选,谨慎使用)
-- TRUNCATE TABLE admins;
-- TRUNCATE TABLE users;
-- TRUNCATE TABLE merchants;
-- 插入管理员用户数据
INSERT INTO admins (username, password, email, nickname, role, status) VALUES
('superadmin', '$2b$10$rOzJqJzX9zX9zX9zX9zX9u', 'superadmin@jiebanke.com', '超级管理员', 'super_admin', 1),
('admin', '$2b$10$rOzJqJzX9zX9zX9zX9zX9u', 'admin@jiebanke.com', '管理员', 'admin', 1),
('operator', '$2b$10$rOzJqJzX9zX9zX9zX9zX9u', 'operator@jiebanke.com', '操作员', 'operator', 1)
ON DUPLICATE KEY UPDATE updated_at = CURRENT_TIMESTAMP;
-- 插入测试用户数据
INSERT INTO users (openid, nickname, gender, phone, email, created_at, updated_at) VALUES
('wx_test_user_001', '测试用户张三', 'male', '13800138001', 'zhangsan@example.com', NOW(), NOW()),
('wx_test_user_002', '测试用户李四', 'female', '13800138002', 'lisi@example.com', NOW(), NOW()),
('wx_test_user_003', '测试用户王五', 'male', '13800138003', 'wangwu@example.com', NOW(), NOW()),
('wx_test_user_004', '测试用户赵六', 'female', '13800138004', 'zhaoliu@example.com', NOW(), NOW()),
('wx_test_user_005', '测试用户钱七', 'male', '13800138005', 'qianqi@example.com', NOW(), NOW()),
('wx_test_user_006', '测试用户孙八', 'female', '13800138006', 'sunba@example.com', NOW(), NOW()),
('wx_test_user_007', '测试用户周九', 'male', '13800138007', 'zhoujiu@example.com', NOW(), NOW()),
('wx_test_user_008', '测试用户吴十', 'female', '13800138008', 'wushi@example.com', NOW(), NOW()),
('wx_test_user_009', '测试用户郑十一', 'male', '13800138009', 'zhengshiyi@example.com', NOW(), NOW()),
('wx_test_user_010', '测试用户王十二', 'female', '13800138010', 'wangshier@example.com', NOW(), NOW())
ON DUPLICATE KEY UPDATE updated_at = NOW();
-- 插入测试商家数据
INSERT INTO merchants (user_id, merchant_type, business_name, contact_person, contact_phone, address, status, created_at, updated_at) VALUES
(1, 'flower_shop', '鲜花小店', '张老板', '13800138100', '北京市朝阳区鲜花大街1号', 'approved', NOW(), NOW()),
(2, 'farm_owner', '快乐农场', '李农场主', '13800138101', '上海市浦东新区农场路88号', 'approved', NOW(), NOW()),
(3, 'activity_organizer', '户外活动俱乐部', '王教练', '13800138102', '广州市天河区体育西路123号', 'approved', NOW(), NOW()),
(4, 'flower_shop', '浪漫花坊', '赵花艺师', '13800138103', '深圳市南山区科技园路456号', 'approved', NOW(), NOW()),
(5, 'farm_owner', '有机农场', '钱农民', '13800138104', '杭州市西湖区龙井路789号', 'pending', NOW(), NOW())
ON DUPLICATE KEY UPDATE updated_at = NOW();
-- 插入测试商品数据
INSERT INTO products (merchant_id, name, description, price, image_url, category, status, created_at, updated_at) VALUES
(1, '红玫瑰花束', '新鲜红玫瑰11朵精美包装', 199.00, '/images/flowers/rose.jpg', 'flowers', 'active', NOW(), NOW()),
(1, '百合花束', '白色百合花清新淡雅', 159.00, '/images/flowers/lily.jpg', 'flowers', 'active', NOW(), NOW()),
(2, '有机蔬菜礼盒', '当季有机蔬菜新鲜配送', 88.00, '/images/farm/vegetables.jpg', 'farm', 'active', NOW(), NOW()),
(2, '散养鸡蛋', '农家散养新鲜鸡蛋', 25.00, '/images/farm/eggs.jpg', 'farm', 'active', NOW(), NOW()),
(3, '户外徒步活动', '周末户外徒步一日游', 150.00, '/images/activities/hiking.jpg', 'activity', 'active', NOW(), NOW()),
(4, '康乃馨花束', '粉色康乃馨温馨祝福', 129.00, '/images/flowers/carnation.jpg', 'flowers', 'active', NOW(), NOW())
ON DUPLICATE KEY UPDATE updated_at = NOW();
-- 插入测试订单数据
INSERT INTO orders (user_id, merchant_id, order_number, total_amount, status, delivery_address, ordered_at) VALUES
(1, 1, 'ORDER202401150001', 199.00, 'completed', '北京市朝阳区测试地址1号', NOW()),
(2, 2, 'ORDER202401150002', 113.00, 'paid', '上海市浦东新区测试地址2号', NOW()),
(3, 3, 'ORDER202401150003', 150.00, 'shipped', '广州市天河区测试地址3号', NOW()),
(4, 1, 'ORDER202401150004', 328.00, 'pending', '深圳市南山区测试地址4号', NOW()),
(5, 4, 'ORDER202401150005', 129.00, 'cancelled', '杭州市西湖区测试地址5号', NOW())
ON DUPLICATE KEY UPDATE updated_at = NOW();
-- 插入订单商品关联数据
INSERT INTO order_items (order_id, product_id, quantity, unit_price) VALUES
(1, 1, 1, 199.00),
(2, 3, 1, 88.00),
(2, 4, 1, 25.00),
(3, 5, 1, 150.00),
(4, 1, 1, 199.00),
(4, 2, 1, 129.00),
(5, 6, 1, 129.00)
ON DUPLICATE KEY UPDATE unit_price = VALUES(unit_price);
-- 插入支付记录数据
INSERT INTO payments (order_id, payment_method, transaction_id, amount, status, paid_at) VALUES
(1, 'wechat', 'WX202401150001', 199.00, 'success', NOW()),
(2, 'alipay', 'AL202401150002', 113.00, 'success', NOW()),
(3, 'balance', 'BAL202401150003', 150.00, 'success', NOW()),
(4, 'wechat', 'WX202401150004', 328.00, 'pending', NULL),
(5, 'alipay', 'AL202401150005', 129.00, 'failed', NULL)
ON DUPLICATE KEY UPDATE updated_at = NOW();
-- 查询确认数据插入情况
SELECT '管理员数据统计:' AS info, COUNT(*) AS count FROM admins
UNION ALL
SELECT '用户数据统计:', COUNT(*) FROM users
UNION ALL
SELECT '商家数据统计:', COUNT(*) FROM merchants
UNION ALL
SELECT '商品数据统计:', COUNT(*) FROM products
UNION ALL
SELECT '订单数据统计:', COUNT(*) FROM orders
UNION ALL
SELECT '支付记录统计:', COUNT(*) FROM payments;
-- 显示最近插入的管理员用户
SELECT '最近管理员:' AS type, username, nickname, role, status FROM admins ORDER BY id DESC LIMIT 3;
-- 显示最近插入的普通用户
SELECT '最近用户:' AS type, nickname, gender, phone, email FROM users ORDER BY id DESC LIMIT 5;
-- 显示商家列表
SELECT '商家列表:' AS type, business_name, contact_person, contact_phone, status FROM merchants ORDER BY id;
-- 显示商品列表
SELECT '商品列表:' AS type, name, price, category, status FROM products ORDER BY merchant_id, id;
-- 显示订单统计
SELECT '订单状态统计:' AS status, COUNT(*) AS count FROM orders GROUP BY status;
COMMIT;
SELECT '数据库初始化完成!' AS message;

105
test-admin-api.js Normal file
View File

@@ -0,0 +1,105 @@
const axios = require('axios');
// API基础配置
const BASE_URL = 'http://localhost:3100';
// 测试管理员登录
async function testAdminLogin() {
try {
console.log('🔐 测试管理员登录接口...');
const response = await axios.post(`${BASE_URL}/api/v1/admin/login`, {
username: 'admin',
password: 'admin123' // 默认密码
});
console.log('✅ 登录成功:', response.data);
return response.data.data.token;
} catch (error) {
console.error('❌ 登录失败:', error.response?.data || error.message);
return null;
}
}
// 测试获取管理员信息
async function testGetAdminProfile(token) {
if (!token) return;
try {
console.log('\n👤 测试获取管理员信息接口...');
const response = await axios.get(`${BASE_URL}/api/v1/admin/profile`, {
headers: { Authorization: `Bearer ${token}` }
});
console.log('✅ 获取管理员信息成功:', response.data);
} catch (error) {
console.error('❌ 获取管理员信息失败:', error.response?.data || error.message);
}
}
// 测试获取用户列表
async function testGetUsers(token) {
if (!token) return;
try {
console.log('\n👥 测试获取用户列表接口...');
const response = await axios.get(`${BASE_URL}/api/v1/users`, {
headers: { Authorization: `Bearer ${token}` },
params: { page: 1, limit: 10 }
});
console.log('✅ 获取用户列表成功:');
console.log(' 总用户数:', response.data.data.total);
console.log(' 当前页用户数:', response.data.data.items.length);
} catch (error) {
console.error('❌ 获取用户列表失败:', error.response?.data || error.message);
}
}
// 测试获取系统信息
async function testGetSystemInfo(token) {
if (!token) return;
try {
console.log('\n💻 测试获取系统信息接口...');
const response = await axios.get(`${BASE_URL}/api/v1/admin/system/info`, {
headers: { Authorization: `Bearer ${token}` }
});
console.log('✅ 获取系统信息成功:');
console.log(' 系统版本:', response.data.data.version);
console.log(' 运行环境:', response.data.data.environment);
} catch (error) {
console.error('❌ 获取系统信息失败:', error.response?.data || error.message);
}
}
// 主测试函数
async function main() {
console.log('🎯 结伴客系统管理员API测试工具');
console.log('='.repeat(60));
// 检查后端服务是否运行
try {
await axios.get(`${BASE_URL}/health`);
console.log('✅ 后端服务正常运行');
} catch (error) {
console.log('⚠️ 后端服务未启动,请先启动后端服务');
console.log(' 运行命令: cd backend && npm start');
return;
}
const token = await testAdminLogin();
await testGetAdminProfile(token);
await testGetUsers(token);
await testGetSystemInfo(token);
console.log('\n' + '='.repeat(60));
console.log('🎉 API测试完成');
}
// 运行测试
main().catch(console.error);