Commit b5ffed78 by luoqi

fix(ingest): emr_record occurred_at 用 created_date(精确就诊时刻)替代 rq(纯日期)

根因(对原数据 + 本地CH确认):病历快读同日多医生(转诊:吴仲恺先、刘柳后)排序错乱,
真因不在前端 —— emr 的 occurred_at 被摄成纯日期(00:00:00),同日打平。
源表 fact_emr_treatment_out 里 rq=Date(只到日)、created_date=datetime(带时分,= 就诊时刻);
diagnosis/treatment/payment 都用 created_date,唯独 emr 用了 rq(emr.yaml occurredAtField=submittedAt=rq
+ emr.parser occurredAt=submittedAt)→ 丢时分。

修(数据层,单一真理源):
- emr.yaml: occurredAtField submittedAt → createdAt(transaction.occurred_at 拿到 datetime)
- emr.parser.ts: occurredAt submittedAt → ctx.transaction.occurredAt(跟 diagnosis/treatment/encounter 一致)
- 撤回前端 band-aid(emr-soap-view 改回按 occurred_at 简单排序)

验证(重摄1000抽样):王思涵 emr 吴仲恺08:05/刘柳08:58 → 刘柳正确排在后;全体 emr 午夜 2987→0。
注:image_finding.yaml 也用 rq(影像AI分析日),源是否有 datetime 待查 — 同 pattern、低优先,后续。
服务器需随部署重摄生效。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parent 750f1f3c
......@@ -5,7 +5,10 @@ canonical: emr
emits:
action: emr_submitted
subjectType: emr
occurredAtField: submittedAt
# occurred_at 用 createdAt(=created_date,精确就诊时刻),不用 submittedAt(=rq,纯日期)。
# rq 只到日 → 同日多医生(如转诊:吴仲恺先、刘柳后)时间打平、病历快读排序错乱。
# created_date 100% 同 rq 日但带时分,与 diagnosis/treatment/payment 口径一致(见 treatment_review.yaml)。
occurredAtField: createdAt
primary:
table: emr_rows
......
......@@ -34,7 +34,6 @@ export class EmrParser implements Parser {
return [];
}
const submittedAt = c.submittedAt ? new Date(c.submittedAt as string) : null;
const encounterExternalId = (c.encounterExternalId as string | undefined) ?? null;
const qualityStatus = (c.qualityStatus as string | undefined) ?? null;
const rejected = ctx.transaction.action === Action.EMR_REJECTED;
......@@ -46,7 +45,10 @@ export class EmrParser implements Parser {
type: FactType.EMR_RECORD,
status: rejected ? FactStatus.INVALIDATED : FactStatus.ACTIVE,
clinicId: ctx.transaction.clinicId,
occurredAt: submittedAt,
// 用 transaction.occurredAt(= emr.yaml occurredAtField=createdAt,精确就诊时刻),
// 跟 diagnosis/treatment/encounter parser 一致。原来用 submittedAt(=rq 纯日期)→ 同日多医生
// (转诊场景)时间打平、病历快读排序错乱。
occurredAt: ctx.transaction.occurredAt,
title: `电子病历 ${externalId}${rejected ? '(质控打回)' : ''}`,
summary: encounterExternalId ? `关联接诊:${encounterExternalId}` : null,
content: {
......
......@@ -23,26 +23,9 @@ import type { AdaptedFact } from './adapt-data';
* - 当前卡淡入展示;默认最新一次接诊(idx=0)
*/
export function EmrSoapView({ facts }: { facts: AdaptedFact[] }) {
// emr_record 的 occurredAt 只到日期(00:00:00)→ 同日多医生(如转诊:吴仲恺先、刘柳后)会打平,
// 排序不稳定。用同次接诊的诊断/治疗事实(带真实时分,经 source_encounter_external_id ↔ emr_external_id
// 关联)补出真实时序做 tiebreak。预计算每条 emr 的排序键,避免比较器里重复扫 facts。
const encId = (f: AdaptedFact) =>
String((f.content as Record<string, unknown> | null)?.source_encounter_external_id ?? '');
const emrList = facts.filter((f) => f.type === 'emr_record');
const sortKey = new Map<string, string>();
for (const emr of emrList) {
const emrId = String((emr.content as Record<string, unknown> | null)?.emr_external_id ?? '');
let best = emr.occurredAt ?? '';
if (emrId) {
for (const f of facts) {
if (f.occurredAt && f.occurredAt > best && encId(f) === emrId) best = f.occurredAt;
}
}
sortKey.set(emr.id, best);
}
const emrs = emrList.sort((a, b) =>
(sortKey.get(b.id) ?? '').localeCompare(sortKey.get(a.id) ?? ''),
);
const emrs = facts
.filter((f) => f.type === 'emr_record')
.sort((a, b) => (b.occurredAt ?? '').localeCompare(a.occurredAt ?? ''));
const [idx, setIdx] = useState(0);
const total = emrs.length;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment