fix: 所有 init_ 方法增加字段级 Dirty Check,相同值不赋值,防止 SQLAlchemy 触发 UPDATE 事件产生冗余审计日志
This commit is contained in:
@ -176,7 +176,28 @@ class PermissionService:
|
||||
db.session.flush() # 获取新插入的 ID
|
||||
print(f"✅ 审计日志菜单已创建 (code: {menu_code})")
|
||||
else:
|
||||
print(f"ℹ️ 审计日志菜单已存在 (code: {menu_code})")
|
||||
# ★★★ Dirty Check:仅当字段真正变化时才 add,避免触发 UPDATE 事件
|
||||
is_dirty = False
|
||||
if existing_menu.parent_id != 0:
|
||||
existing_menu.parent_id = 0
|
||||
is_dirty = True
|
||||
if existing_menu.name != '审计日志':
|
||||
existing_menu.name = '审计日志'
|
||||
is_dirty = True
|
||||
if existing_menu.path != '/system/audit':
|
||||
existing_menu.path = '/system/audit'
|
||||
is_dirty = True
|
||||
if existing_menu.sort_order != 110:
|
||||
existing_menu.sort_order = 110
|
||||
is_dirty = True
|
||||
if existing_menu.is_visible != True:
|
||||
existing_menu.is_visible = True
|
||||
is_dirty = True
|
||||
if is_dirty:
|
||||
db.session.add(existing_menu)
|
||||
print(f"🔄 审计日志菜单已更新 (code: {menu_code})")
|
||||
else:
|
||||
print(f"ℹ️ 审计日志菜单已存在,无需更新 (code: {menu_code})")
|
||||
|
||||
# 2. 为超级管理员赋予审计日志菜单权限
|
||||
role_code = 'SUPER_ADMIN'
|
||||
@ -230,7 +251,14 @@ class PermissionService:
|
||||
db.session.flush()
|
||||
print(f"✅ 盘点管理顶级菜单已创建")
|
||||
else:
|
||||
print(f"ℹ️ 盘点管理顶级菜单已存在")
|
||||
is_dirty = False
|
||||
if stocktake_menu.parent_id != 0: stocktake_menu.parent_id = 0; is_dirty = True
|
||||
if stocktake_menu.name != '盘点管理': stocktake_menu.name = '盘点管理'; is_dirty = True
|
||||
if stocktake_menu.path != '/stocktake': stocktake_menu.path = '/stocktake'; is_dirty = True
|
||||
if stocktake_menu.sort_order != 30: stocktake_menu.sort_order = 30; is_dirty = True
|
||||
if stocktake_menu.is_visible != True: stocktake_menu.is_visible = True; is_dirty = True
|
||||
if is_dirty: db.session.add(stocktake_menu); print(f"🔄 盘点管理顶级菜单已更新")
|
||||
else: print(f"ℹ️ 盘点管理顶级菜单已存在")
|
||||
|
||||
# 2. 创建子菜单:盲盘作业
|
||||
stocktake_op_code = 'inventory_stocktake'
|
||||
@ -248,7 +276,13 @@ class PermissionService:
|
||||
db.session.flush()
|
||||
print(f"✅ 盲盘作业菜单已创建")
|
||||
else:
|
||||
print(f"ℹ️ 盲盘作业菜单已存在")
|
||||
is_dirty = False
|
||||
if stocktake_op_menu.name != '盲盘作业': stocktake_op_menu.name = '盲盘作业'; is_dirty = True
|
||||
if stocktake_op_menu.path != '/stocktake/operation': stocktake_op_menu.path = '/stocktake/operation'; is_dirty = True
|
||||
if stocktake_op_menu.sort_order != 1: stocktake_op_menu.sort_order = 1; is_dirty = True
|
||||
if stocktake_op_menu.is_visible != True: stocktake_op_menu.is_visible = True; is_dirty = True
|
||||
if is_dirty: db.session.add(stocktake_op_menu); print(f"🔄 盲盘作业菜单已更新")
|
||||
else: print(f"ℹ️ 盲盘作业菜单已存在")
|
||||
|
||||
# 3. 为盲盘作业添加操作权限元素
|
||||
stocktake_op_element = SysElement.query.filter_by(
|
||||
@ -265,7 +299,11 @@ class PermissionService:
|
||||
db.session.add(stocktake_op_element)
|
||||
print(f"✅ 盲盘作业操作权限已创建")
|
||||
else:
|
||||
print(f"ℹ️ 盲盘作业操作权限已存在")
|
||||
is_dirty = False
|
||||
if stocktake_op_element.name != '盲盘操作': stocktake_op_element.name = '盲盘操作'; is_dirty = True
|
||||
if stocktake_op_element.element_type != 'operation': stocktake_op_element.element_type = 'operation'; is_dirty = True
|
||||
if is_dirty: db.session.add(stocktake_op_element); print(f"🔄 盲盘作业操作权限已更新")
|
||||
else: print(f"ℹ️ 盲盘作业操作权限已存在")
|
||||
|
||||
# 4. 创建子菜单:盈亏调整
|
||||
adjustment_code = 'stock_adjustment'
|
||||
@ -283,7 +321,13 @@ class PermissionService:
|
||||
db.session.flush()
|
||||
print(f"✅ 盈亏调整菜单已创建")
|
||||
else:
|
||||
print(f"ℹ️ 盈亏调整菜单已存在")
|
||||
is_dirty = False
|
||||
if adjustment_menu.name != '盈亏调整': adjustment_menu.name = '盈亏调整'; is_dirty = True
|
||||
if adjustment_menu.path != '/stocktake/adjustment': adjustment_menu.path = '/stocktake/adjustment'; is_dirty = True
|
||||
if adjustment_menu.sort_order != 2: adjustment_menu.sort_order = 2; is_dirty = True
|
||||
if adjustment_menu.is_visible != True: adjustment_menu.is_visible = True; is_dirty = True
|
||||
if is_dirty: db.session.add(adjustment_menu); print(f"🔄 盈亏调整菜单已更新")
|
||||
else: print(f"ℹ️ 盈亏调整菜单已存在")
|
||||
|
||||
# 5. 为盈亏调整添加列表权限元素 (stock_adjustment:list)
|
||||
adjustment_list_element = SysElement.query.filter_by(
|
||||
@ -300,7 +344,11 @@ class PermissionService:
|
||||
db.session.add(adjustment_list_element)
|
||||
print(f"✅ 盈亏调整列表权限已创建")
|
||||
else:
|
||||
print(f"ℹ️ 盈亏调整列表权限已存在")
|
||||
is_dirty = False
|
||||
if adjustment_list_element.name != '盈亏列表': adjustment_list_element.name = '盈亏列表'; is_dirty = True
|
||||
if adjustment_list_element.element_type != 'element': adjustment_list_element.element_type = 'element'; is_dirty = True
|
||||
if is_dirty: db.session.add(adjustment_list_element); print(f"🔄 盈亏调整列表权限已更新")
|
||||
else: print(f"ℹ️ 盈亏调整列表权限已存在")
|
||||
|
||||
# 6. 为盈亏调整添加操作权限元素 (stock_adjustment:operation)
|
||||
adjustment_op_element = SysElement.query.filter_by(
|
||||
@ -317,7 +365,11 @@ class PermissionService:
|
||||
db.session.add(adjustment_op_element)
|
||||
print(f"✅ 盈亏调整操作权限已创建")
|
||||
else:
|
||||
print(f"ℹ️ 盈亏调整操作权限已存在")
|
||||
is_dirty = False
|
||||
if adjustment_op_element.name != '盈亏操作': adjustment_op_element.name = '盈亏操作'; is_dirty = True
|
||||
if adjustment_op_element.element_type != 'operation': adjustment_op_element.element_type = 'operation'; is_dirty = True
|
||||
if is_dirty: db.session.add(adjustment_op_element); print(f"🔄 盈亏调整操作权限已更新")
|
||||
else: print(f"ℹ️ 盈亏调整操作权限已存在")
|
||||
|
||||
# 7. 为超级管理员分配所有盘点相关权限
|
||||
menu_codes = [stocktake_mgmt_code, stocktake_op_code, adjustment_code]
|
||||
@ -491,13 +543,19 @@ class PermissionService:
|
||||
db.session.delete(e)
|
||||
db.session.delete(dup)
|
||||
|
||||
# 第三步:强制重新设置所有子菜单的 parent_id,确保没有遗漏
|
||||
# 改为对象级更新以触发审计事件
|
||||
# 第三步:仅当子菜单 parent_id 有误时才更新(Dirty Check)
|
||||
# 遍历所有子菜单,只在 parent_id 需要修正时才触碰对象
|
||||
child_codes = [m[0] for m in menu_defs if m[3] is not None]
|
||||
child_menus = SysMenu.query.filter(SysMenu.code.in_(child_codes)).all()
|
||||
for m in child_menus:
|
||||
m.parent_id = None
|
||||
# 只有 parent_id 为 0 或 None(即没有正确挂载父菜单)时才更新
|
||||
if m.parent_id == 0 or m.parent_id is None:
|
||||
m.parent_id = None # SQLAlchemy 设为 None 表示挂载到根(parent_id=None)
|
||||
db.session.add(m)
|
||||
print(f"🔧 修正子菜单 parent_id: {m.code} (parent_id → None)")
|
||||
|
||||
# 创建或更新菜单
|
||||
# 第四步:创建或更新菜单(带字段级 Dirty Check)
|
||||
# 只有至少有一个字段真正变化了才 add,避免 SQLAlchemy 产生 UPDATE 事件
|
||||
menu_map = {} # code -> menu obj
|
||||
|
||||
for code, name, path, parent_code, sort_order in menu_defs:
|
||||
@ -508,21 +566,38 @@ class PermissionService:
|
||||
db.session.flush()
|
||||
print(f"✅ 菜单已创建: {name} ({code})")
|
||||
else:
|
||||
# 更新已有菜单的属性
|
||||
menu.name = name
|
||||
menu.path = path
|
||||
menu.sort_order = sort_order
|
||||
# ★★★ 字段级 Dirty Check:逐字段比较,仅在值真正变化时赋值
|
||||
is_dirty = False
|
||||
|
||||
if menu.name != name:
|
||||
menu.name = name
|
||||
is_dirty = True
|
||||
if menu.path != path:
|
||||
menu.path = path
|
||||
is_dirty = True
|
||||
if menu.sort_order != sort_order:
|
||||
menu.sort_order = sort_order
|
||||
is_dirty = True
|
||||
|
||||
# 只有至少一个字段变化了才 add(触发 UPDATE)
|
||||
if is_dirty:
|
||||
db.session.add(menu)
|
||||
print(f"🔄 菜单已更新: {name} ({code})")
|
||||
|
||||
menu_map[code] = menu
|
||||
|
||||
# 设置 parent_id
|
||||
# 第五步:设置 parent_id(带 Dirty Check,只在值真正变化时更新)
|
||||
for code, name, path, parent_code, sort_order in menu_defs:
|
||||
if parent_code and parent_code in menu_map:
|
||||
menu = menu_map[code]
|
||||
parent = menu_map[parent_code]
|
||||
menu.parent_id = parent.id
|
||||
# 只有 parent_id 实际变化了才赋值,避免重复触发 UPDATE
|
||||
if menu.parent_id != parent.id:
|
||||
menu.parent_id = parent.id
|
||||
db.session.add(menu)
|
||||
print(f"🔗 菜单 {code} 已挂载到父菜单 {parent_code} (id={parent.id})")
|
||||
|
||||
# 为超级管理员分配所有菜单权限
|
||||
# 第六步:为超级管理员分配顶级菜单权限(只做 INSERT,不触碰已存在的记录)
|
||||
for code, name, path, parent_code, sort_order in menu_defs:
|
||||
if parent_code is None: # 只分配顶级菜单
|
||||
existing_perm = SysRolePermission.query.filter_by(
|
||||
|
||||
Reference in New Issue
Block a user