refactor: 清理后端冗余代码和未用依赖

This commit is contained in:
2026-05-19 15:46:31 +08:00
parent d30dd0da25
commit 3240027d48
11 changed files with 32 additions and 111 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ CapacityReport 用于每周导入 Excel/CSV 数据,按 `Configure.json` 与 `R
- 后端:FastAPI + Uvicorn + Supervisor
- 前端:Vue 3 + TypeScript + Vite + Naive UI
- 数据库:MySQL 8.0+,通过 PyMySQL + SQLAlchemy 访问
- 数据库:MySQL 8.0+,通过 PyMySQL 访问
- 数据处理:Pandas + OpenPyXL
- 部署:Docker + Docker Compose
+2 -25
View File
@@ -56,11 +56,8 @@ def _dataframe_from_table(db: DatabaseManager, table_name: str) -> pd.DataFrame:
@router.post("/api/database/test")
async def test_database():
db = DatabaseManager(state.config)
try:
success, message = db.test_connection()
return {"success": success, "message": message}
finally:
db.dispose()
success, message = db.test_connection()
return {"success": success, "message": message}
@router.get("/api/database/info")
@@ -70,8 +67,6 @@ async def get_database_info():
return {"success": True, **db.get_server_info()}
except Exception as exc:
return {"success": False, "error": str(exc)}
finally:
db.dispose()
@router.get("/api/database/tables")
@@ -82,8 +77,6 @@ async def get_tables():
return {"tables": db.get_tables()}
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/database/table/info")
@@ -93,8 +86,6 @@ async def get_table_info(table_name: str = Body(..., embed=True)):
return db.get_table_info(table_name)
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/database/table/data")
@@ -110,8 +101,6 @@ async def query_table_data(
return db.query_table(table_name, page, page_size, order_by=order_by, order_dir=order_dir)
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/database/table/query")
@@ -135,8 +124,6 @@ async def query_table_with_filter(
)
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/database/table/truncate")
@@ -147,8 +134,6 @@ async def truncate_table(table_name: str = Body(..., embed=True)):
return {"success": True, "message": f"表 {table_name} 已清空"}
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/database/table/drop")
@@ -159,8 +144,6 @@ async def drop_table(table_name: str = Body(..., embed=True)):
return {"success": True, "message": f"表 {table_name} 已删除"}
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/database/table/drop-all")
@@ -176,8 +159,6 @@ async def drop_all_tables():
}
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/database/execute")
@@ -192,8 +173,6 @@ async def execute_sql(sql: str = Body(..., embed=True)):
raise
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
@router.post("/api/download")
@@ -226,8 +205,6 @@ async def download_table(
raise
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
finally:
db.dispose()
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename_prefix = requested_tables[0] if len(requested_tables) == 1 else "tables"
+6 -10
View File
@@ -19,15 +19,12 @@ async def health_check():
try:
db_manager = DatabaseManager(state.config)
try:
server_info = db_manager.get_server_info()
checks["database"] = {
"status": "ok",
"version": server_info.get("version", "unknown"),
"load_data_infile": server_info.get("load_data_infile", False),
}
finally:
db_manager.dispose()
server_info = db_manager.get_server_info()
checks["database"] = {
"status": "ok",
"version": server_info.get("version", "unknown"),
"load_data_infile": server_info.get("load_data_infile", False),
}
except Exception as exc:
checks["database"] = {"status": "error", "message": str(exc)}
@@ -39,4 +36,3 @@ async def health_check():
"uptime_pid": os.getpid(),
"checks": checks,
}
-2
View File
@@ -4,7 +4,6 @@ import hashlib
import hmac
import json
import time
from pathlib import Path
from typing import Optional
from app.config import BASE_DIR
@@ -81,4 +80,3 @@ def _sign(header: str, payload: str) -> str:
hashlib.sha256,
).digest()
return base64.urlsafe_b64encode(raw).decode().rstrip("=")
+1 -48
View File
@@ -2,14 +2,9 @@
数据库连接与操作模块 - 性能优化版
"""
import pymysql
from urllib.parse import quote
from contextlib import contextmanager
from typing import Any, Dict, List, Optional, Tuple
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
from app.config import AppConfig
@@ -18,33 +13,6 @@ class DatabaseManager:
def __init__(self, config: AppConfig):
self.config = config
self._engine: Optional[sqlalchemy.Engine] = None
@property
def engine(self) -> sqlalchemy.Engine:
"""获取 SQLAlchemy 引擎(带连接池)- 优化配置"""
if self._engine is None:
mysql = self.config.mysql
self._engine = create_engine(
f'mysql+pymysql://'
f'{quote(mysql.user)}:'
f'{quote(mysql.passwd)}@'
f'{quote(mysql.host)}:'
f'{mysql.port}/'
f'{quote(mysql.dbname)}?charset=utf8mb4',
poolclass=QueuePool,
pool_size=10, # 增大连接池
max_overflow=20, # 增大溢出连接
pool_pre_ping=True,
pool_recycle=3600,
echo=False,
# 性能优化参数
connect_args={
'local_infile': True, # 允许 LOAD DATA LOCAL
'autocommit': False,
}
)
return self._engine
@contextmanager
def get_connection(self):
@@ -230,15 +198,6 @@ class DatabaseManager:
"total_pages": (total + page_size - 1) // page_size
}
def delete_rows(self, table_name: str, condition: str, params: List[Any]) -> int:
"""删除符合条件的行"""
with self.get_connection() as conn:
with conn.cursor() as cursor:
sql = f"DELETE FROM `{table_name}` WHERE {condition}"
cursor.execute(sql, params)
conn.commit()
return cursor.rowcount
def truncate_table(self, table_name: str) -> bool:
"""清空表"""
with self.get_connection() as conn:
@@ -272,7 +231,7 @@ class DatabaseManager:
try:
cursor.execute(f"DROP TABLE IF EXISTS `{table}`")
dropped_tables.append(table)
except Exception as e:
except Exception:
# 记录错误但继续删除其他表
pass
@@ -434,9 +393,3 @@ class DatabaseManager:
with conn.cursor() as cursor:
cursor.execute(sql)
conn.commit()
def dispose(self):
"""释放连接池"""
if self._engine:
self._engine.dispose()
self._engine = None
+1 -1
View File
@@ -49,7 +49,7 @@ class HistoryManager:
"""加载历史记录"""
try:
return json.loads(HISTORY_FILE.read_text(encoding='utf-8'))
except:
except (OSError, json.JSONDecodeError):
return []
def _save(self, records: List[Dict[str, Any]]):
-2
View File
@@ -220,8 +220,6 @@ class DataProcessor:
finally:
# 清理临时目录
self._cleanup_temp_dir()
# 释放数据库连接
self.db.dispose()
return self.results
+12 -19
View File
@@ -8,10 +8,12 @@ CapacityReport 统一构建脚本
import os
import sys
import json
import platform
import shutil
import subprocess
import re
import tarfile
import traceback
from pathlib import Path
# ============================================================================
@@ -37,9 +39,7 @@ MYSQL_PORT = 3306
# 应用端口映射
APP_PORT_HOST = 19081
APP_PORT_CONTAINER = 9081
MYSQL_PORT_HOST = 13306
MYSQL_PORT_CONTAINER = 3306
# ============================================================================
# 脚本目录配置
@@ -51,14 +51,12 @@ DIST_DIR = PROJECT_ROOT / "dist"
BUILD_DIR = PROJECT_ROOT / "build"
TEMP_BUILD_DIR = BUILD_DIR / "temp"
# 颜色输出(Windows 支持)
import platform
if platform.system() == 'Windows':
try:
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
except:
except OSError:
pass
class Colors:
@@ -95,7 +93,7 @@ def run_cmd(cmd, check=True, capture_output=False):
text=True
)
return result
except subprocess.CalledProcessError as e:
except subprocess.CalledProcessError:
if check:
print_error(f"命令执行失败: {' '.join(cmd)}")
sys.exit(1)
@@ -198,7 +196,7 @@ def image_exists(image_name):
check=True
)
return image_name in result.stdout
except:
except (subprocess.CalledProcessError, FileNotFoundError):
return False
def format_size(size_bytes):
@@ -668,14 +666,10 @@ def build_full_package():
sys.exit(1)
# 检查 Docker Compose
docker_compose_cmd = None
try:
subprocess.run(["docker", "compose", "version"], capture_output=True, check=True)
docker_compose_cmd = "docker compose"
except:
if check_command("docker-compose"):
docker_compose_cmd = "docker-compose"
else:
except (subprocess.CalledProcessError, FileNotFoundError):
if not check_command("docker-compose"):
print_error("未检测到 Docker Compose")
sys.exit(1)
@@ -689,14 +683,14 @@ def build_full_package():
if not image_exists(python_image):
print_info(f"Python 镜像不存在,正在拉取: {python_image}")
run_cmd(["docker", "pull", python_image])
print_info(f"Python 镜像拉取完成")
print_info("Python 镜像拉取完成")
else:
print_info(f"Python 镜像已存在: {python_image}")
if not image_exists(mysql_image):
print_info(f"MySQL 镜像不存在,正在拉取: {mysql_image}")
run_cmd(["docker", "pull", mysql_image])
print_info(f"MySQL 镜像拉取完成")
print_info("MySQL 镜像拉取完成")
else:
print_info(f"MySQL 镜像已存在: {mysql_image}")
@@ -728,7 +722,7 @@ def build_full_package():
if dockerignore_build.read_text() == dockerignore_root.read_text():
dockerignore_root.unlink()
print_info("已清理临时 .dockerignore")
except:
except OSError:
pass
# 标记 MySQL 镜像(提取版本号)
@@ -844,7 +838,7 @@ def build_update_package():
if not image_exists(python_image):
print_info(f"Python 镜像不存在,正在拉取: {python_image}")
run_cmd(["docker", "pull", python_image])
print_info(f"Python 镜像拉取完成")
print_info("Python 镜像拉取完成")
else:
print_info(f"Python 镜像已存在: {python_image}")
@@ -876,7 +870,7 @@ def build_update_package():
if dockerignore_build.read_text() == dockerignore_root.read_text():
dockerignore_root.unlink()
print_info("已清理临时 .dockerignore")
except:
except OSError:
pass
# 导出镜像
@@ -992,6 +986,5 @@ if __name__ == "__main__":
sys.exit(1)
except Exception as e:
print_error(f"构建失败: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
+8 -1
View File
@@ -1,5 +1,12 @@
# 项目上下文记录
## 2026-05-19:清理后端冗余代码和未用依赖
- `app/database.py` 移除未使用的 SQLAlchemy 连接池、`engine` 属性、`dispose()` 空释放路径和未引用的 `delete_rows()`;数据库访问统一保留现有 PyMySQL 上下文连接。
- `app/api/routers/database.py`、`app/api/routers/health.py` 和 `app/processor.py` 同步去除无效 `dispose()` 调用,避免保留没有实际资源释放意义的样板代码。
- `requirements.txt`、`run.bat` 和 `README.md` 移除 SQLAlchemy 依赖和说明;`build/build.py` 清理无用端口常量、内联导入和宽泛异常捕获。
- 已清理本地 `.ruff_cache/` 与重复的 `ReportScript.sql.bak`;已执行 `.venv\Scripts\python.exe -m compileall app build`、`uvx ruff check .`、`uvx vulture app build --min-confidence 80` 和 `npm run build`,均通过。
## 2026-05-19:移除旧版 HTML 前端和双端口托管
- 删除 `frontend_old/` 旧版 HTML/CSS/JS 前端及其本地 Monaco 资源,项目只保留 Vue 3 新前端。
@@ -324,7 +331,7 @@
### 依赖与清理
- Python 依赖保留当前代码实际使用项:`fastapi`、`uvicorn[standard]`、`python-multipart`、`pymysql`、`sqlalchemy`、`cryptography`、`pandas`、`openpyxl`、`chardet`、`supervisor`。
- Python 依赖保留当前代码实际使用项:`fastapi`、`uvicorn[standard]`、`python-multipart`、`pymysql`、`cryptography`、`pandas`、`openpyxl`、`chardet`、`supervisor`。
- 已移除未使用的 `sqlparse`、`aiofiles`、`python-dateutil`。
- 旧静态目录、根目录打包产物、日志和 Python 编译缓存属于可清理产物,不应提交。
-1
View File
@@ -5,7 +5,6 @@ python-multipart
# Database
pymysql
sqlalchemy
cryptography
# Data processing
+1 -1
View File
@@ -16,7 +16,7 @@ if not exist "%PYTHON_EXE%" (
exit /b 1
)
"%PYTHON_EXE%" -c "import fastapi, uvicorn, pandas, openpyxl, pymysql, sqlalchemy, chardet" >nul 2>&1
"%PYTHON_EXE%" -c "import fastapi, uvicorn, pandas, openpyxl, pymysql, chardet" >nul 2>&1
if errorlevel 1 (
echo [INFO] Installing or repairing Python dependencies...
uv pip install -r requirements.txt