diff --git a/.devops/config.yaml b/.devops/config.yaml
index 01e4883..469b45d 100644
--- a/.devops/config.yaml
+++ b/.devops/config.yaml
@@ -30,6 +30,15 @@ dingtalk:
access_token: ed3533e05cf13e090c098436ee6cd52b2adfa2d85b5b2b9da1ae2bccdaecb8f3
secret: SEC66372694e16e7e931f53aefb4b847b7fb6c42350a10f0f27fbf4151785353261
+# 数据库配置(用于数据库管理页面)
+database:
+ container_name: ruoyi-mysql # MySQL 容器名称
+ host: localhost
+ port: 3306
+ user: root
+ password: password
+ charset: utf8mb4
+
# 基础设施服务配置(只部署一次)
infrastructure:
- name: ruoyi-mysql
diff --git a/.devops/monitor.py b/.devops/monitor.py
index 6824fbc..ff208f3 100644
--- a/.devops/monitor.py
+++ b/.devops/monitor.py
@@ -17,6 +17,15 @@ from datetime import datetime
from pathlib import Path
from flask import Flask, request, jsonify, render_template_string
+# 数据库相关导入
+try:
+ import pymysql
+ pymysql.install_as_MySQLdb()
+ PYMYSQL_AVAILABLE = True
+except ImportError:
+ PYMYSQL_AVAILABLE = False
+ print("警告: pymysql 未安装,数据库管理功能将不可用。请运行: pip install pymysql")
+
# 添加当前目录到 Python 路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
@@ -862,7 +871,7 @@ class DeploymentServer:
📖 使用说明
触发部署:点击下方表格中的"部署链接",或直接访问 http://IP:9999/项目名称
示例:http://IP:9999/tuoheng-device 触发 tuoheng-device 项目部署
- 查看日志:点击这里查看部署日志 | 查看容器日志
+ 查看日志:点击这里查看部署日志 | 查看容器日志 | 数据库管理
🌐 服务访问入口
@@ -1466,11 +1475,553 @@ class DeploymentServer:
except Exception as e:
return jsonify({'logs': [], 'error': str(e)})
+ @self.app.route('/database')
+ def view_database():
+ """数据库管理页面"""
+ if not PYMYSQL_AVAILABLE:
+ return '''
+
+
+
+
+ 数据库管理 - 错误
+
+
+ 数据库管理功能不可用
+ pymysql 模块未安装,请运行: pip install pymysql
+ 返回首页
+
+
+ '''
+
+ # 获取数据库配置
+ db_config = self.monitor.config.get('database', {})
+ container_name = db_config.get('container_name', 'ruoyi-mysql')
+
+ html = f'''
+
+
+
+
+ 数据库管理
+
+
+
+
+
+
+
+
说明:
+
+ - 点击数据库名称查看该数据库的所有表
+ - 点击表名查看表数据(默认显示前100条)
+ - 可以在SQL编辑器中执行自定义SQL查询
+ - ⚠️ 请谨慎执行修改数据的SQL语句
+
+
+
+
+
+
+
+
+
💻 SQL 查询
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ '''
+ return html
+
+ @self.app.route('/api/database/list')
+ def get_database_list():
+ """获取数据库列表API"""
+ if not PYMYSQL_AVAILABLE:
+ return jsonify({'success': False, 'error': 'pymysql 未安装'})
+
+ try:
+ db_config = self.monitor.config.get('database', {})
+ container_name = db_config.get('container_name', 'ruoyi-mysql')
+
+ # 通过 docker exec 连接到容器内的 MySQL
+ cmd = f"docker exec {container_name} mysql -uroot -ppassword -e 'SHOW DATABASES;'"
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)
+
+ if result.returncode != 0:
+ return jsonify({'success': False, 'error': f'连接数据库失败: {result.stderr}'})
+
+ # 解析数据库列表
+ databases = []
+ for line in result.stdout.strip().split('\n')[1:]: # 跳过第一行标题
+ db_name = line.strip()
+ if db_name and db_name not in ['information_schema', 'performance_schema', 'mysql', 'sys']:
+ databases.append(db_name)
+
+ return jsonify({'success': True, 'databases': databases})
+ except Exception as e:
+ return jsonify({'success': False, 'error': str(e)})
+
+ @self.app.route('/api/database/tables')
+ def get_table_list():
+ """获取表列表API"""
+ if not PYMYSQL_AVAILABLE:
+ return jsonify({'success': False, 'error': 'pymysql 未安装'})
+
+ try:
+ db_name = request.args.get('db')
+ if not db_name:
+ return jsonify({'success': False, 'error': '缺少数据库名称'})
+
+ db_config = self.monitor.config.get('database', {})
+ container_name = db_config.get('container_name', 'ruoyi-mysql')
+
+ # 通过 docker exec 连接到容器内的 MySQL
+ cmd = f"docker exec {container_name} mysql -uroot -ppassword -e 'USE {db_name}; SHOW TABLES;'"
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)
+
+ if result.returncode != 0:
+ return jsonify({'success': False, 'error': f'查询表列表失败: {result.stderr}'})
+
+ # 解析表列表
+ tables = []
+ for line in result.stdout.strip().split('\n')[1:]: # 跳过第一行标题
+ table_name = line.strip()
+ if table_name:
+ tables.append(table_name)
+
+ return jsonify({'success': True, 'tables': tables})
+ except Exception as e:
+ return jsonify({'success': False, 'error': str(e)})
+
+ @self.app.route('/api/database/query', methods=['POST'])
+ def execute_query():
+ """执行SQL查询API"""
+ if not PYMYSQL_AVAILABLE:
+ return jsonify({'success': False, 'error': 'pymysql 未安装'})
+
+ try:
+ data = request.get_json()
+ database = data.get('database')
+ sql = data.get('sql', '').strip()
+
+ if not database or not sql:
+ return jsonify({'success': False, 'error': '缺少必要参数'})
+
+ db_config = self.monitor.config.get('database', {})
+ container_name = db_config.get('container_name', 'ruoyi-mysql')
+
+ # 转义SQL中的单引号
+ sql_escaped = sql.replace("'", "'\\''")
+
+ # 通过 docker exec 执行 SQL
+ cmd = f"docker exec {container_name} mysql -uroot -ppassword {database} -e '{sql_escaped}' --batch"
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
+
+ if result.returncode != 0:
+ return jsonify({'success': False, 'error': f'SQL执行失败: {result.stderr}'})
+
+ # 解析查询结果
+ lines = result.stdout.strip().split('\n')
+ if not lines or not lines[0]:
+ return jsonify({'success': True, 'data': [], 'columns': [], 'rows': 0})
+
+ # 第一行是列名
+ columns = lines[0].split('\t')
+
+ # 解析数据行
+ data_rows = []
+ for line in lines[1:]:
+ if line:
+ values = line.split('\t')
+ row_dict = {}
+ for i, col in enumerate(columns):
+ row_dict[col] = values[i] if i < len(values) else None
+ data_rows.append(row_dict)
+
+ return jsonify({
+ 'success': True,
+ 'data': data_rows,
+ 'columns': columns,
+ 'rows': len(data_rows)
+ })
+ except Exception as e:
+ return jsonify({'success': False, 'error': str(e)})
+
@self.app.route('/')
def deploy_project(project_name):
"""触发项目部署"""
# 避免与其他路由冲突
- if project_name in ['logs', 'api', 'containers', 'container-logs']:
+ if project_name in ['logs', 'api', 'containers', 'container-logs', 'database']:
return jsonify({'code': 404, 'message': '路径不存在'})
Logger.info(f"收到HTTP部署请求: {project_name}")
diff --git a/.devops/pmstart.sh b/.devops/pmstart.sh
index b6efc47..8746c51 100755
--- a/.devops/pmstart.sh
+++ b/.devops/pmstart.sh
@@ -58,6 +58,11 @@ if ! python3 -c "import flask" 2>/dev/null; then
python3 -m pip install --user --break-system-packages flask 2>/dev/null || \
python3 -m pip install --user flask
fi
+if ! python3 -c "import pymysql" 2>/dev/null; then
+ echo "安装 PyMySQL(用于数据库管理功能)..."
+ python3 -m pip install --user --break-system-packages pymysql 2>/dev/null || \
+ python3 -m pip install --user pymysql
+fi
echo "✓ Python 依赖检查完成"
# 5. 删除已存在的 PM2 进程