From 456b7ca03bc464cbb6e7e5c76357640972cb57db Mon Sep 17 00:00:00 2001 From: 27942 <1313123@342> Date: Fri, 6 Feb 2026 02:08:20 +0800 Subject: [PATCH] haha --- business/views.py | 451 +++++++++++++++++++++++----------------------- 1 file changed, 230 insertions(+), 221 deletions(-) diff --git a/business/views.py b/business/views.py index 36fb45c..2f8a00b 100644 --- a/business/views.py +++ b/business/views.py @@ -134,22 +134,12 @@ def search_related_records(client_info, party_info, exclude_project_id=None): if not client_info and not party_info: return result - # 解析委托人信息和相对方信息 - client_parsed = parse_person_info(client_info) if client_info else {'name': '', 'id_number': '', 'original': ''} - party_parsed = parse_person_info(party_info) if party_info else {'name': '', 'id_number': '', 'original': ''} + # 解析委托人和相对方信息(支持 JSON 数组,提取所有人员) + client_names, client_id_numbers, client_originals = _extract_all_person_info(client_info) + party_names, party_id_numbers, party_originals = _extract_all_person_info(party_info) - # 提取姓名/名称(用于匹配) - client_name = client_parsed['name'] - client_id_number = client_parsed['id_number'] - client_original = client_parsed['original'] - - party_name = party_parsed['name'] - party_id_number = party_parsed['id_number'] - party_original = party_parsed['original'] - - # 检索预立案表 - 冲突规则:当前委托人只与历史「委托人」匹配,当前相对方只与历史「相对方」匹配,任一匹配即冲突 - # 预立案表字段:client_username/party_username(JSON 数组) - if (client_info or client_name) or (party_info or party_name): + # 检索预立案表 - 委托人只匹配历史委托人,相对方只匹配历史相对方,任一匹配即冲突 + if client_names or party_names: matched_prefilings = [] prefiling_all = PreFiling.objects.filter(is_deleted=False) for pf in prefiling_all[:100]: @@ -157,36 +147,36 @@ def search_related_records(client_info, party_info, exclude_project_id=None): break pf_client_names = [] try: - client_data = json.loads(pf.client_username) if isinstance(pf.client_username, str) else pf.client_username - if isinstance(client_data, list): - for item in client_data: + cd = json.loads(pf.client_username) if isinstance(pf.client_username, str) else pf.client_username + if isinstance(cd, list): + for item in cd: if isinstance(item, dict) and 'name' in item: pf_client_names.append(item['name'].strip()) - elif isinstance(client_data, dict) and 'name' in client_data: - pf_client_names.append(client_data['name'].strip()) + elif isinstance(cd, dict) and 'name' in cd: + pf_client_names.append(cd['name'].strip()) except (json.JSONDecodeError, TypeError, AttributeError): pf_client_names = [pf.client_username.strip()] if pf.client_username else [] pf_party_names = [] try: - party_data = json.loads(pf.party_username) if isinstance(pf.party_username, str) else pf.party_username - if isinstance(party_data, list): - for item in party_data: + pd = json.loads(pf.party_username) if isinstance(pf.party_username, str) else pf.party_username + if isinstance(pd, list): + for item in pd: if isinstance(item, dict) and 'name' in item: pf_party_names.append(item['name'].strip()) - elif isinstance(party_data, dict) and 'name' in party_data: - pf_party_names.append(party_data['name'].strip()) + elif isinstance(pd, dict) and 'name' in pd: + pf_party_names.append(pd['name'].strip()) except (json.JSONDecodeError, TypeError, AttributeError): pf_party_names = [pf.party_username.strip()] if pf.party_username else [] client_match = False - if (client_info or client_name) and pf_client_names: - for pf_client in pf_client_names: - if (client_name and pf_client in client_name) or (client_original and pf_client in client_original): + if client_names and pf_client_names: + for pf_c in pf_client_names: + if any(pf_c in cn for cn in client_names) or any(pf_c in co for co in client_originals): client_match = True break party_match = False - if (party_info or party_name) and pf_party_names: - for pf_party in pf_party_names: - if (party_name and pf_party in party_name) or (party_original and pf_party in party_original): + if party_names and pf_party_names: + for pf_p in pf_party_names: + if any(pf_p in pn for pn in party_names) or any(pf_p in po for po in party_originals): party_match = True break if client_match or party_match: @@ -199,54 +189,43 @@ def search_related_records(client_info, party_info, exclude_project_id=None): }) result['prefiling_conflicts'] = matched_prefilings - # 检索立项表 - 冲突规则:当前委托人只匹配历史 client_info,当前相对方只匹配历史 party_info,任一匹配即冲突 + # 检索立项表 - 委托人只匹配历史 client_info,相对方只匹配历史 party_info project_records = ProjectRegistration.objects.filter(is_deleted=False) if exclude_project_id: project_records = project_records.exclude(id=exclude_project_id) project_q = Q() - if client_info or client_name: - if client_name: - project_q |= Q(client_info__icontains=client_name) - if client_original: - project_q |= Q(client_info__icontains=client_original[:50]) - if client_id_number: - project_q |= Q(client_info__icontains=client_id_number) - if party_info or party_name: - if party_name: - project_q |= Q(party_info__icontains=party_name) - if party_original: - project_q |= Q(party_info__icontains=party_original[:50]) - if party_id_number: - project_q |= Q(party_info__icontains=party_id_number) + for cn in client_names: + project_q |= Q(client_info__icontains=cn) + for co in client_originals: + project_q |= Q(client_info__icontains=co[:50]) + for cid in client_id_numbers: + project_q |= Q(client_info__icontains=cid) + for pn in party_names: + project_q |= Q(party_info__icontains=pn) + for po in party_originals: + project_q |= Q(party_info__icontains=po[:50]) + for pid in party_id_numbers: + project_q |= Q(party_info__icontains=pid) if project_q: project_records = project_records.filter(project_q) project_list = list(project_records[:10].values('id', 'ContractNo', 'times', 'type', 'client_info', 'party_info')) result['project_conflicts'] = project_list - # 检索投标表 - 投标表只有BiddingUnit字段,需要检查是否包含委托人或相对方信息 - # BiddingUnit可能同时包含委托人和相对方,或者只包含其中一方 + # 检索投标表 - 招标单位是否包含委托人或相对方信息 bid_records = Bid.objects.filter(is_deleted=False) bid_q = Q() - - # 如果有提取出的名称,优先使用名称匹配 - if client_name: - bid_q |= Q(BiddingUnit__icontains=client_name) - if party_name: - bid_q |= Q(BiddingUnit__icontains=party_name) - - # 如果有完整信息,也尝试匹配 - if client_original: - bid_q |= Q(BiddingUnit__icontains=client_original[:50]) - if party_original: - bid_q |= Q(BiddingUnit__icontains=party_original[:50]) - - # 如果有身份证号,也尝试匹配 - if client_id_number: - bid_q |= Q(BiddingUnit__icontains=client_id_number) - if party_id_number: - bid_q |= Q(BiddingUnit__icontains=party_id_number) - - # 如果构建了查询条件,执行查询 + for cn in client_names: + bid_q |= Q(BiddingUnit__icontains=cn) + for pn in party_names: + bid_q |= Q(BiddingUnit__icontains=pn) + for co in client_originals: + bid_q |= Q(BiddingUnit__icontains=co[:50]) + for po in party_originals: + bid_q |= Q(BiddingUnit__icontains=po[:50]) + for cid in client_id_numbers: + bid_q |= Q(BiddingUnit__icontains=cid) + for pid in party_id_numbers: + bid_q |= Q(BiddingUnit__icontains=pid) if bid_q: bid_records = bid_records.filter(bid_q) bid_list = list(bid_records[:10].values('id', 'ProjectName', 'times', 'BiddingUnit')) @@ -382,12 +361,10 @@ class registration(APIView): submit=user ) - # 利益冲突检索:比对预立案、立项、投标三张表 - client_info_str = _prefiling_person_to_info(prefiling.client_username) - party_info_str = _prefiling_person_to_info(prefiling.party_username) + # 利益冲突检索:比对预立案、立项、投标三张表(直接传 JSON,conflict_search 内部解析所有人员) conflict_result = conflict_search( - client_info=client_info_str, - party_info=party_info_str, + client_info=prefiling.client_username, + party_info=prefiling.party_username, undertaker=Undertaker, exclude_prefiling_id=prefiling.id ) @@ -543,12 +520,10 @@ class EditRegistration(APIView): pre.Undertaker = Undertaker pre.save(update_fields=['Undertaker']) - # 利益冲突检索:比对预立案、立项、投标三张表 - client_info_str = _prefiling_person_to_info(pre.client_username) - party_info_str = _prefiling_person_to_info(pre.party_username) + # 利益冲突检索:比对预立案、立项、投标三张表(直接传 JSON,conflict_search 内部解析所有人员) conflict_result = conflict_search( - client_info=client_info_str, - party_info=party_info_str, + client_info=pre.client_username, + party_info=pre.party_username, undertaker=pre.Undertaker, exclude_prefiling_id=pre.id ) @@ -4225,23 +4200,62 @@ def _prefiling_person_to_info(person_json): return None -def _normalize_client_party_for_search(val): +def _extract_all_person_info(info_val): """ - 将 conflict-search 接口的 client_info/party_info 统一为检索用字符串。 - 支持:JSON 字符串(如 '[{"name":"张三","idNumber":"111"}]')、dict/list、或普通字符串。 + 从 client_info/party_info 中提取所有人员的姓名和身份证号。 + 支持: + - JSON 字符串数组:'[{"name":"张三","idNumber":"111"},{"name":"王五","idNumber":"333"}]' + - JSON 字符串对象:'{"name":"张三","idNumber":"111"}' + - list / dict(已解析的 JSON) + - 普通字符串:"张三(111)"、"张三,身份证号:111"、"张三" + 返回: (names_list, id_numbers_list, originals_list) """ - if val is None: - return None - if isinstance(val, str): - val = val.strip() - if not val: - return None - if val.startswith('[') or val.startswith('{'): - return _prefiling_person_to_info(val) - return val - if isinstance(val, (list, dict)): - return _prefiling_person_to_info(val) - return None + names = [] + id_numbers = [] + originals = [] + if not info_val: + return names, id_numbers, originals + # 尝试 JSON 解析 + data = None + if isinstance(info_val, str): + info_val = info_val.strip() + if not info_val: + return names, id_numbers, originals + if info_val.startswith('[') or info_val.startswith('{'): + try: + data = json.loads(info_val) + except (json.JSONDecodeError, TypeError): + pass + elif isinstance(info_val, (list, dict)): + data = info_val + if data is not None: + if isinstance(data, dict): + data = [data] + if isinstance(data, list): + for item in data: + if not isinstance(item, dict): + continue + name = (item.get('name') or item.get('name_original') or '').strip() + id_num = (item.get('idNumber') or item.get('id_number') or '').strip() + if name: + names.append(name) + if id_num: + id_numbers.append(id_num) + orig = f"{name}({id_num})" if name and id_num else (name or id_num or '') + if orig: + originals.append(orig) + if names or id_numbers: + return names, id_numbers, originals + # 回退到 parse_person_info 处理普通字符串 + if isinstance(info_val, str): + parsed = parse_person_info(info_val) + if parsed['name']: + names.append(parsed['name']) + if parsed['id_number']: + id_numbers.append(parsed['id_number']) + if parsed['original']: + originals.append(parsed['original']) + return names, id_numbers, originals def parse_person_info(person_str): @@ -4337,18 +4351,9 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ if not any([client_info, party_info, undertaker, bidding_unit]): return result - # 解析委托人信息和相对方信息 - client_parsed = parse_person_info(client_info) if client_info else {'name': '', 'id_number': '', 'original': ''} - party_parsed = parse_person_info(party_info) if party_info else {'name': '', 'id_number': '', 'original': ''} - - # 提取姓名/名称(用于匹配) - client_name = client_parsed['name'] - client_id_number = client_parsed['id_number'] - client_original = client_parsed['original'] - - party_name = party_parsed['name'] - party_id_number = party_parsed['id_number'] - party_original = party_parsed['original'] + # 解析委托人和相对方信息(支持 JSON 数组,提取所有人员的姓名和身份证号) + client_names, client_id_numbers, client_originals = _extract_all_person_info(client_info) + party_names, party_id_numbers, party_originals = _extract_all_person_info(party_info) # 1. 检索预立案表 prefiling_q = Q(is_deleted=False) @@ -4359,99 +4364,102 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ prefiling_all = PreFiling.objects.filter(prefiling_q) for pf in prefiling_all: - if len(matched_prefilings) >= 50: # 限制返回数量 + if len(matched_prefilings) >= 50: break is_match = False match_reason = [] - # 检查委托人/相对方匹配 - if client_info or client_name: - pf_client_names = [] - try: - client_data = json.loads(pf.client_username) if isinstance(pf.client_username, str) else pf.client_username - if isinstance(client_data, list): - for item in client_data: - if isinstance(item, dict) and 'name' in item: - pf_client_names.append(item['name'].strip()) - elif isinstance(client_data, dict) and 'name' in client_data: - pf_client_names.append(client_data['name'].strip()) - except (json.JSONDecodeError, TypeError, AttributeError): - pf_client_names = [pf.client_username.strip()] if pf.client_username else [] - - pf_party_names = [] - try: - party_data = json.loads(pf.party_username) if isinstance(pf.party_username, str) else pf.party_username - if isinstance(party_data, list): - for item in party_data: - if isinstance(item, dict) and 'name' in item: - pf_party_names.append(item['name'].strip()) - elif isinstance(party_data, dict) and 'name' in party_data: - pf_party_names.append(party_data['name'].strip()) - except (json.JSONDecodeError, TypeError, AttributeError): - pf_party_names = [pf.party_username.strip()] if pf.party_username else [] - - # 冲突规则:当前委托人只与历史「委托人」匹配,当前相对方只与历史「相对方」匹配 - # 检查委托人匹配(仅匹配历史记录的委托人) - if client_info or client_name: - for pf_client in pf_client_names: - if client_name and pf_client in client_name: + # 解析历史记录的委托人/相对方姓名及身份证号 + pf_client_names = [] + pf_client_ids = [] + try: + cd = json.loads(pf.client_username) if isinstance(pf.client_username, str) else pf.client_username + if isinstance(cd, list): + for item in cd: + if isinstance(item, dict): + n = (item.get('name') or '').strip() + if n: + pf_client_names.append(n) + pid = (item.get('idNumber') or item.get('id_number') or '').strip() + if pid: + pf_client_ids.append(pid) + elif isinstance(cd, dict): + n = (cd.get('name') or '').strip() + if n: + pf_client_names.append(n) + pid = (cd.get('idNumber') or cd.get('id_number') or '').strip() + if pid: + pf_client_ids.append(pid) + except (json.JSONDecodeError, TypeError, AttributeError): + if pf.client_username: + pf_client_names = [pf.client_username.strip()] + + pf_party_names = [] + pf_party_ids = [] + try: + pd = json.loads(pf.party_username) if isinstance(pf.party_username, str) else pf.party_username + if isinstance(pd, list): + for item in pd: + if isinstance(item, dict): + n = (item.get('name') or '').strip() + if n: + pf_party_names.append(n) + pid = (item.get('idNumber') or item.get('id_number') or '').strip() + if pid: + pf_party_ids.append(pid) + elif isinstance(pd, dict): + n = (pd.get('name') or '').strip() + if n: + pf_party_names.append(n) + pid = (pd.get('idNumber') or pd.get('id_number') or '').strip() + if pid: + pf_party_ids.append(pid) + except (json.JSONDecodeError, TypeError, AttributeError): + if pf.party_username: + pf_party_names = [pf.party_username.strip()] + + # 冲突规则:当前委托人只与历史「委托人」匹配,当前相对方只与历史「相对方」匹配 + # 委托人姓名匹配 + if client_names and pf_client_names: + for pf_c in pf_client_names: + if any(pf_c in cn for cn in client_names): + is_match = True + match_reason.append(f"委托人姓名匹配:{pf_c}") + break + if not is_match and client_originals: + for pf_c in pf_client_names: + if any(pf_c in co for co in client_originals): is_match = True - match_reason.append(f"委托人姓名匹配:{pf_client}") + match_reason.append(f"委托人信息匹配:{pf_c}") break - if client_original and pf_client in client_original: + # 委托人身份证号匹配 + if client_id_numbers and pf_client_ids: + for pf_cid in pf_client_ids: + if any(cid in pf_cid or pf_cid in cid for cid in client_id_numbers): + is_match = True + match_reason.append("委托人身份证号匹配") + break + # 相对方姓名匹配 + if party_names and pf_party_names: + for pf_p in pf_party_names: + if any(pf_p in pn for pn in party_names): + is_match = True + match_reason.append(f"相对方姓名匹配:{pf_p}") + break + if not any("相对方" in r for r in match_reason) and party_originals: + for pf_p in pf_party_names: + if any(pf_p in po for po in party_originals): is_match = True - match_reason.append(f"委托人信息匹配:{pf_client}") + match_reason.append(f"相对方信息匹配:{pf_p}") break - # 检查相对方匹配(仅匹配历史记录的相对方) - if party_info or party_name: - for pf_party in pf_party_names: - if party_name and pf_party in party_name: - is_match = True - match_reason.append(f"相对方姓名匹配:{pf_party}") - break - if party_original and pf_party in party_original: - is_match = True - match_reason.append(f"相对方信息匹配:{pf_party}") - break - - # 检查身份证号匹配:委托人身份证只查历史委托人,相对方身份证只查历史相对方 - if client_id_number: - try: - client_data = json.loads(pf.client_username) if isinstance(pf.client_username, str) else pf.client_username - if isinstance(client_data, list): - for item in client_data: - if isinstance(item, dict): - pf_id = item.get('idNumber', '') or item.get('id_number', '') - if pf_id and client_id_number in str(pf_id): - is_match = True - match_reason.append(f"委托人身份证号匹配") - break - elif isinstance(client_data, dict): - pf_id = client_data.get('idNumber', '') or client_data.get('id_number', '') - if pf_id and client_id_number in str(pf_id): - is_match = True - match_reason.append(f"委托人身份证号匹配") - except (json.JSONDecodeError, TypeError, AttributeError): - pass - if party_id_number: - try: - party_data = json.loads(pf.party_username) if isinstance(pf.party_username, str) else pf.party_username - if isinstance(party_data, list): - for item in party_data: - if isinstance(item, dict): - pf_id = item.get('idNumber', '') or item.get('id_number', '') - if pf_id and party_id_number in str(pf_id): - is_match = True - match_reason.append(f"相对方身份证号匹配") - break - elif isinstance(party_data, dict): - pf_id = party_data.get('idNumber', '') or party_data.get('id_number', '') - if pf_id and party_id_number in str(pf_id): - is_match = True - match_reason.append(f"相对方身份证号匹配") - except (json.JSONDecodeError, TypeError, AttributeError): - pass + # 相对方身份证号匹配 + if party_id_numbers and pf_party_ids: + for pf_pid in pf_party_ids: + if any(pid in pf_pid or pf_pid in pid for pid in party_id_numbers): + is_match = True + match_reason.append("相对方身份证号匹配") + break # 检查承办人员匹配 if undertaker and pf.Undertaker: @@ -4480,32 +4488,31 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ project_records = ProjectRegistration.objects.filter(project_q) project_list = [] - for pro in project_records[:50]: # 限制查询数量 + for pro in project_records[:50]: is_match = False match_reason = [] # 冲突规则:当前委托人只与历史「委托人」匹配,当前相对方只与历史「相对方」匹配 - if (client_info or client_name) and pro.client_info: - if client_name and client_name in pro.client_info: + if (client_names or client_id_numbers) and pro.client_info: + if client_names and any(cn in pro.client_info for cn in client_names): is_match = True match_reason.append("委托人姓名匹配") - elif client_original and client_original in pro.client_info: + elif client_originals and any(co in pro.client_info for co in client_originals): is_match = True match_reason.append("委托人信息匹配") - elif client_id_number and client_id_number in pro.client_info: + elif client_id_numbers and any(cid in pro.client_info for cid in client_id_numbers): is_match = True match_reason.append("委托人身份证号匹配") - if party_info or party_name: - if pro.party_info: - if party_name and party_name in pro.party_info: - is_match = True - match_reason.append("相对方姓名匹配") - elif party_original and party_original in pro.party_info: - is_match = True - match_reason.append("相对方信息匹配") - elif party_id_number and party_id_number in pro.party_info: - is_match = True - match_reason.append("相对方身份证号匹配") + if (party_names or party_id_numbers) and pro.party_info: + if party_names and any(pn in pro.party_info for pn in party_names): + is_match = True + match_reason.append("相对方姓名匹配") + elif party_originals and any(po in pro.party_info for po in party_originals): + is_match = True + match_reason.append("相对方信息匹配") + elif party_id_numbers and any(pid in pro.party_info for pid in party_id_numbers): + is_match = True + match_reason.append("相对方身份证号匹配") # 检查负责人匹配 if undertaker and pro.responsiblefor: @@ -4516,7 +4523,6 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ main_lawyer = responsiblefor_data.get('main_lawyer', '') assistant_lawyer = responsiblefor_data.get('assistant_lawyer', '') case_manager_lawyer = responsiblefor_data.get('case_manager_lawyer', '') - if undertaker in str(responsible_person) or undertaker in str(main_lawyer) or \ undertaker in str(assistant_lawyer) or undertaker in str(case_manager_lawyer): is_match = True @@ -4549,7 +4555,7 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ bid_records = Bid.objects.filter(bid_q) bid_list = [] - for bid in bid_records[:50]: # 限制查询数量 + for bid in bid_records[:50]: is_match = False match_reason = [] @@ -4559,26 +4565,25 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ is_match = True match_reason.append("招标单位匹配") - # 检查委托人/相对方是否在招标单位中(支持姓名和身份证号匹配) - if (client_info or client_name) and bid.BiddingUnit: - if client_name and client_name in bid.BiddingUnit: + # 检查委托人/相对方是否在招标单位中 + if (client_names or client_id_numbers) and bid.BiddingUnit: + if client_names and any(cn in bid.BiddingUnit for cn in client_names): is_match = True match_reason.append("委托人姓名在招标单位中") - elif client_original and client_original in bid.BiddingUnit: + elif client_originals and any(co in bid.BiddingUnit for co in client_originals): is_match = True match_reason.append("委托人信息在招标单位中") - elif client_id_number and client_id_number in bid.BiddingUnit: + elif client_id_numbers and any(cid in bid.BiddingUnit for cid in client_id_numbers): is_match = True match_reason.append("委托人身份证号在招标单位中") - - if (party_info or party_name) and bid.BiddingUnit: - if party_name and party_name in bid.BiddingUnit: + if (party_names or party_id_numbers) and bid.BiddingUnit: + if party_names and any(pn in bid.BiddingUnit for pn in party_names): is_match = True match_reason.append("相对方姓名在招标单位中") - elif party_original and party_original in bid.BiddingUnit: + elif party_originals and any(po in bid.BiddingUnit for po in party_originals): is_match = True match_reason.append("相对方信息在招标单位中") - elif party_id_number and party_id_number in bid.BiddingUnit: + elif party_id_numbers and any(pid in bid.BiddingUnit for pid in party_id_numbers): is_match = True match_reason.append("相对方身份证号在招标单位中") @@ -4617,10 +4622,14 @@ class ConflictSearch(APIView): - exclude_project_id: 要排除的立项ID(可选) - exclude_bid_id: 要排除的投标ID(可选) """ - raw_client = request.data.get('client_info') - raw_party = request.data.get('party_info') - client_info = _normalize_client_party_for_search(raw_client) - party_info = _normalize_client_party_for_search(raw_party) + # client_info / party_info 支持 JSON 字符串(如 '[{"name":"张三","idNumber":"111"}]')或普通字符串 + client_info = request.data.get('client_info') or None + party_info = request.data.get('party_info') or None + # 如果是字符串,做 strip;如果是 list/dict 保持原样(conflict_search 内部会用 _extract_all_person_info 解析) + if isinstance(client_info, str): + client_info = client_info.strip() or None + if isinstance(party_info, str): + party_info = party_info.strip() or None undertaker = request.data.get('undertaker', '').strip() if request.data.get('undertaker') else None bidding_unit = request.data.get('bidding_unit', '').strip() if request.data.get('bidding_unit') else None exclude_prefiling_id = request.data.get('exclude_prefiling_id')