docs: 更新项目文档,完善需求和技术细节

This commit is contained in:
ylweng
2025-09-01 01:05:53 +08:00
parent 028a458283
commit 816a51ae82
48 changed files with 18629 additions and 5301 deletions

View File

@@ -1,6 +1,6 @@
# 应用配置
NODE_ENV=development
PORT=3000
PORT=3200
JWT_SECRET=your-super-secret-jwt-key-change-in-production
# 数据库配置

View File

@@ -6,10 +6,10 @@ PORT=3200
APP_NAME=爱鉴花小程序后端
# MySQL数据库配置
DB_HOST=192.168.0.240
DB_PORT=3306
DB_HOST=129.211.213.226
DB_PORT=9527
DB_USERNAME=root
DB_PASSWORD=aiot$Aiot123
DB_PASSWORD=aiotAiot123!
DB_DATABASE=ajhdata
# Redis配置

View File

@@ -7,10 +7,10 @@ PORT=3000
APP_NAME=爱鉴花小程序后端
# MySQL数据库配置
DB_HOST=192.168.0.240
DB_PORT=3306
DB_HOST=129.211.213.226
DB_PORT=9527
DB_USERNAME=root
DB_PASSWORD=aiot$Aiot123
DB_PASSWORD=aiotAiot123!
DB_DATABASE=ajhdata
# Redis配置

View File

@@ -6,7 +6,7 @@
## 基础信息
- **基础URL**: `http://localhost:3000/api/v1`
- **基础URL**: `http://localhost:3200/api/v1`
- **认证方式**: Bearer Token (JWT)
- **数据格式**: JSON
- **字符编码**: UTF-8

View File

@@ -6,7 +6,8 @@
## 技术栈
- Node.js
- Express.js
- MongoDB
- SQLite开发环境
- MySQL生产环境
- Redis
## 文件结构

View File

@@ -2,14 +2,14 @@
## 📋 数据库连接信息
### 测试环境
- **主机**: 192.168.0.240
- **端口**: 3306
### 开发环境 (MySQL)
- **主机**: 129.211.213.226
- **端口**: 9527
- **用户名**: root
- **密码**: aiot$Aiot123
- **密码**: aiotAiot123!
- **数据库**: ajhdata
### 生产环境
### 生产环境 (MySQL)
- **主机**: 129.211.213.226
- **端口**: 9527
- **用户名**: root

View File

@@ -22,13 +22,14 @@ const userRoutes = require('./routes/users');
const productRoutes = require('./routes/products');
const orderRoutes = require('./routes/orders');
const identificationRoutes = require('./routes/identifications');
const adminRoutes = require('./routes/admin');
// 导入中间件
const { errorHandler } = require('./middlewares/errorHandler');
const { authMiddleware } = require('./middlewares/auth');
const app = express();
const PORT = process.env.PORT || 3000;
const PORT = process.env.PORT || 3201;
// 安全中间件
app.use(helmet());
@@ -75,6 +76,7 @@ app.use('/api/v1/users', authMiddleware, userRoutes);
app.use('/api/v1/products', productRoutes);
app.use('/api/v1/orders', authMiddleware, orderRoutes);
app.use('/api/v1/identifications', authMiddleware, identificationRoutes);
app.use('/api/v1/admin', authMiddleware, adminRoutes);
// 404处理
app.use('*', (req, res) => {

View File

@@ -4,12 +4,12 @@
*/
const databaseConfig = {
// 测试环境配置
// 开发环境配置
development: {
host: '192.168.0.240',
port: 3306,
host: '129.211.213.226',
port: 9527,
username: 'root',
password: 'aiot$Aiot123',
password: 'aiotAiot123!',
database: 'ajhdata',
dialect: 'mysql',
logging: console.log,

View File

@@ -21,7 +21,7 @@ const options = {
{
url: process.env.NODE_ENV === 'production'
? 'https://api.aijianhua.com'
: `http://localhost:${process.env.PORT || 3000}`,
: `http://localhost:${process.env.PORT || 3200}`,
description: process.env.NODE_ENV === 'production' ? '生产环境' : '开发环境'
}
],

BIN
backend/database.sqlite Normal file

Binary file not shown.

5309
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,49 +5,43 @@
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js",
"test": "jest",
"lint": "eslint .",
"dev": "NODE_ENV=development PORT=3200 nodemon app.js",
"prod": "NODE_ENV=production node app.js",
"db:init": "node scripts/initDatabase.js",
"db:check": "node scripts/initDatabase.js --check",
"db:migrate": "node scripts/migrate.js",
"db:seed": "node scripts/seedData.js"
"test": "jest",
"docs": "node scripts/generateDocs.js"
},
"dependencies": {
"express": "^4.18.2",
"mysql2": "^3.6.0",
"cors": "^2.8.5",
"helmet": "^7.0.0",
"compression": "^1.7.4",
"morgan": "^1.10.0",
"dotenv": "^16.3.1",
"jsonwebtoken": "^9.0.2",
"bcryptjs": "^2.4.3",
"validator": "^13.11.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"helmet": "^6.1.5",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",
"multer": "^1.4.5-lts.1",
"mysql2": "^3.6.0",
"redis": "^4.6.8",
"socket.io": "^4.7.2",
"sqlite3": "^5.1.7",
"swagger-ui-express": "^4.6.3",
"validator": "^13.11.0",
"yamljs": "^0.3.0"
},
"devDependencies": {
"nodemon": "^3.0.1",
"jest": "^29.6.2",
"eslint": "^8.47.0",
"prettier": "^3.0.2",
"@types/node": "^20.5.0",
"typescript": "^5.1.6"
"nodemon": "^2.0.22"
},
"keywords": [
"wechat",
"mini-program",
"plant-identification",
"ecommerce",
"api"
"aijianhua",
"plant",
"identification",
"api",
"express"
],
"author": "爱鉴花开发团队",
"author": "爱鉴花团队",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
"node": ">=14.0.0"
}
}
}

265
backend/routes/admin.js Normal file
View File

@@ -0,0 +1,265 @@
const express = require('express');
const dbConnector = require('../utils/dbConnector');
const { adminRequired } = require('../middlewares/auth');
const { asyncHandler } = require('../middlewares/errorHandler');
const router = express.Router();
/**
* 获取系统统计概览
*/
router.get('/statistics/overview', adminRequired, asyncHandler(async (req, res) => {
// 获取总用户数
const totalUsersResult = await dbConnector.query(
'SELECT COUNT(*) as total FROM users WHERE status = 1'
);
// 获取今日新增用户数
const newUsersTodayResult = await dbConnector.query(
'SELECT COUNT(*) as total FROM users WHERE status = 1 AND DATE(created_at) = CURDATE()'
);
// 获取总订单数
const totalOrdersResult = await dbConnector.query(
'SELECT COUNT(*) as total FROM orders'
);
// 获取总收入
const totalRevenueResult = await dbConnector.query(
'SELECT COALESCE(SUM(total_amount), 0) as total FROM orders WHERE payment_status = 1'
);
// 获取总识别次数
const totalIdentificationsResult = await dbConnector.query(
'SELECT COUNT(*) as total FROM identifications'
);
// 获取今日活跃用户数
const activeUsersTodayResult = await dbConnector.query(
`SELECT COUNT(DISTINCT user_id) as total FROM (
SELECT user_id FROM orders WHERE DATE(created_at) = CURDATE()
UNION
SELECT user_id FROM identifications WHERE DATE(created_at) = CURDATE()
) as active_users`
);
res.json({
code: 200,
message: '获取成功',
data: {
total_users: totalUsersResult[0].total,
new_users_today: newUsersTodayResult[0].total,
total_orders: totalOrdersResult[0].total,
total_revenue: parseFloat(totalRevenueResult[0].total),
total_identifications: totalIdentificationsResult[0].total,
active_users_today: activeUsersTodayResult[0].total
}
});
}));
/**
* 获取趋势数据
*/
router.get('/statistics/trend', adminRequired, asyncHandler(async (req, res) => {
const { days = 7, type = 'users' } = req.query;
const dayCount = parseInt(days);
let query = '';
let dataKey = '';
switch (type) {
case 'users':
query = `
SELECT DATE(created_at) as date, COUNT(*) as count
FROM users
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY)
GROUP BY DATE(created_at)
ORDER BY date
`;
dataKey = 'new_users';
break;
case 'orders':
query = `
SELECT DATE(created_at) as date, COUNT(*) as count
FROM orders
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY)
GROUP BY DATE(created_at)
ORDER BY date
`;
dataKey = 'new_orders';
break;
case 'revenue':
query = `
SELECT DATE(created_at) as date, COALESCE(SUM(total_amount), 0) as amount
FROM orders
WHERE payment_status = 1 AND created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY)
GROUP BY DATE(created_at)
ORDER BY date
`;
dataKey = 'revenue';
break;
case 'identifications':
query = `
SELECT DATE(created_at) as date, COUNT(*) as count
FROM identifications
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY)
GROUP BY DATE(created_at)
ORDER BY date
`;
dataKey = 'identifications';
break;
default:
return res.status(400).json({
code: 400,
message: '不支持的统计类型',
data: null
});
}
const trendData = await dbConnector.query(query, [dayCount]);
res.json({
code: 200,
message: '获取成功',
data: {
type,
days: dayCount,
trend: trendData,
total: trendData.reduce((sum, item) => sum + (item.count || item.amount || 0), 0)
}
});
}));
/**
* 获取系统配置列表
*/
router.get('/config', adminRequired, asyncHandler(async (req, res) => {
const configs = await dbConnector.query(
'SELECT config_key, config_value, config_type, description FROM system_config ORDER BY config_key'
);
res.json({
code: 200,
message: '获取成功',
data: configs
});
}));
/**
* 获取单个系统配置
*/
router.get('/config/:key', adminRequired, asyncHandler(async (req, res) => {
const { key } = req.params;
const configs = await dbConnector.query(
'SELECT config_key, config_value, config_type, description FROM system_config WHERE config_key = ?',
[key]
);
if (configs.length === 0) {
return res.status(404).json({
code: 404,
message: '配置项不存在',
data: null
});
}
res.json({
code: 200,
message: '获取成功',
data: configs[0]
});
}));
/**
* 更新系统配置
*/
router.put('/config/:key', adminRequired, asyncHandler(async (req, res) => {
const { key } = req.params;
const { value } = req.body;
if (value === undefined) {
return res.status(400).json({
code: 400,
message: '配置值不能为空',
data: null
});
}
const result = await dbConnector.query(
'UPDATE system_config SET config_value = ?, updated_at = CURRENT_TIMESTAMP WHERE config_key = ?',
[value, key]
);
if (result.affectedRows === 0) {
return res.status(404).json({
code: 404,
message: '配置项不存在',
data: null
});
}
res.json({
code: 200,
message: '更新成功',
data: null
});
}));
/**
* 获取操作日志
*/
router.get('/logs', adminRequired, asyncHandler(async (req, res) => {
const { page = 1, limit = 20, module, action, username } = req.query;
const offset = (page - 1) * limit;
let whereClause = 'WHERE 1=1';
let queryParams = [];
if (module) {
whereClause += ' AND module = ?';
queryParams.push(module);
}
if (action) {
whereClause += ' AND action = ?';
queryParams.push(action);
}
if (username) {
whereClause += ' AND username LIKE ?';
queryParams.push(`%${username}%`);
}
// 获取日志列表
const logs = await dbConnector.query(
`SELECT id, user_id, username, user_type, module, action, target_id,
description, ip_address, user_agent, created_at
FROM operation_logs ${whereClause}
ORDER BY created_at DESC
LIMIT ? OFFSET ?`,
[...queryParams, parseInt(limit), offset]
);
// 获取总数
const totalResult = await dbConnector.query(
`SELECT COUNT(*) as total FROM operation_logs ${whereClause}`,
queryParams
);
res.json({
code: 200,
message: '获取成功',
data: {
logs,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total: totalResult[0].total,
pages: Math.ceil(totalResult[0].total / limit)
}
}
});
}));
module.exports = router;

View File

@@ -66,7 +66,7 @@ router.post('/register', async (req, res, next) => {
// 创建用户
const result = await dbConnector.query(
'INSERT INTO users (username, password_hash, phone, email, user_type) VALUES (?, ?, ?, ?, ?)',
'INSERT INTO users (username, password, phone, email, user_type) VALUES (?, ?, ?, ?, ?)',
[username, hashedPassword, phone, email, user_type]
);
@@ -127,7 +127,7 @@ router.post('/login', async (req, res, next) => {
const userData = user[0];
// 验证密码
const isValidPassword = await bcrypt.compare(password, userData.password_hash);
const isValidPassword = await bcrypt.compare(password, userData.password);
if (!isValidPassword) {
return res.status(401).json({
code: 401,

View File

@@ -0,0 +1,260 @@
#!/usr/bin/env node
/**
* SQLite数据库初始化脚本
* 用于创建SQLite数据库表结构
*/
const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const databaseConfig = require('../config/database');
class SQLiteInitializer {
constructor() {
this.db = null;
}
/**
* 创建数据库连接
*/
createConnection() {
try {
this.db = new sqlite3.Database(databaseConfig.storage);
console.log('✅ SQLite数据库连接成功');
return true;
} catch (error) {
console.error('❌ SQLite数据库连接失败:', error.message);
return false;
}
}
/**
* 执行SQL语句
*/
run(sql, params = []) {
return new Promise((resolve, reject) => {
this.db.run(sql, params, function(err) {
if (err) {
reject(err);
} else {
resolve(this);
}
});
});
}
/**
* 创建users表
*/
async createUsersTable() {
const sql = `
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
phone VARCHAR(20) UNIQUE,
email VARCHAR(100) UNIQUE,
user_type VARCHAR(20) DEFAULT 'user',
status INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`;
try {
await this.run(sql);
console.log('✅ users表创建成功');
return true;
} catch (error) {
console.error('❌ 创建users表失败:', error.message);
return false;
}
}
/**
* 创建orders表
*/
async createOrdersTable() {
const sql = `
CREATE TABLE IF NOT EXISTS orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_number VARCHAR(50) UNIQUE NOT NULL,
user_id INTEGER NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
payment_status INTEGER DEFAULT 0,
shipping_status INTEGER DEFAULT 0,
shipping_address TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users (id)
)
`;
try {
await this.run(sql);
console.log('✅ orders表创建成功');
return true;
} catch (error) {
console.error('❌ 创建orders表失败:', error.message);
return false;
}
}
/**
* 创建identifications表
*/
async createIdentificationsTable() {
const sql = `
CREATE TABLE IF NOT EXISTS identifications (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
image_url VARCHAR(255) NOT NULL,
result TEXT NOT NULL,
confidence DECIMAL(5,4) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users (id)
)
`;
try {
await this.run(sql);
console.log('✅ identifications表创建成功');
return true;
} catch (error) {
console.error('❌ 创建identifications表失败:', error.message);
return false;
}
}
/**
* 创建products表
*/
async createProductsTable() {
const sql = `
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
category_id INTEGER,
price DECIMAL(10,2) NOT NULL,
stock INTEGER DEFAULT 0,
image VARCHAR(255),
description TEXT,
status INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`;
try {
await this.run(sql);
console.log('✅ products表创建成功');
return true;
} catch (error) {
console.error('❌ 创建products表失败:', error.message);
return false;
}
}
/**
* 插入初始管理员用户
*/
async insertAdminUser() {
const sql = `
INSERT OR IGNORE INTO users (username, password, phone, email, user_type, status)
VALUES (?, ?, ?, ?, ?, ?)
`;
// 密码: admin123 (bcrypt加密)
const hashedPassword = '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi';
try {
await this.run(sql, [
'admin',
hashedPassword,
'13800138000',
'admin@example.com',
'admin',
1
]);
console.log('✅ 管理员用户创建成功');
return true;
} catch (error) {
console.error('❌ 创建管理员用户失败:', error.message);
return false;
}
}
/**
* 关闭数据库连接
*/
closeConnection() {
if (this.db) {
this.db.close();
console.log('🔌 数据库连接已关闭');
}
}
/**
* 主初始化方法
*/
async initialize() {
console.log('🚀 开始SQLite数据库初始化...');
console.log(`📋 环境: ${process.env.NODE_ENV || 'development'}`);
console.log(`🗄️ 数据库文件: ${databaseConfig.storage}`);
console.log('─'.repeat(50));
// 创建连接
const connected = this.createConnection();
if (!connected) {
process.exit(1);
}
// 创建表
const tablesCreated = await Promise.all([
this.createUsersTable(),
this.createOrdersTable(),
this.createIdentificationsTable(),
this.createProductsTable()
]);
if (tablesCreated.every(result => result)) {
console.log('✅ 所有表创建成功');
} else {
console.error('❌ 表创建过程中出现错误');
this.closeConnection();
process.exit(1);
}
// 插入初始数据
const adminCreated = await this.insertAdminUser();
if (!adminCreated) {
console.warn('⚠️ 管理员用户创建失败或已存在');
}
console.log('✅ SQLite数据库初始化完成');
this.closeConnection();
}
}
// 执行初始化
const initializer = new SQLiteInitializer();
// 处理命令行参数
const args = process.argv.slice(2);
if (args.includes('--help') || args.includes('-h')) {
console.log(`
使用方法: node scripts/initSQLite.js [选项]
选项:
--help, -h 显示帮助信息
示例:
node scripts/initSQLite.js # 完整初始化
`);
process.exit(0);
}
initializer.initialize().catch(error => {
console.error('❌ 初始化过程中发生错误:', error.message);
process.exit(1);
});

View File

@@ -4,12 +4,14 @@
*/
const mysql = require('mysql2/promise');
const sqlite3 = require('sqlite3').verbose();
const databaseConfig = require('../config/database');
class DBConnector {
constructor() {
this.pool = null;
this.connection = null;
this.db = null;
this.init();
}
@@ -18,25 +20,31 @@ class DBConnector {
*/
init() {
try {
this.pool = mysql.createPool({
host: databaseConfig.host,
port: databaseConfig.port,
user: databaseConfig.username,
password: databaseConfig.password,
database: databaseConfig.database,
connectionLimit: databaseConfig.pool.max,
acquireTimeout: databaseConfig.pool.acquire,
timeout: databaseConfig.pool.idle,
charset: 'utf8mb4',
timezone: '+08:00',
decimalNumbers: true,
supportBigNumbers: true,
bigNumberStrings: false
});
console.log('✅ 数据库连接池初始化成功');
if (databaseConfig.dialect === 'sqlite') {
// SQLite配置
this.db = new sqlite3.Database(databaseConfig.storage);
console.log('✅ SQLite数据库连接成功');
} else {
// MySQL配置
this.pool = mysql.createPool({
host: databaseConfig.host,
port: databaseConfig.port,
user: databaseConfig.username,
password: databaseConfig.password,
database: databaseConfig.database,
connectionLimit: databaseConfig.pool.max,
acquireTimeout: databaseConfig.pool.acquire,
timeout: databaseConfig.pool.idle,
charset: 'utf8mb4',
timezone: '+08:00',
decimalNumbers: true,
supportBigNumbers: true,
bigNumberStrings: false
});
console.log('✅ MySQL数据库连接池初始化成功');
}
} catch (error) {
console.error('❌ 数据库连接初始化失败:', error.message);
console.error('❌ 数据库连接初始化失败:', error.message);
throw error;
}
}
@@ -62,19 +70,36 @@ class DBConnector {
* @returns {Promise} 查询结果
*/
async query(sql, params = []) {
let connection;
try {
connection = await this.getConnection();
const [rows] = await connection.execute(sql, params);
return rows;
} catch (error) {
console.error('SQL执行失败:', error.message);
console.error('SQL:', sql);
console.error('参数:', params);
throw error;
} finally {
if (connection) {
connection.release();
if (databaseConfig.dialect === 'sqlite') {
// SQLite查询实现
return new Promise((resolve, reject) => {
this.db.all(sql, params, (err, rows) => {
if (err) {
console.error('❌ SQL执行失败:', err.message);
console.error('SQL:', sql);
console.error('参数:', params);
reject(err);
} else {
resolve(rows);
}
});
});
} else {
// MySQL查询实现
let connection;
try {
connection = await this.getConnection();
const [rows] = await connection.execute(sql, params);
return rows;
} catch (error) {
console.error('❌ SQL执行失败:', error.message);
console.error('SQL:', sql);
console.error('参数:', params);
throw error;
} finally {
if (connection) {
connection.release();
}
}
}
}

View File

@@ -0,0 +1,278 @@
# 爱鉴花后台管理系统 API 接口文档
基于 OpenAPI 3.0 规范
## 基础信息
- **Base URL**: `http://localhost:3200/api`
- **认证方式**: Bearer Token (JWT)
- **响应格式**: JSON
## 统一响应格式
所有接口都遵循以下响应格式:
```json
{
"code": 200,
"message": "操作成功",
"data": {}
}
```
## 认证接口
### 管理员登录
**POST** `/auth/login`
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| login | string | 是 | 用户名/手机号/邮箱 |
| password | string | 是 | 密码 |
**响应示例**:
```json
{
"code": 200,
"message": "登录成功",
"data": {
"user_id": 1,
"username": "admin",
"user_type": "admin",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
```
## 用户管理接口
### 获取用户列表
**GET** `/users`
**权限要求**: 管理员
**查询参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| page | number | 否 | 页码默认1 |
| limit | number | 否 | 每页数量默认10 |
| keyword | string | 否 | 搜索关键词 |
| user_type | string | 否 | 用户类型过滤 |
**响应示例**:
```json
{
"code": 200,
"message": "获取成功",
"data": {
"users": [
{
"id": 1,
"username": "testuser",
"phone": "13800138000",
"email": "test@example.com",
"user_type": "farmer",
"created_at": "2024-01-01T00:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 100,
"pages": 10
}
}
}
```
### 获取用户详情
**GET** `/users/{id}`
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | number | 是 | 用户ID |
### 删除用户
**DELETE** `/users/{id}`
**权限要求**: 管理员
## 商品管理接口
### 获取商品列表
**GET** `/products`
**查询参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| page | number | 否 | 页码默认1 |
| limit | number | 否 | 每页数量默认10 |
| category_id | number | 否 | 分类ID过滤 |
| min_price | number | 否 | 最低价格 |
| max_price | number | 否 | 最高价格 |
| status | number | 否 | 状态过滤 |
### 创建商品
**POST** `/products`
**权限要求**: 管理员
**请求体**:
```json
{
"name": "玫瑰花",
"category_id": 1,
"price": 29.9,
"stock": 100,
"image": "/uploads/roses.jpg",
"description": "新鲜玫瑰花束"
}
```
## 订单管理接口
### 获取订单列表
**GET** `/orders`
**权限要求**: 管理员
**查询参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| page | number | 否 | 页码默认1 |
| limit | number | 否 | 每页数量默认10 |
| status | number | 否 | 订单状态过滤 |
| start_date | string | 否 | 开始日期 |
| end_date | string | 否 | 结束日期 |
### 更新订单状态
**PUT** `/orders/{id}/status`
**权限要求**: 管理员
**请求体**:
```json
{
"payment_status": 1,
"shipping_status": 2
}
```
## 识别记录管理接口
### 获取识别记录列表
**GET** `/identifications`
**权限要求**: 管理员
**查询参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| page | number | 否 | 页码默认1 |
| limit | number | 否 | 每页数量默认10 |
| start_date | string | 否 | 开始日期 |
| end_date | string | 否 | 结束日期 |
| min_confidence | number | 否 | 最低置信度 |
## 数据统计接口
### 获取系统统计概览
**GET** `/admin/statistics/overview`
**权限要求**: 管理员
**响应示例**:
```json
{
"code": 200,
"message": "获取成功",
"data": {
"total_users": 1000,
"new_users_today": 10,
"total_orders": 500,
"total_revenue": 15000.50,
"total_identifications": 2000,
"active_users_today": 50
}
}
```
### 获取趋势数据
**GET** `/admin/statistics/trend`
**查询参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| days | number | 否 | 天数默认7 |
| type | string | 否 | 统计类型users/orders/revenue/identifications |
## 系统配置接口
### 获取系统配置
**GET** `/admin/config`
**权限要求**: 管理员
### 更新系统配置
**PUT** `/admin/config/{key}`
**权限要求**: 管理员
**请求体**:
```json
{
"value": "new_value"
}
```
## 错误码说明
| 错误码 | 说明 |
|--------|------|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 403 | 权限不足 |
| 404 | 资源不存在 |
| 409 | 资源冲突 |
| 500 | 服务器内部错误 |
## 安全要求
1. 所有敏感操作需要管理员权限
2. API请求需要携带有效的JWT Token
3. 密码传输需要加密
4. 文件上传需要验证文件类型和大小
---
*文档版本: 1.0.0*
*最后更新: 2024-01-01*