feat: 数据管理列宽可调/行编辑删除/模板导入,CellData 处理日志细化

- 数据表列宽可拖拽 + 新增「操作」列(编辑/删除该行)
- 工具栏新增「模板」「导入」:CSV 按模板字段校验,不一致则导入失败
- 后端 DatabaseManager/MetrixWarehouse 增加行更新/删除/CSV 导入 + 对应路由
- CellData 解压/解析/写库日志细化(逐文件、分批进度)
- 修复 ScriptPanel monaco mysql 深层导入缺类型声明导致的 vue-tsc 构建失败
This commit is contained in:
2026-06-26 05:32:06 +08:00
parent 639bae694d
commit f0bbc77763
7 changed files with 543 additions and 15 deletions
+57
View File
@@ -1,6 +1,7 @@
"""
数据库连接与操作模块
"""
import csv
import pymysql
from contextlib import contextmanager
from typing import Any, Dict, List, Optional, Tuple
@@ -199,6 +200,62 @@ class DatabaseManager:
"total_pages": (total + page_size - 1) // page_size
}
def _row_conditions(self, identifier: Dict[str, Any]) -> Tuple[str, List[Any]]:
"""按整行原值构造 WHERE:NULL 用 IS NULL;调用方再加 LIMIT 1 只影响单行。"""
parts: List[str] = []
params: List[Any] = []
for col, val in identifier.items():
if val is None:
parts.append(f"`{col}` IS NULL")
else:
parts.append(f"`{col}` = %s")
params.append(val)
return (" AND ".join(parts) if parts else "1 = 0"), params
def update_row(self, table_name: str, identifier: Dict[str, Any], values: Dict[str, Any]) -> int:
"""更新单行:按 identifier(原始整行) 定位、LIMIT 1,避免影响重复行。返回影响行数。"""
if not values:
return 0
set_clause = ", ".join(f"`{col}` = %s" for col in values)
set_params = list(values.values())
where_clause, where_params = self._row_conditions(identifier)
sql = f"UPDATE `{table_name}` SET {set_clause} WHERE {where_clause} LIMIT 1"
with self.get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(sql, set_params + where_params)
conn.commit()
return cursor.rowcount
def delete_row(self, table_name: str, identifier: Dict[str, Any]) -> int:
"""删除单行:按 identifier(原始整行) 定位、LIMIT 1。返回影响行数。"""
where_clause, where_params = self._row_conditions(identifier)
sql = f"DELETE FROM `{table_name}` WHERE {where_clause} LIMIT 1"
with self.get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute(sql, where_params)
conn.commit()
return cursor.rowcount
def import_csv(self, file_path: str, table_name: str) -> int:
"""按 CSV 表头列追加导入(列须与表字段一致,由调用方校验)。返回导入行数。"""
with open(file_path, "r", encoding="utf-8-sig", newline="") as handle:
reader = csv.reader(handle)
try:
header = next(reader)
except StopIteration:
return 0
columns = [str(name).strip() for name in header]
width = len(columns)
data: List[Tuple] = []
for row in reader:
if not any(str(cell).strip() for cell in row):
continue
cells = list(row[:width]) + [""] * (width - len(row))
data.append(tuple(cells))
if not data:
return 0
return self.bulk_insert(table_name, columns, data)
def truncate_table(self, table_name: str) -> bool:
"""清空表"""
with self.get_connection() as conn: