From 7262a33a93f008364547a42d8ed4c2ee8bbec34a Mon Sep 17 00:00:00 2001 From: Marsway Date: Wed, 4 Mar 2026 13:56:58 +0800 Subject: [PATCH] fixing --- extensions/sync_ehr_to_oa/job.py | 94 +++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 15 deletions(-) diff --git a/extensions/sync_ehr_to_oa/job.py b/extensions/sync_ehr_to_oa/job.py index 11c82fc..f2342e3 100644 --- a/extensions/sync_ehr_to_oa/job.py +++ b/extensions/sync_ehr_to_oa/job.py @@ -79,6 +79,64 @@ def _normalize_job_no(v: Any) -> str: return s.upper() +def _extract_oa_row_id_and_fields(row: dict[str, Any]) -> tuple[int | None, dict[str, Any]]: + """ + 兼容不同 OA export 返回结构,提取: + - row_id + - 字段字典(key=fieldCode, value=单元格对象或值) + """ + field_map: dict[str, Any] = {} + row_id: int | None = None + + # 结构 A:masterData 直接是 {field0001: {value,showValue}, ...} + master = row.get("masterData") + if isinstance(master, dict): + for k, v in master.items(): + if isinstance(k, str) and k.startswith("field"): + field_map[k] = v + for candidate in (row.get("id"), row.get("masterDataId"), master.get("id")): + if candidate is None: + continue + try: + row_id = int(str(candidate)) + break + except Exception: + continue + + # 结构 B:masterTable.record.fields = [{name,value,showValue}, ...] + master_table = row.get("masterTable") + if isinstance(master_table, dict): + record = master_table.get("record") + if isinstance(record, dict): + fields = record.get("fields") + if isinstance(fields, list): + for fld in fields: + if not isinstance(fld, dict): + continue + name = str(fld.get("name") or "").strip() + if name: + field_map[name] = fld + if row_id is None: + rid = record.get("id") + if rid is not None: + try: + row_id = int(str(rid)) + except Exception: + pass + + # 结构 C:行级 fields 列表 + row_fields = row.get("fields") + if isinstance(row_fields, list): + for fld in row_fields: + if not isinstance(fld, dict): + continue + name = str(fld.get("name") or "").strip() + if name: + field_map[name] = fld + + return row_id, field_map + + def _choose_better_record(current: dict[str, Any], candidate: dict[str, Any]) -> dict[str, Any]: def _score(item: dict[str, Any]) -> str: record = item.get("recordInfo") or {} @@ -292,35 +350,41 @@ class SyncEhrToOaFormJob(BaseJob): job_field_code = display_to_code["工号"] oa_id_by_job_no: dict[str, int] = {} oa_id_by_job_no_norm: dict[str, int] = {} + row_parse_miss = 0 for row in rows: if not isinstance(row, dict): continue - master = row.get("masterData") or {} - if not isinstance(master, dict): - continue - job_no = _cell_value(master.get(job_field_code)) + row_id, field_map = _extract_oa_row_id_and_fields(row) + job_no = _cell_value(field_map.get(job_field_code)) if not job_no: + row_parse_miss += 1 + if verbose_trace and row_parse_miss <= 20: + logger.info( + "OA 行解析未取到工号:job_field=%s row_keys=%s field_keys_sample=%s", + job_field_code, + list(row.keys())[:20], + list(field_map.keys())[:20], + ) continue - row_id_raw = row.get("id") - if row_id_raw is None: - row_id_raw = row.get("masterDataId") - if row_id_raw is None: - row_id_raw = master.get("id") - if row_id_raw is None: - continue - try: - row_id = int(str(row_id_raw)) - except Exception: + if row_id is None: + row_parse_miss += 1 + if verbose_trace and row_parse_miss <= 20: + logger.info( + "OA 行解析未取到记录ID:job_no=%s row_keys=%s", + job_no, + list(row.keys())[:20], + ) continue oa_id_by_job_no[job_no] = row_id job_no_norm = _normalize_job_no(job_no) if job_no_norm: oa_id_by_job_no_norm[job_no_norm] = row_id logger.info( - "OA 工号索引完成:indexed_job_numbers=%s indexed_job_numbers_norm=%s", + "OA 工号索引完成:indexed_job_numbers=%s indexed_job_numbers_norm=%s parse_miss=%s", len(oa_id_by_job_no), len(oa_id_by_job_no_norm), + row_parse_miss, ) if verbose_trace: for job_no, row_id in list(oa_id_by_job_no.items()):