refactor(backend): 更新数据库配置并迁移至MySQL,优化文档和技术栈描述
This commit is contained in:
375
API_DOCS.md
Normal file
375
API_DOCS.md
Normal file
@@ -0,0 +1,375 @@
|
||||
# 📚 API 接口文档
|
||||
|
||||
## 📋 文档说明
|
||||
本文档详细描述了杰邦科项目的所有API接口,包括请求参数、响应格式和错误代码。
|
||||
|
||||
## 🔐 认证方式
|
||||
|
||||
### JWT Token 认证
|
||||
所有需要认证的API必须在请求头中携带Token:
|
||||
```
|
||||
Authorization: Bearer <your_jwt_token>
|
||||
```
|
||||
|
||||
### Token 获取
|
||||
通过登录接口获取Token,Token有效期为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
264
architecture.md
Normal 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年* 📅
|
||||
257
backend/README_DEVELOPMENT.md
Normal file
257
backend/README_DEVELOPMENT.md
Normal 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**
|
||||
26
backend/docker-compose.yml
Normal file
26
backend/docker-compose.yml
Normal 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
|
||||
67
backend/scripts/init-database.sql
Normal file
67
backend/scripts/init-database.sql
Normal 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);
|
||||
125
backend/scripts/init-test-data.js
Normal file
125
backend/scripts/init-test-data.js
Normal 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 };
|
||||
174
backend/scripts/test-api-endpoints.js
Normal file
174
backend/scripts/test-api-endpoints.js
Normal 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 };
|
||||
128
backend/scripts/test-database-connection.js
Normal file
128
backend/scripts/test-database-connection.js
Normal 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 };
|
||||
62
backend/scripts/test-dev-connection.js
Normal file
62
backend/scripts/test-dev-connection.js
Normal 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);
|
||||
});
|
||||
48
backend/scripts/test-network.js
Normal file
48
backend/scripts/test-network.js
Normal 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
364
docs/database-design.md
Normal 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
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
33
reset-admin-password.js
Normal 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
111
scripts/init-database.sql
Normal 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
105
test-admin-api.js
Normal 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);
|
||||
Reference in New Issue
Block a user