You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
11 KiB
264 lines
11 KiB
import json
|
|
import logging
|
|
from util.mysql_utils import mysql_client
|
|
|
|
# 配置日志
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class GraphStyleService:
|
|
@staticmethod
|
|
def _get_or_create_group(group_name: str) -> int:
|
|
"""内部辅助方法:获取或创建方案组 ID"""
|
|
if not group_name or group_name.strip() == "":
|
|
group_name = "默认方案"
|
|
|
|
group_name = group_name.strip()
|
|
|
|
# 1. 查询是否存在
|
|
check_sql = "SELECT id FROM graph_style_groups WHERE group_name = %s LIMIT 1"
|
|
existing = mysql_client.execute_query(check_sql, (group_name,))
|
|
if existing:
|
|
return int(existing[0]['id'])
|
|
|
|
# 2. 不存在则插入
|
|
insert_sql = "INSERT INTO graph_style_groups (group_name, is_active, is_default) VALUES (%s, %s, %s)"
|
|
mysql_client.execute_update(insert_sql, (group_name, False, False))
|
|
|
|
# 3. 获取新生成的 ID
|
|
final_check = mysql_client.execute_query(check_sql, (group_name,))
|
|
return int(final_check[0]['id']) if final_check else 1
|
|
|
|
@staticmethod
|
|
def create_config(canvas_name: str, current_label: str, styles_dict: dict, group_name: str = None) -> bool:
|
|
"""【纯新增】用于另存为或初始保存"""
|
|
config_json = json.dumps(styles_dict, ensure_ascii=False)
|
|
target_group_id = GraphStyleService._get_or_create_group(group_name)
|
|
|
|
sql = """
|
|
INSERT INTO graph_configs (canvas_name, current_label, config_json, group_id)
|
|
VALUES (%s, %s, %s, %s)
|
|
"""
|
|
affected_rows = mysql_client.execute_update(sql, (canvas_name, current_label, config_json, target_group_id))
|
|
return affected_rows > 0
|
|
|
|
@staticmethod
|
|
def update_config(config_id: int, canvas_name: str, current_label: str, styles_dict: dict,
|
|
group_name: str = None, is_auto_save: bool = False, target_group_id: int = None) -> bool:
|
|
"""
|
|
核心更新逻辑:支持精准 ID 移动,优化了逻辑优先级判断
|
|
"""
|
|
if not config_id:
|
|
logger.error("更新失败:缺少 config_id")
|
|
return False
|
|
|
|
config_json_str = json.dumps(styles_dict, ensure_ascii=False)
|
|
|
|
try:
|
|
# --- 步骤 1:查询当前数据库状态 ---
|
|
curr_sql = "SELECT group_id, canvas_name, current_label, config_json FROM graph_configs WHERE id = %s"
|
|
current_data = mysql_client.execute_query(curr_sql, (config_id,))
|
|
|
|
if not current_data:
|
|
logger.warning(f"更新失败:找不到 ID 为 {config_id} 的配置")
|
|
return False
|
|
|
|
curr_row = current_data[0]
|
|
old_group_id = int(curr_row['group_id'])
|
|
|
|
# --- 步骤 2:确定目标组 ID (调整优先级) ---
|
|
# 优先级 1: 只要传了 target_group_id,就说明是移动操作,优先级最高
|
|
if target_group_id is not None:
|
|
final_group_id = int(target_group_id)
|
|
logger.info(f"【移动模式】配置 {config_id}: 强制设定目标组 ID 为 {final_group_id}")
|
|
|
|
# 优先级 2: 自动保存模式下,锁定 group_id 不允许变动
|
|
elif is_auto_save:
|
|
final_group_id = old_group_id
|
|
logger.debug(f"【自保模式】配置 {config_id}: 锁定原组 ID {final_group_id}")
|
|
|
|
# 优先级 3: 传了 group_name 但没传 target_group_id (旧版移动逻辑)
|
|
elif group_name:
|
|
final_group_id = GraphStyleService._get_or_create_group(group_name)
|
|
logger.info(f"【名称模式】配置 {config_id}: 根据名称 [{group_name}] 获得 ID {final_group_id}")
|
|
|
|
# 兜底:保持不变
|
|
else:
|
|
final_group_id = old_group_id
|
|
|
|
# --- 步骤 3:差异比对 ---
|
|
# 增加对数据一致性的判定
|
|
has_changed = (
|
|
int(final_group_id) != old_group_id or
|
|
canvas_name != curr_row['canvas_name'] or
|
|
current_label != curr_row['current_label'] or
|
|
config_json_str != curr_row['config_json']
|
|
)
|
|
|
|
if not has_changed:
|
|
logger.info(
|
|
f"配置 {config_id} 内容无变化 (最终目标ID:{final_group_id}, 原ID:{old_group_id}),跳过数据库更新")
|
|
return True
|
|
|
|
# --- 步骤 4:执行更新 ---
|
|
sql = """
|
|
UPDATE graph_configs
|
|
SET group_id = %s, canvas_name = %s, current_label = %s, config_json = %s
|
|
WHERE id = %s
|
|
"""
|
|
params = (final_group_id, canvas_name, current_label, config_json_str, config_id)
|
|
|
|
affected_rows = mysql_client.execute_update(sql, params)
|
|
|
|
if affected_rows > 0:
|
|
logger.info(f"更新成功,ID: {config_id}, 归属组已变更为: {final_group_id}")
|
|
return True
|
|
else:
|
|
logger.error(f"数据库更新执行成功但受影响行数为 0,ID: {config_id}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
logger.error(f"Service 层更新异常: {str(e)}", exc_info=True)
|
|
return False
|
|
|
|
@staticmethod
|
|
def get_grouped_configs() -> list:
|
|
"""获取嵌套结构的方案列表"""
|
|
groups_sql = "SELECT id, group_name, is_active, is_default FROM graph_style_groups ORDER BY is_default DESC, id ASC"
|
|
groups = mysql_client.execute_query(groups_sql) or []
|
|
|
|
configs_sql = "SELECT id, group_id, canvas_name, current_label, config_json, create_time FROM graph_configs"
|
|
configs = mysql_client.execute_query(configs_sql) or []
|
|
|
|
# 格式化配置数据
|
|
for conf in configs:
|
|
conf['styles'] = json.loads(conf['config_json']) if conf.get('config_json') else {}
|
|
# 保持 key 简洁
|
|
if 'config_json' in conf:
|
|
del conf['config_json']
|
|
if conf.get('create_time') and not isinstance(conf['create_time'], str):
|
|
conf['create_time'] = conf['create_time'].strftime('%Y-%m-%d %H:%M:%S')
|
|
|
|
# 组装嵌套结构
|
|
for g in groups:
|
|
g['is_active'] = bool(g['is_active'])
|
|
g['is_default'] = bool(g['is_default'])
|
|
g['configs'] = [c for c in configs if c['group_id'] == g['id']]
|
|
g['expanded'] = g['is_active']
|
|
return groups
|
|
|
|
@staticmethod
|
|
def get_active_configs() -> list:
|
|
"""
|
|
获取 is_active = 1 的方案组及其配置项
|
|
返回长度为 0 或 1 的列表(因为通常只有一个激活组)
|
|
"""
|
|
# 1. 查询 is_active = 1 的组(按 id 排序,取第一个以防有多个)
|
|
group_sql = """
|
|
SELECT id, group_name, is_active, is_default
|
|
FROM graph_style_groups
|
|
WHERE is_active = 1
|
|
ORDER BY id ASC
|
|
LIMIT 1
|
|
"""
|
|
groups = mysql_client.execute_query(group_sql) or []
|
|
|
|
if not groups:
|
|
return [] # 没有激活的组
|
|
|
|
group = groups[0]
|
|
group_id = group['id']
|
|
|
|
# 2. 查询该组下的所有配置
|
|
configs_sql = """
|
|
SELECT id, group_id, canvas_name, current_label, config_json, create_time
|
|
FROM graph_configs
|
|
WHERE group_id = %s
|
|
"""
|
|
configs = mysql_client.execute_query(configs_sql, (group_id,)) or []
|
|
|
|
# 3. 处理配置项
|
|
for conf in configs:
|
|
if conf.get('config_json'):
|
|
try:
|
|
conf['styles'] = json.loads(conf['config_json'])
|
|
except (TypeError, ValueError):
|
|
conf['styles'] = {}
|
|
del conf['config_json']
|
|
|
|
if conf.get('create_time') and not isinstance(conf['create_time'], str):
|
|
conf['create_time'] = conf['create_time'].strftime('%Y-%m-%d %H:%M:%S')
|
|
|
|
# 4. 组装结果
|
|
group['configs'] = configs
|
|
|
|
return [group] # 返回单元素列表,保持接口兼容性
|
|
@staticmethod
|
|
def apply_group_all(group_id: int) -> bool:
|
|
"""切换当前激活的方案组"""
|
|
try:
|
|
# 重置所有组的激活状态
|
|
mysql_client.execute_update("UPDATE graph_style_groups SET is_active = %s", (False,))
|
|
# 激活目标组
|
|
affected_rows = mysql_client.execute_update(
|
|
"UPDATE graph_style_groups SET is_active = %s WHERE id = %s",
|
|
(True, group_id)
|
|
)
|
|
return affected_rows > 0
|
|
except Exception as e:
|
|
logger.error(f"应用全案异常: {str(e)}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def set_default_group(group_id: int) -> bool:
|
|
"""设为默认方案组"""
|
|
try:
|
|
mysql_client.execute_update("UPDATE graph_style_groups SET is_default = %s", (False,))
|
|
affected_rows = mysql_client.execute_update(
|
|
"UPDATE graph_style_groups SET is_default = %s WHERE id = %s",
|
|
(True, group_id)
|
|
)
|
|
return affected_rows > 0
|
|
except Exception as e:
|
|
logger.error(f"设置默认方案异常: {str(e)}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def delete_group(group_id: int) -> bool:
|
|
"""级联删除组及其下的所有配置"""
|
|
try:
|
|
# 先删配置,再删组(如果没设外键级联)
|
|
mysql_client.execute_update("DELETE FROM graph_configs WHERE group_id = %s", (group_id,))
|
|
affected_rows = mysql_client.execute_update("DELETE FROM graph_style_groups WHERE id = %s", (group_id,))
|
|
return affected_rows > 0
|
|
except Exception as e:
|
|
logger.error(f"删除方案组异常: {str(e)}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def delete_config(config_id: int) -> bool:
|
|
"""删除单个配置"""
|
|
try:
|
|
affected_rows = mysql_client.execute_update("DELETE FROM graph_configs WHERE id = %s", (config_id,))
|
|
return affected_rows > 0
|
|
except Exception as e:
|
|
logger.error(f"删除配置异常: {str(e)}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def batch_delete_configs(config_ids: list) -> int:
|
|
"""批量删除"""
|
|
if not config_ids: return 0
|
|
try:
|
|
placeholders = ', '.join(['%s'] * len(config_ids))
|
|
sql = f"DELETE FROM graph_configs WHERE id IN ({placeholders})"
|
|
return mysql_client.execute_update(sql, tuple(config_ids))
|
|
except Exception as e:
|
|
logger.error(f"批量删除异常: {str(e)}")
|
|
return 0
|
|
|
|
@staticmethod
|
|
def get_group_list() -> list:
|
|
"""简单的方案名称列表"""
|
|
sql = "SELECT id, group_name, is_active, is_default FROM graph_style_groups ORDER BY is_default DESC, id DESC"
|
|
return mysql_client.execute_query(sql) or []
|