diff --git a/yuthon_issue/models/issue_library.py b/yuthon_issue/models/issue_library.py
index 903a7ec93..85b87c97f 100644
--- a/yuthon_issue/models/issue_library.py
+++ b/yuthon_issue/models/issue_library.py
@@ -170,6 +170,78 @@ class IssueLibrary(models.Model):
for record in issue_active_ids:
record._compute_meeting()
+ def remove_duplicate_lines(self):
+ """删除关联流程和关联会议中的重复明细行,重复的只保留一条(保留创建日期最早的)"""
+ total_removed = 0
+ detail_msg = []
+
+ for rec in self:
+ # ========== 1. 去重:关联流程明细 (issue.library.approval.line) ==========
+ # 重复判断依据:同一议题下,code 相同视为重复
+ approval_lines = rec.issue_library_approval_line_ids
+ if approval_lines:
+ # 按 code 分组,找出每组中需要删除的多余记录
+ seen_codes = {} # {code: [line_ids]}
+ for line in approval_lines:
+ key = line.code or ''
+ if key not in seen_codes:
+ seen_codes[key] = []
+ seen_codes[key].append(line.id)
+
+ approval_to_remove = []
+ for code_val, line_ids in seen_codes.items():
+ if len(line_ids) > 1:
+ # 按创建时间排序,保留第一条(最早),其余删除
+ sorted_lines = self.env['issue.library.approval.line'].browse(line_ids).sorted(key=lambda l: l.create_date or '')
+ approval_to_remove.extend(sorted_lines[1:].ids)
+
+ if approval_to_remove:
+ self.env['issue.library.approval.line'].browse(approval_to_remove).unlink()
+ removed_count = len(approval_to_remove)
+ total_removed += removed_count
+ detail_msg.append(f'议题【{rec.name or rec.code}】关联流程去重删除 {removed_count} 条')
+
+ # ========== 2. 去重:关联会议明细 (issue.library.room.line) ==========
+ # 重复判断依据:同一议题下,room_booking_id 相同视为重复
+ room_lines = rec.issue_library_room_line_ids
+ if room_lines:
+ seen_bookings = {} # {room_booking_id: [line_ids]}
+ for line in room_lines:
+ key = line.room_booking_id.id or 0
+ if key not in seen_bookings:
+ seen_bookings[key] = []
+ seen_bookings[key].append(line.id)
+
+ room_to_remove = []
+ for booking_id, line_ids in seen_bookings.items():
+ if len(line_ids) > 1:
+ # 按 id 排序,保留第一条(id 最小的),其余删除
+ sorted_lines = self.env['issue.library.room.line'].browse(line_ids).sorted(key=lambda l: l.id)
+ room_to_remove.extend(sorted_lines[1:].ids)
+
+ if room_to_remove:
+ self.env['issue.library.room.line'].browse(room_to_remove).unlink()
+ removed_count = len(room_to_remove)
+ total_removed += removed_count
+ detail_msg.append(f'议题【{rec.name or rec.code}】关联会议去重删除 {removed_count} 条')
+
+ # 返回结果通知
+ msg = f'共清理 {total_removed} 条重复数据'
+ if detail_msg:
+ msg += '\n' + '\n'.join(detail_msg[:10]) # 最多显示前10条详情
+ if len(detail_msg) > 10:
+ msg += f'\n...等共 {len(detail_msg)} 个议题'
+
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': '去重完成',
+ 'message': msg,
+ 'sticky': True,
+ }
+ }
+
def batch_add_ci_char(self):
import re
active_ids = self._context.get('active_ids', [])
diff --git a/yuthon_issue/views/issue_library_views.xml b/yuthon_issue/views/issue_library_views.xml
index 24330f758..547a35f8d 100644
--- a/yuthon_issue/views/issue_library_views.xml
+++ b/yuthon_issue/views/issue_library_views.xml
@@ -8,6 +8,10 @@
decoration-info="issue_state == 'will'"
decoration-success="issue_state == 'done'"
decoration-muted="issue_state == 'cancel'">
+
@@ -60,6 +64,8 @@
@@ -114,6 +120,8 @@
decoration-muted="issue_state == 'cancel'">
@@ -458,6 +466,8 @@
@@ -505,6 +515,8 @@
+
@@ -721,6 +733,8 @@
+
@@ -919,6 +933,8 @@