This commit is contained in:
李鹏宇
2026-06-05 14:22:46 +08:00
parent 127f671af6
commit d40af6c178
+68 -78
View File
@@ -225,107 +225,90 @@ class AiReportTemplate(models.Model):
if self.model_id:
self.model_name = self.model_id.model
# ===== onchange: field_ids 变化时联动更新 =====
@api.onchange('field_ids')
def _onchange_field_ids(self):
"""显示字段变化 → 自动同步 字段列表 + 字段标签 + 列定义"""
if self.field_ids:
self.field_list = json.dumps([f.name for f in self.field_ids], ensure_ascii=False)
self.field_list = json.dumps(
[f.name for f in self.field_ids], ensure_ascii=False)
self.field_labels = json.dumps(
{f.name: f.field_description for f in self.field_ids},
ensure_ascii=False
)
# 同步 column_ids:去重 + 删不在的 + 补缺失的 + 修复空字段
if self.column_ids or self.field_ids:
new_field_ids = set(self.field_ids.ids)
cmds = []
# 1) 收集 column_ids,按 field_id 分组,重复的只保留第一个
kept = {}
for col in self.column_ids:
fid = col.field_id.id if col.field_id else None
if not fid:
cmds.append((2, col.id))
elif fid not in kept:
kept[fid] = col
else:
cmds.append((2, col.id)) # 重复的删掉
# 2) 修复 kept 列中 field_name 为空的列
for fid, col in kept.items():
if not col.field_name:
f = self.field_ids.filtered(lambda r: r.id == fid)
fname = f.name if f else col.field_id.name
cmds.append((1, col.id, {'field_name': fname}))
# 3) 删掉不在 field_ids 里的
for fid, col in kept.items():
if fid not in new_field_ids:
cmds.append((2, col.id))
# 4) 补充 field_ids 里有但 column_ids 里没有的
seq = max((col.sequence for col in self.column_ids), default=0) + 10
for f in self.field_ids:
if f.id not in kept:
cmds.append((0, 0, {
'field_id': f.id,
'field_name': f.name,
'label': f.field_description,
'sequence': seq,
}))
seq += 10
if cmds:
self.column_ids = cmds
ensure_ascii=False)
else:
self.field_list = '[]'
self.field_labels = '{}'
# 同步列定义(onchange 和 write 共用同一套逻辑)
self._sync_columns()
# ===== create / write 同步 =====
# ===== create / write: 保存时联动同步 =====
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('model_id') and not vals.get('model_name'):
model = self.env['ir.model'].browse(vals['model_id'])
vals['model_name'] = model.model
if vals.get('field_ids'):
if 'field_ids' in vals:
self._sync_field_list_from_ids(vals)
records = super().create(vals_list)
for record in records:
if record.field_ids:
record._sync_column_ids_from_field_ids()
record._sync_columns()
return records
def write(self, vals):
if vals.get('model_id') and 'model_name' not in vals:
model = self.env['ir.model'].browse(vals['model_id'])
vals['model_name'] = model.model
if vals.get('field_ids'):
field_ids_changed = 'field_ids' in vals
if field_ids_changed:
self._sync_field_list_from_ids(vals)
result = super().write(vals)
# 任何 write 都触发 column 去重 + 同步(清理历史重复数据 + 确保一致性)
for record in self:
if record.field_ids:
record._sync_column_ids_from_field_ids()
if field_ids_changed:
for record in self:
record._sync_columns()
return result
def _sync_column_ids_from_field_ids(self):
"""根据 field_ids 同步 column_ids:去重 + 删不在的 + 补缺失的 + 修复空字段"""
# ===== 核心:列定义同步 =====
def _sync_columns(self):
"""根据 field_ids 同步 column_ids,保证:
① 列定义 = 显示字段(一对一对应)
② 不重复 → 同一 field_id 只保留一条
③ 不遗漏 → field_ids 有的必须建列
④ 不多余 → field_ids 没的必须删列
⑤ 可修复 → field_name 为空的自动补全"""
self.ensure_one()
new_field_ids = set(self.field_ids.ids)
target_fids = set(self.field_ids.ids)
cmds = []
# 1) 收集 column_ids,按 field_id 分组,重复的只保留第一个
kept = {}
kept = {} # fid → col(去重后唯一保留的列)
# ---- 步骤 1:遍历现有 column_ids,去重 + 清理无 field_id 的脏数据 ----
for col in self.column_ids:
fid = col.field_id.id if col.field_id else None
if not fid:
cmds.append((2, col.id)) # 没有 field_id 的脏数据直接删
elif fid not in kept:
kept[fid] = col
cmds.append((3, col.id)) # 脏数据:无关联 field → 删除
elif fid in kept:
cmds.append((3, col.id)) # 重复:同一 field_id 第二条 → 删除
else:
cmds.append((2, col.id)) # 重复的删掉
# 2) 修复 kept 列中 field_name 为空的列(required=True 约束)
kept[fid] = col # 首条 → 保留
# ---- 步骤 2:删除 field 已不在 field_ids 中的列 ----
for fid, col in list(kept.items()):
if fid not in target_fids:
cmds.append((3, col.id))
del kept[fid] # 从 kept 清除,避免步骤 4 误判
# ---- 步骤 3:修复保留列中 field_name 为空的 ----
for fid, col in kept.items():
if not col.field_name:
f = self.field_ids.filtered(lambda r: r.id == fid)
fname = f.name if f else col.field_id.name
field = self.field_ids.filtered(lambda r: r.id == fid)
fname = field.name if field else col.field_id.name
cmds.append((1, col.id, {'field_name': fname}))
# 3) 删掉不在 field_ids 里的
for fid, col in kept.items():
if fid not in new_field_ids:
cmds.append((2, col.id))
# 4) 补充 field_ids 里有但 column_ids 里没有的
seq = max((col.sequence for col in self.column_ids), default=0) + 10
# ---- 步骤 4:field_ids 中有、但 column_ids 中没有的 → 新建 ----
seq = max(
(c.sequence for c in self.column_ids if c.sequence),
default=0
) + 10
for f in self.field_ids:
if f.id not in kept:
cmds.append((0, 0, {
@@ -335,28 +318,35 @@ class AiReportTemplate(models.Model):
'sequence': seq,
}))
seq += 10
if cmds:
self.column_ids = cmds
# ===== 辅助:从 vals 命令中提取 field_ids 并填充 field_list / field_labels =====
@api.model
def _sync_field_list_from_ids(self, vals):
import json
"""从 vals['field_ids'](Many2many 命令格式)提取 ID 集合,
无条件覆盖 field_list 和 field_labels(因为 field_ids 变了)"""
ids = []
field_cmds = vals['field_ids']
if isinstance(field_cmds, list):
for cmd in field_cmds:
if isinstance(cmd, (list, tuple)):
if cmd[0] == 6:
ids = cmd[2]
if cmd[0] == 6: # (6, 0, ids) → 全量替换
ids = list(cmd[2]) if cmd[2] else []
break
elif cmd[0] == 4:
elif cmd[0] == 4: # (4, id) → 追加
ids.append(cmd[1])
elif cmd[0] == 5: # (5,) → 清空所有
ids = []
break
if ids:
fields_records = self.env['ir.model.fields'].browse(ids)
if not vals.get('field_list'):
vals['field_list'] = json.dumps([f.name for f in fields_records], ensure_ascii=False)
if not vals.get('field_labels'):
vals['field_labels'] = json.dumps(
{f.name: f.field_description for f in fields_records},
ensure_ascii=False
)
vals['field_list'] = json.dumps(
[f.name for f in fields_records], ensure_ascii=False)
vals['field_labels'] = json.dumps(
{f.name: f.field_description for f in fields_records},
ensure_ascii=False)
else:
vals['field_list'] = '[]'
vals['field_labels'] = '{}'