<script lang="ts" setup>
/**
 * 接诊病历面板（双栏）
 * diagnosis / medicalAdvice 与处方 Tab 双向绑定
 * 诊断/医嘱气泡走处方同源接口；其余字段走病历词条
 * 文本域双击弹出放大编辑 Modal
 */
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue';

import { useDebounceFn } from '@vueuse/core';
import { useVbenDrawer, useVbenModal } from '@vben/common-ui';
import {
  Button,
  Input,
  InputNumber,
  Textarea,
  message,
} from 'ant-design-vue';
import {
  ClearOutlined,
  HistoryOutlined,
  RobotOutlined,
  SaveOutlined,
} from '@ant-design/icons-vue';

import { getSystemConfigByKeys } from '#/views/system/system-config/api';
import {
  hasVipPermission,
  VIP_FEATURE,
  type StoreVipInfo,
} from '#/utils/vip';

import {
  clearMedicalRecord,
  getMedicalRecord,
  saveMedicalRecord,
} from './api';
import EntryKeywordBubble, {
  type MedicalRecordEntryItem,
} from './components/EntryKeywordBubble.vue';
import CommonDxOrderChips from './components/CommonDxOrderChips.vue';
import PatientMedicalRecordDrawer from './components/PatientMedicalRecordDrawer.vue';
import TextareaExpandModal from './components/TextareaExpandModal.vue';
import AiMedicalRecordModal from './components/AiMedicalRecordModal.vue';
import HistoryImportModal, {
  type HistoryImportDiffItem,
} from './components/HistoryImportModal.vue';
import { emptyMedicalRecord, isHistoryFieldVisible } from './config/constants';
import {
  clearMedicalRecordDraft,
  loadMedicalRecordDraft,
  saveMedicalRecordDraft,
} from './utils/localDraft';

/** 诊断/医嘱常用展示：tags标签 / bubble气泡 / both两边 */
type MrCommonDisplayMode = 'tags' | 'bubble' | 'both';

const props = withDefaults(
  defineProps<{
    registerId: number;
    storeId?: number;
    userPatientId?: number;
    /** 与处方同步：临床诊断 */
    diagnosis: string;
    /** 与处方同步：医嘱 */
    medicalAdvice: string;
    /** 在线复诊时诊断只读 */
    diagnosisReadonly?: boolean;
    /** localStorage 键前缀（chat-shop 用 storagePrefix 隔离） */
    storagePrefix?: string;
    /** 就诊人性别 1男2女，用于月经史/婚育史显隐 */
    patientSex?: number;
    /** 就诊人年龄，用于婚育史显隐 */
    patientAge?: number;
    /** 就诊人姓名（AI 写病历确认用） */
    patientName?: string;
    /**
     * 履约诊所 VIP（接诊/复诊传入）；不传则回落登录态
     */
    storeVip?: StoreVipInfo | null;
    /**
     * 是否在面板内展示操作工具栏
     * 接诊台/弹窗已把按钮提到一级 Tab 下吸顶工具栏时传 false
     */
    showToolbar?: boolean;
  }>(),
  {
    storeId: 0,
    userPatientId: 0,
    diagnosisReadonly: false,
    storagePrefix: '',
    patientSex: 0,
    patientAge: 0,
    patientName: '',
    storeVip: undefined,
    showToolbar: true,
  },
);

/** 按履约诊所或登录态判断 VIP */
function checkVip(code: string) {
  if (props.storeVip !== undefined) {
    return hasVipPermission(code, props.storeVip);
  }
  return hasVipPermission(code);
}

const emit = defineEmits<{
  'update:diagnosis': [string];
  'update:medicalAdvice': [string];
  /** 病历关键字段同步到处方（主诉/诊断/中医三典名称） */
  'sync-to-prescription': [Record<string, any>];
  /** AI 校正后的开方旧字段 id（diseases_id/method_id/syndrome_id） */
  'apply-tcm-ids': [
    {
      diseases_id?: number | null;
      method_id?: number | null;
      syndrome_id?: number | null;
    },
  ];
}>();

/** 防抖：主诉/中医手输同步到处方，避免每个字符都触发 */
let syncToRxTimer: ReturnType<typeof setTimeout> | null = null;
function emitSyncToPrescription() {
  emit('sync-to-prescription', {
    diagnosis: diagnosisModel.value || form.diagnosis || '',
    chief_complaint: form.chief_complaint || '',
    doctor_order: medicalAdviceModel.value || form.doctor_order || '',
    medicalAdvice: medicalAdviceModel.value || form.doctor_order || '',
    tcm_syndrome: form.tcm_syndrome || '',
    tcm_disease: form.tcm_disease || '',
    tcm_method: form.tcm_method || '',
  });
}
function scheduleSyncToPrescription() {
  if (hydrating.value) return;
  if (syncToRxTimer) clearTimeout(syncToRxTimer);
  syncToRxTimer = setTimeout(() => emitSyncToPrescription(), 280);
}

const form = reactive(emptyMedicalRecord());
const loading = ref(false);
/** 加载中不写本地，避免接口回填触发草稿覆盖 */
const hydrating = ref(false);
/** P4：最近一次导入的 AI 生成记录 ID，保存病历时回传后端做采纳率/修改率统计（换号/清空重置） */
const aiMrGenerationId = ref(0);
/** 系统配置：常用|我的展示位置，默认标签 */
const commonDisplayMode = ref<MrCommonDisplayMode>('tags');
const showCommonTags = computed(
  () => commonDisplayMode.value === 'tags' || commonDisplayMode.value === 'both',
);
const showCommonInBubble = computed(
  () =>
    commonDisplayMode.value === 'bubble' || commonDisplayMode.value === 'both',
);
/** AI写病历入口：门店 VIP 需开通 ai_medical_record */
const canUseAiMedicalRecord = computed(() =>
  checkVip(VIP_FEATURE.AI_MEDICAL_RECORD),
);
/** 标签区刷新（气泡内新增/加常用后） */
const commonChipsTick = ref(0);

/**
 * 病历模块焦点顺序：常规区 → 健康信息整块 → 中医病案整块
 * 「健康信息」内：现病史与各类史；「中医病案」内：舌象→脉象→辨证→证候→疾病→治法
 */
const MODULE_ORDER = [
  'chief_complaint',
  'treatment_advice',
  'doctor_order',
  'physical_exam',
  'auxiliary_exam',
  'present_illness',
  'past_history',
  'allergy_history',
  'family_history',
  'epidemic_history',
  'personal_history',
  'menstrual_history',
  'marital_history',
  'tongue',
  'pulse',
  'tcm_case',
  'tcm_syndrome',
  'tcm_disease',
  'tcm_method',
] as const;

type MrModuleKey = (typeof MODULE_ORDER)[number];

const panelRootRef = ref<HTMLElement | null>(null);
const searchRefs = reactive<Record<string, { focus?: () => void; close?: () => void } | null>>(
  {},
);
const textareaRefs = reactive<Record<string, any>>({});

function setSearchRef(key: string, el: unknown) {
  searchRefs[key] = (el as any) || null;
}

function setTextareaRef(key: string, el: unknown) {
  textareaRefs[key] = el || null;
}

/** 聚焦某模块搜索气泡 */
function focusModuleSearch(key: MrModuleKey) {
  Object.values(searchRefs).forEach((r) => r?.close?.());
  nextTick(() => searchRefs[key]?.focus?.());
}

/**
 * 聚焦某模块文本域/输入框
 * 舌象/脉象是 Input，其余多为 Textarea，兼容两种 DOM
 */
function focusModuleTextarea(key: MrModuleKey) {
  Object.values(searchRefs).forEach((r) => r?.close?.());
  nextTick(() => {
    const comp = textareaRefs[key];
    if (!comp) return;
    // Ant Design Vue 组件常自带 focus()
    if (typeof comp.focus === 'function') {
      comp.focus();
      return;
    }
    const el =
      comp?.resizableTextArea?.textArea ||
      comp?.$el?.querySelector?.('textarea') ||
      comp?.$el?.querySelector?.('input') ||
      (comp instanceof HTMLTextAreaElement || comp instanceof HTMLInputElement
        ? comp
        : null);
    el?.focus?.();
  });
}

/**
 * Ctrl+Enter：搜索→同模块文本域；文本域→下一模块搜索（首尾循环）
 * Ctrl+Shift+Enter：文本域→同模块搜索；搜索→上一模块文本域（首尾循环）
 */
function onPanelKeydownCapture(e: KeyboardEvent) {
  if (!e.ctrlKey || e.key !== 'Enter') return;
  const target = e.target as HTMLElement | null;
  if (!target || !panelRootRef.value?.contains(target)) return;
  const host = target.closest('[data-mr-module]') as HTMLElement | null;
  if (!host || !panelRootRef.value.contains(host)) return;
  const moduleKey = host.getAttribute('data-mr-module') as MrModuleKey | null;
  const role = host.getAttribute('data-mr-role') as 'search' | 'textarea' | null;
  if (!moduleKey || !role) return;
  const idx = MODULE_ORDER.indexOf(moduleKey);
  if (idx < 0) return;
  e.preventDefault();
  e.stopPropagation();
  const n = MODULE_ORDER.length;
  if (e.shiftKey) {
    if (role === 'textarea') {
      focusModuleSearch(moduleKey);
      return;
    }
    const prev = MODULE_ORDER[(idx - 1 + n) % n];
    focusModuleTextarea(prev);
    return;
  }
  if (role === 'search') {
    focusModuleTextarea(moduleKey);
    return;
  }
  const next = MODULE_ORDER[(idx + 1) % n];
  focusModuleSearch(next);
}

/** 读取常用展示位置配置 */
async function loadCommonDisplayMode() {
  try {
    const res = await getSystemConfigByKeys(['mr_common_display_mode']);
    const raw = String(
      res?.mr_common_display_mode ?? res?.data?.mr_common_display_mode ?? 'tags',
    );
    commonDisplayMode.value =
      raw === 'bubble' || raw === 'both' ? raw : 'tags';
  } catch {
    commonDisplayMode.value = 'tags';
  }
}

onMounted(() => {
  loadCommonDisplayMode();
});

/** 优先 props，其次病历/挂号回填的 form.user_patient_id */
const effectivePatientId = computed(
  () => Number(props.userPatientId || form.user_patient_id || 0),
);

const diagnosisModel = computed({
  get: () => props.diagnosis,
  set: (v: string) => emit('update:diagnosis', v),
});
const medicalAdviceModel = computed({
  get: () => props.medicalAdvice,
  set: (v: string) => emit('update:medicalAdvice', v),
});

const [ExpandModal, expandModalApi] = useVbenModal({
  connectedComponent: TextareaExpandModal,
});

/** 引用历史：用列表抽屉选择，避免 latest 排除当前挂号导致「列表有、引用无」 */
const [CiteHistoryDrawer, citeHistoryDrawerApi] = useVbenDrawer({
  connectedComponent: PatientMedicalRecordDrawer,
});

/** 档案史与病历史不一致时确认导入 */
const [HistoryImportModalHost, historyImportModalApi] = useVbenModal({
  connectedComponent: HistoryImportModal,
});

/** 空串与「无」视为同一默认态（与后端 normalizeHistoryCompare 对齐） */
function normalizeHistoryCompare(value: unknown): string {
  const t = String(value ?? '').trim();
  return t === '' || t === '无' ? '无' : t;
}

/** 本会话已对某挂号提示过导入，避免切 Tab 反复弹 */
function historyImportSkipKey(registerId: number) {
  return `xk_mr_hist_import_skip_${props.storagePrefix || ''}${registerId}`;
}

/**
 * 草稿合并后按「当前表单 vs 档案」再滤一遍差异，有差异才弹预览确认
 */
function maybeAskHistoryImport(rawDiff: HistoryImportDiffItem[]) {
  const rid = Number(props.registerId || 0);
  if (!rid || !Array.isArray(rawDiff) || !rawDiff.length) return;
  try {
    if (sessionStorage.getItem(historyImportSkipKey(rid)) === '1') return;
  } catch {
    /* ignore */
  }
  const rows: HistoryImportDiffItem[] = [];
  for (const item of rawDiff) {
    if (!item?.field) continue;
    const current = normalizeHistoryCompare((form as any)[item.field]);
    const importVal = normalizeHistoryCompare(item.import);
    if (current === importVal) continue;
    rows.push({
      field: item.field,
      label: item.label || item.field,
      current,
      import: importVal,
    });
  }
  if (!rows.length) return;
  historyImportModalApi.setData({
    rows,
    onConfirm: (list: HistoryImportDiffItem[]) => {
      const patch: Record<string, string> = {};
      for (const row of list || []) {
        if (row?.field) patch[row.field] = row.import || '无';
      }
      Object.keys(patch).forEach((k) => {
        if (Object.prototype.hasOwnProperty.call(form, k)) {
          (form as any)[k] = patch[k];
        }
      });
      persistLocalDraft();
      try {
        sessionStorage.setItem(historyImportSkipKey(rid), '1');
      } catch {
        /* ignore */
      }
      message.success('已导入档案病史，请检查后保存');
    },
    onCancel: () => {
      try {
        sessionStorage.setItem(historyImportSkipKey(rid), '1');
      } catch {
        /* ignore */
      }
    },
  });
  historyImportModalApi.open();
}

/** 组装当前可落盘的病历草稿（含诊断/医嘱） */
function buildDraftPayload() {
  return {
    ...form,
    register_id: props.registerId,
    store_id: props.storeId || form.store_id,
    user_patient_id: effectivePatientId.value,
    diagnosis: diagnosisModel.value,
    doctor_order: medicalAdviceModel.value,
  };
}

/** 写入本地草稿（带前缀隔离） */
function persistLocalDraft() {
  if (!props.registerId || hydrating.value) return;
  const keyId = `${props.storagePrefix || ''}${props.registerId}`;
  saveMedicalRecordDraft(keyId, buildDraftPayload());
}

const debouncedPersistLocal = useDebounceFn(persistLocalDraft, 300);

/**
 * 拉取病历：接口 + 本地草稿合并（草稿覆盖内容字段，避免刷新丢失未保存编辑）
 */
async function loadRecord() {
  if (!props.registerId) return;
  // 无病历 VIP 不请求，避免弹出「未开通病历VIP」；普通诊所只看病历 Tab 隐藏即可
  if (!checkVip(VIP_FEATURE.MEDICAL_RECORD)) return;
  loading.value = true;
  hydrating.value = true;
  let historyDiff: HistoryImportDiffItem[] = [];
  try {
    const data = await getMedicalRecord({
      register_id: props.registerId,
      store_id: props.storeId || undefined,
    });
    historyDiff = Array.isArray(data?.history_import_diff)
      ? data.history_import_diff
      : [];
    Object.assign(form, emptyMedicalRecord(props.registerId, props.storeId), data || {});
    // 提示字段不进表单/草稿
    delete (form as any).history_import_diff;
    delete (form as any).patient_history_defaults;
    const draftKey = `${props.storagePrefix || ''}${props.registerId}`;
    const draft = loadMedicalRecordDraft(draftKey);
    if (draft) {
      const keepMeta = {
        id: form.id || draft.id || 0,
        register_id: props.registerId,
        store_id: props.storeId || form.store_id || draft.store_id || 0,
        user_patient_id:
          props.userPatientId ||
          form.user_patient_id ||
          draft.user_patient_id ||
          0,
      };
      Object.assign(form, draft, keepMeta);
      if (draft.diagnosis) emit('update:diagnosis', draft.diagnosis);
      if (draft.doctor_order) emit('update:medicalAdvice', draft.doctor_order);
    } else {
      if (!props.diagnosis && form.diagnosis) {
        emit('update:diagnosis', form.diagnosis);
      }
      if (!props.medicalAdvice && form.doctor_order) {
        emit('update:medicalAdvice', form.doctor_order);
      }
    }
    // 处方侧已有值优先（接诊草稿可能先恢复了诊断/医嘱）
    if (props.diagnosis) form.diagnosis = props.diagnosis;
    if (props.medicalAdvice) form.doctor_order = props.medicalAdvice;
  } catch (e: any) {
    console.error(e);
    const draft = loadMedicalRecordDraft(
      `${props.storagePrefix || ''}${props.registerId}`,
    );
    if (draft) {
      Object.assign(form, emptyMedicalRecord(props.registerId, props.storeId), draft);
      if (draft.diagnosis) emit('update:diagnosis', draft.diagnosis);
      if (draft.doctor_order) emit('update:medicalAdvice', draft.doctor_order);
    }
  } finally {
    loading.value = false;
    hydrating.value = false;
    // 草稿合并完成后再判断是否弹导入确认
    nextTick(() => maybeAskHistoryImport(historyDiff));
  }
}

watch(
  () => props.registerId,
  (id) => {
    // 换号后 AI 采纳关联失效，重置避免误关联到别的挂号
    aiMrGenerationId.value = 0;
    if (id) loadRecord();
  },
  { immediate: true },
);

watch(
  () => props.diagnosis,
  (v) => {
    form.diagnosis = v || '';
    debouncedPersistLocal();
  },
);
watch(
  () => props.medicalAdvice,
  (v) => {
    form.doctor_order = v || '';
    debouncedPersistLocal();
  },
);

/** 表单任意字段变更都落本地，防止刷新丢失；主诉/中医同步处方 */
watch(
  form,
  () => {
    debouncedPersistLocal();
    scheduleSyncToPrescription();
  },
  { deep: true },
);

function appendText(base: string, add: string) {
  if (!add) return base || '';
  if (!base) return add;
  return `${base}${base.endsWith('\n') ? '' : '\n'}${add}`;
}

/**
 * 诊断/医嘱与处方一致：用中文逗号拼接，避免重复
 */
function appendCommaText(base: string, add: string) {
  if (!add) return base || '';
  const parts = (base || '').split('，').map((s) => s.trim()).filter(Boolean);
  if (parts.includes(add)) return parts.join('，');
  parts.push(add);
  return parts.join('，');
}

/** 从中文逗号列表移除一项 */
function removeCommaText(base: string, remove: string) {
  if (!base || !remove) return base || '';
  return (base || '')
    .split('，')
    .map((s) => s.trim())
    .filter((s) => s && s !== remove)
    .join('，');
}

/** 从换行文本移除一行（优先整行匹配，否则去掉首次出现） */
function removeAppendedText(base: string, remove: string) {
  if (!base || !remove) return base || '';
  const lines = base.split('\n');
  const idx = lines.findIndex((l) => l.trim() === remove.trim());
  if (idx >= 0) {
    lines.splice(idx, 1);
    return lines.join('\n');
  }
  const i = base.indexOf(remove);
  if (i < 0) return base;
  return `${base.slice(0, i)}${base.slice(i + remove.length)}`
    .replace(/\n{3,}/g, '\n\n')
    .replace(/^\n+|\n+$/g, '');
}

/** 字段正文是否已包含该文案 */
function fieldContainsText(base: string, text: string) {
  const t = String(text || '').trim();
  if (!t) return false;
  const v = String(base || '');
  if (!v) return false;
  if (v.split('，').map((s) => s.trim()).includes(t)) return true;
  if (v.split('\n').map((s) => s.trim()).includes(t)) return true;
  return v.includes(t);
}

/**
 * 选用词条（切换）：正文已有则删除对应文案，否则追加
 * 舌象/脉象：相同则清空，不同则覆盖
 */
function onEntryPick(fieldCode: string, item: MedicalRecordEntryItem) {
  const text = item.content || item.title || '';
  if (!text) return;
  if (fieldCode === 'tongue' || fieldCode === 'pulse') {
    const cur = String((form as any)[fieldCode] || '');
    (form as any)[fieldCode] = cur.trim() === text.trim() ? '' : text;
    return;
  }
  if (fieldCode === 'diagnosis') {
    diagnosisModel.value = fieldContainsText(diagnosisModel.value, text)
      ? removeCommaText(diagnosisModel.value, text)
      : appendCommaText(diagnosisModel.value, text);
    scheduleSyncToPrescription();
    return;
  }
  if (fieldCode === 'doctor_order') {
    medicalAdviceModel.value = fieldContainsText(medicalAdviceModel.value, text)
      ? removeCommaText(medicalAdviceModel.value, text)
      : appendCommaText(medicalAdviceModel.value, text);
    return;
  }
  if (
    fieldCode === 'tcm_disease' ||
    fieldCode === 'tcm_syndrome' ||
    fieldCode === 'tcm_method'
  ) {
    const cur = String((form as any)[fieldCode] || '');
    (form as any)[fieldCode] = fieldContainsText(cur, text)
      ? removeCommaText(cur, text)
      : appendCommaText(cur, text);
    scheduleSyncToPrescription();
    return;
  }
  const cur = String((form as any)[fieldCode] || '');
  (form as any)[fieldCode] = fieldContainsText(cur, text)
    ? removeAppendedText(cur, text)
    : appendText(cur, text);
}

/**
 * 双击文本域：弹出放大编辑框（可带词条搜索与常用快捷）
 */
function openExpandEditor(
  title: string,
  getValue: () => string,
  setValue: (v: string) => void,
  readonly = false,
  extra?: {
    source?:
      | 'entry'
      | 'diagnosis'
      | 'doctor_order'
      | 'tcm_disease'
      | 'tcm_syndrome'
      | 'tcm_method';
    fieldCode?: string;
    showChips?: boolean;
    showCommonInBubble?: boolean;
    joinMode?: 'comma' | 'newline' | 'replace';
  },
) {
  if (readonly) return;
  expandModalApi.setData({
    title,
    value: getValue() || '',
    onConfirm: (v: string) => setValue(v),
    storeId: props.storeId,
    readonly,
    ...extra,
  });
  expandModalApi.open();
}

function openDiagnosisExpand() {
  openExpandEditor(
    '临床诊断',
    () => diagnosisModel.value,
    (v) => {
      diagnosisModel.value = v;
    },
    props.diagnosisReadonly,
    {
      source: 'diagnosis',
      showChips: showCommonTags.value,
      showCommonInBubble: showCommonInBubble.value,
      joinMode: 'comma',
    },
  );
}

function openAdviceExpand() {
  openExpandEditor(
    '医嘱',
    () => medicalAdviceModel.value,
    (v) => {
      medicalAdviceModel.value = v;
    },
    false,
    {
      source: 'doctor_order',
      showChips: showCommonTags.value,
      showCommonInBubble: showCommonInBubble.value,
      joinMode: 'comma',
    },
  );
}

function openFieldExpand(fieldCode: string, label: string) {
  const tcmSourceMap: Record<
    string,
    'tcm_disease' | 'tcm_syndrome' | 'tcm_method'
  > = {
    // 与开方旧字段交叉绑定：证候搜 diseases；疾病搜 syndrome
    tcm_syndrome: 'tcm_disease',
    tcm_disease: 'tcm_syndrome',
    tcm_method: 'tcm_method',
  };
  const tcmSource = tcmSourceMap[fieldCode];
  const joinMode =
    fieldCode === 'tongue' || fieldCode === 'pulse'
      ? 'replace'
      : tcmSource
        ? 'comma'
        : 'newline';
  openExpandEditor(
    label,
    () => String((form as any)[fieldCode] || ''),
    (v) => {
      (form as any)[fieldCode] = v;
    },
    false,
    {
      source: tcmSource || 'entry',
      fieldCode: tcmSource ? undefined : fieldCode,
      // 词条与诊断/医嘱一样，跟随 mr_common_display_mode（中医三典无常用词条表）
      showChips: !tcmSource && showCommonTags.value,
      showCommonInBubble: !tcmSource && showCommonInBubble.value,
      joinMode,
    },
  );
}

/** 保存病历（同步诊断/医嘱；主诉必填） */
async function handleSave() {
  if (!props.registerId) {
    message.warning('无挂号信息');
    return;
  }
  const chief = String(form.chief_complaint || '').trim();
  if (!chief) {
    message.warning('请填写主诉');
    focusModuleTextarea('chief_complaint');
    return;
  }
  loading.value = true;
  try {
    await saveMedicalRecord({
      ...form,
      register_id: props.registerId,
      store_id: props.storeId || form.store_id,
      user_patient_id: effectivePatientId.value,
      diagnosis: diagnosisModel.value,
      doctor_order: medicalAdviceModel.value,
      medicalAdvice: medicalAdviceModel.value,
      // 后端按此开关做主诉必填拦截
      validate_required: 1,
      // P4：AI 导入来源生成 ID，后端据此统计采纳率/修改率
      ai_generation_id: aiMrGenerationId.value || undefined,
    });
    persistLocalDraft();
    message.success('病历已保存');
  } finally {
    loading.value = false;
  }
}

/**
 * 打开 AI 写病历抽屉：先进历史；无历史自动打开生成框
 */
function handleAiGenerate() {
  if (!canUseAiMedicalRecord.value) {
    message.warning('当前门店未开通AI写病历VIP功能');
    return;
  }
  if (!props.registerId) {
    message.warning('无挂号信息');
    return;
  }
  aiMedicalRecordModalRef.value?.open({
    registerId: props.registerId,
    storeId: props.storeId || undefined,
    patientName: props.patientName || '',
    patientSex: Number(props.patientSex || 0),
    patientAge: Number(props.patientAge || 0),
    chiefComplaint: String(form.chief_complaint || ''),
    medicalRecord: { ...form },
  });
}

/**
 * 将 AI 预览结果导入病历表单（不自动保存）
 */
function handleImportAiMedicalRecord(payload: {
  chief_complaint: string;
  fields: Record<string, string>;
  tcm_ids?: {
    diseases_id?: number | null;
    method_id?: number | null;
    syndrome_id?: number | null;
  } | null;
  generation_id?: number;
}) {
  // P4：记录本次导入来源的生成 ID，保存病历时回传做采纳率统计
  aiMrGenerationId.value = Number(payload?.generation_id || 0);
  const fields = payload?.fields || {};
  Object.keys(fields).forEach((k) => {
    if (k === 'chief_complaint' || k === 'name') return;
    // 诊断与处方同源，走双向绑定而不是仅写 form
    if (k === 'diagnosis') {
      const dx = fields[k] == null ? '' : String(fields[k]);
      form.diagnosis = dx;
      emit('update:diagnosis', dx);
      return;
    }
    // 医嘱与处方同源：必须 emit，否则在线复诊处方侧医嘱仍为空
    if (k === 'doctor_order' || k === 'medicalAdvice') {
      const adv = fields[k] == null ? '' : String(fields[k]);
      form.doctor_order = adv;
      emit('update:medicalAdvice', adv);
      return;
    }
    if (Object.prototype.hasOwnProperty.call(form, k)) {
      (form as any)[k] = fields[k] == null ? '' : String(fields[k]);
    }
  });
  if (payload?.chief_complaint) {
    form.chief_complaint = payload.chief_complaint;
  }
  persistLocalDraft();
  emitSyncToPrescription();
  // AI 已校正的字典 id：直接落到开方旧字段，供监管取码
  if (payload?.tcm_ids && typeof payload.tcm_ids === 'object') {
    emit('apply-tcm-ids', payload.tcm_ids);
  }
  message.success('已导入，请检查后保存');
}

const aiMedicalRecordModalRef = ref<InstanceType<typeof AiMedicalRecordModal> | null>(null);

/**
 * AI「生成病历」弹窗点改字段：即时同步到本页表单（不落库，与 AI 出方预览改病历同链路）
 */
function handleSyncAiMedicalRecord(partial: Record<string, any>) {
  patchFields(partial || {});
}

/**
 * 外部/弹窗局部回写病历字段，同步表单与本地草稿，不自动落库
 */
function patchFields(partial: Record<string, any>) {
  if (!partial || typeof partial !== 'object') return;
  Object.keys(partial).forEach((k) => {
    const raw = partial[k];
    const val = raw == null ? '' : String(raw);
    if (k === 'diagnosis') {
      form.diagnosis = val;
      emit('update:diagnosis', val);
      return;
    }
    if (k === 'doctor_order' || k === 'medicalAdvice') {
      form.doctor_order = val;
      emit('update:medicalAdvice', val);
      return;
    }
    if (Object.prototype.hasOwnProperty.call(form, k)) {
      (form as any)[k] = val;
    }
  });
  persistLocalDraft();
  scheduleSyncToPrescription();
}

async function handleClear() {
  if (!props.registerId) return;
  await clearMedicalRecord({
    register_id: props.registerId,
    store_id: props.storeId || undefined,
  });
  const keepPatient = effectivePatientId.value;
  Object.assign(form, emptyMedicalRecord(props.registerId, props.storeId));
  form.user_patient_id = keepPatient;
  // 病历清空后 AI 内容已不存在，解除采纳关联
  aiMrGenerationId.value = 0;
  emit('update:diagnosis', '');
  emit('update:medicalAdvice', '');
  clearMedicalRecordDraft(`${props.storagePrefix || ''}${props.registerId}`);
  message.success('已清空病历');
}

/**
 * 打开引用历史病历抽屉（从列表选择，可引用填充）
 */
function handleCiteHistory() {
  const patientId = effectivePatientId.value;
  if (!patientId) {
    message.warning('无就诊人信息');
    return;
  }
  citeHistoryDrawerApi.setData({
    mode: 'cite',
    userPatientId: patientId,
    storeId: props.storeId || undefined,
    excludeRegisterId: props.registerId || 0,
    onCite: applyCitedRecord,
  });
  citeHistoryDrawerApi.open();
}

/**
 * 将选中的历史病历回填到当前编辑区（保留当前挂号关联 id）
 */
function applyCitedRecord(data: Record<string, any>) {
  const patientId = effectivePatientId.value;
  const keepIds = {
    id: form.id,
    register_id: props.registerId,
    store_id: props.storeId || form.store_id,
    user_patient_id: patientId,
  };
  Object.assign(form, data, keepIds);
  if (data.diagnosis) emit('update:diagnosis', data.diagnosis);
  if (data.doctor_order) emit('update:medicalAdvice', data.doctor_order);
  persistLocalDraft();
  emitSyncToPrescription();
  message.success('已引用历史病历');
}

defineExpose({
  save: handleSave,
  clear: handleClear,
  loadRecord,
  applyCitedRecord,
  openCiteHistory: handleCiteHistory,
  aiGenerate: handleAiGenerate,
  loading,
  getPayload: () => ({
    ...form,
    user_patient_id: effectivePatientId.value,
    diagnosis: diagnosisModel.value,
    doctor_order: medicalAdviceModel.value,
    // P4：随发处方同步保存病历的链路也带上 AI 生成 ID
    ai_generation_id: aiMrGenerationId.value || undefined,
  }),
  /** 外部局部回写（如 AI 出方预览点改） */
  patchFields,
});

/** source：走中医三典气泡；默认 entry 走病历词条 */
function fieldBlock(
  fieldCode: string,
  label: string,
  textKey?: string,
  source?: 'entry' | 'tcm_disease' | 'tcm_syndrome' | 'tcm_method',
  required = false,
) {
  return {
    fieldCode,
    label,
    textKey: textKey || fieldCode,
    source: source || 'entry',
    required,
  };
}

/** 中医病案内嵌：证候→疾病→治法（一行两列排布） */
const tcmCaseSubFields = [
  fieldBlock('tcm_syndrome', '中医证候', undefined, 'tcm_disease'),
  fieldBlock('tcm_disease', '中医疾病', undefined, 'tcm_syndrome'),
  fieldBlock('tcm_method', '中医治法', undefined, 'tcm_method'),
];

/**
 * 两列切块：证候|疾病、治法|空
 * 与舌象/脉象同一行两列布局一致
 */
const tcmCaseSubRows = [
  [tcmCaseSubFields[0], tcmCaseSubFields[1]],
  [tcmCaseSubFields[2], null],
] as const;

/**
 * 常规字段（不含健康史）：双列自动填满
 * 健康信息 / 中医病案各自成组，不混进本网格
 */
const allNormalFields = [
  fieldBlock('chief_complaint', '主诉', undefined, undefined, true),
  fieldBlock('treatment_advice', '治疗意见'),
  // 诊断/医嘱与处方 Tab 同源双向同步
  fieldBlock('diagnosis', '临床诊断'),
  fieldBlock('doctor_order', '医嘱'),
  fieldBlock('physical_exam', '体征检查'),
  fieldBlock('auxiliary_exam', '辅助检查'),
];

/** 健康信息分组：与就诊人健康问诊对齐（现病史 + 各类史） */
const allHealthFields = [
  fieldBlock('present_illness', '现病史'),
  fieldBlock('past_history', '既往史'),
  fieldBlock('allergy_history', '过敏史'),
  fieldBlock('family_history', '家族史'),
  fieldBlock('epidemic_history', '流行病学史'),
  fieldBlock('personal_history', '个人史'),
  fieldBlock('menstrual_history', '月经史'),
  fieldBlock('marital_history', '婚育史'),
];

const visibleNormalFields = computed(() => allNormalFields);

/** 月经史/婚育史按性别年龄过滤 */
const visibleHealthFields = computed(() =>
  allHealthFields.filter((f) =>
    isHistoryFieldVisible(f.fieldCode, props.patientSex, props.patientAge),
  ),
);
</script>
<template>
  <div
    ref="panelRootRef"
    class="medical-record-panel"
    :class="{ 'opacity-60': loading }"
    @keydown.capture="onPanelKeydownCapture"
  >
    <!-- 面板内工具栏（接诊台吸顶场景通过 showToolbar=false 隐藏） -->
    <div
      v-if="showToolbar"
      class="mr-toolbar mb-2 flex flex-wrap items-center gap-1"
    >
      <Button type="link" size="small" danger @click="handleClear">
        <ClearOutlined />
        清空病历
      </Button>
      <Button type="link" size="small" @click="handleCiteHistory">
        <HistoryOutlined />
        引用历史病历
      </Button>
      <Button
        v-if="canUseAiMedicalRecord"
        type="link"
        size="small"
        :loading="loading"
        @click="handleAiGenerate"
      >
        <RobotOutlined />
        AI写病历
      </Button>
      <Button
        type="link"
        size="small"
        :loading="loading"
        @click="handleSave"
      >
        <SaveOutlined />
        保存病历
      </Button>
    </div>
    <div class="mb-2 text-xs text-muted-foreground">
      提示：双击文本域可放大编辑；Ctrl+Enter 下一项，Ctrl+Shift+Enter 上一项
    </div>

    <!-- 常规字段：双列自动填满，避免一侧留白 -->
    <div class="mr-fields-grid">
      <div
        v-for="f in visibleNormalFields"
        :key="f.fieldCode"
        class="mr-field-block"
      >
        <div class="mr-field-head mb-1">
          <span class="mr-field-label">
            {{ f.label }}
            <em v-if="f.required" class="mr-field-required">*</em>
          </span>
          <!-- 诊断/医嘱走处方同源气泡；其余走病历词条 -->
          <div
            v-if="f.fieldCode === 'diagnosis'"
            class="mr-field-search"
            data-mr-module="diagnosis"
            data-mr-role="search"
          >
            <EntryKeywordBubble
              :ref="(el) => setSearchRef('diagnosis', el)"
              source="diagnosis"
              placeholder="诊断关键字"
              compact
              :show-common-in-bubble="showCommonInBubble"
              @select="(item) => onEntryPick('diagnosis', item)"
              @common-changed="commonChipsTick += 1"
            />
          </div>
          <div
            v-else-if="f.fieldCode === 'doctor_order'"
            class="mr-field-search"
            data-mr-module="doctor_order"
            data-mr-role="search"
          >
            <EntryKeywordBubble
              :ref="(el) => setSearchRef('doctor_order', el)"
              source="doctor_order"
              placeholder="医嘱关键字"
              compact
              :show-common-in-bubble="showCommonInBubble"
              @select="(item) => onEntryPick('doctor_order', item)"
              @common-changed="commonChipsTick += 1"
            />
          </div>
          <div
            v-else
            class="mr-field-search"
            :data-mr-module="f.fieldCode"
            data-mr-role="search"
          >
            <EntryKeywordBubble
              :ref="(el) => setSearchRef(f.fieldCode, el)"
              :field-code="f.fieldCode"
              :store-id="storeId"
              compact
              :show-common-in-bubble="showCommonInBubble"
              @select="(item) => onEntryPick(f.fieldCode, item)"
              @common-changed="commonChipsTick += 1"
            />
          </div>
        </div>
        <div
          v-if="f.fieldCode === 'physical_exam'"
          class="vitals-para mb-2"
        >
          <span class="vital-chunk">
            <span class="vital-label">体温(°C)</span>
            <InputNumber
              v-model:value="form.temperature"
              :min="0"
              :step="0.1"
              :bordered="false"
              class="vital-input"
              placeholder=" "
            />
          </span>
          <span class="vital-chunk">
            <span class="vital-label">身高(cm)</span>
            <InputNumber
              v-model:value="form.height"
              :min="0"
              :bordered="false"
              class="vital-input"
              placeholder=" "
            />
          </span>
          <span class="vital-chunk">
            <span class="vital-label">体重(KG)</span>
            <InputNumber
              v-model:value="form.weight"
              :min="0"
              :step="0.1"
              :bordered="false"
              class="vital-input"
              placeholder=" "
            />
          </span>
          <span class="vital-chunk">
            <span class="vital-label">呼吸(次/分)</span>
            <InputNumber
              v-model:value="form.respiratory_rate"
              :min="0"
              :bordered="false"
              class="vital-input vital-input--sm"
              placeholder=" "
            />
          </span>
          <span class="vital-chunk">
            <span class="vital-label">高压 mmHg</span>
            <InputNumber
              v-model:value="form.bp_systolic"
              :min="0"
              :bordered="false"
              class="vital-input vital-input--sm"
              placeholder=" "
            />
          </span>
          <span class="vital-sep">/</span>
          <span class="vital-chunk">
            <span class="vital-label">低压 mmHg</span>
            <InputNumber
              v-model:value="form.bp_diastolic"
              :min="0"
              :bordered="false"
              class="vital-input vital-input--sm"
              placeholder=" "
            />
          </span>
        </div>
        <template v-if="f.fieldCode === 'diagnosis'">
          <div data-mr-module="diagnosis" data-mr-role="textarea">
            <Textarea
              :ref="(el) => setTextareaRef('diagnosis', el)"
              v-model:value="diagnosisModel"
              :rows="2"
              :readonly="diagnosisReadonly"
              placeholder="临床诊断（与处方同步，双击放大）"
              @dblclick="openDiagnosisExpand"
            />
          </div>
          <CommonDxOrderChips
            v-if="showCommonTags && !diagnosisReadonly"
            :key="`dx_chips_${commonChipsTick}`"
            source="diagnosis"
            :field-value="diagnosisModel"
            @select="
              (text) =>
                onEntryPick('diagnosis', {
                  id: text,
                  title: text,
                  content: text,
                  remark: '',
                })
            "
          />
        </template>
        <template v-else-if="f.fieldCode === 'doctor_order'">
          <div data-mr-module="doctor_order" data-mr-role="textarea">
            <Textarea
              :ref="(el) => setTextareaRef('doctor_order', el)"
              v-model:value="medicalAdviceModel"
              :rows="2"
              placeholder="医嘱（与处方同步，双击放大）"
              @dblclick="openAdviceExpand"
            />
          </div>
          <CommonDxOrderChips
            v-if="showCommonTags"
            :key="`order_chips_${commonChipsTick}`"
            source="doctor_order"
            :field-value="medicalAdviceModel"
            @select="
              (text) =>
                onEntryPick('doctor_order', {
                  id: text,
                  title: text,
                  content: text,
                  remark: '',
                })
            "
          />
        </template>
        <template v-else>
          <div :data-mr-module="f.fieldCode" data-mr-role="textarea">
            <Textarea
              :ref="(el) => setTextareaRef(f.fieldCode, el)"
              v-model:value="(form as any)[f.textKey]"
              :rows="2"
              :placeholder="`[选择] ${f.label}（双击放大）`"
              @dblclick="openFieldExpand(f.textKey, f.label)"
            />
          </div>
          <CommonDxOrderChips
            v-if="showCommonTags"
            :key="`entry_chips_${f.fieldCode}_${commonChipsTick}`"
            source="entry"
            :field-code="f.fieldCode"
            :field-value="String((form as any)[f.textKey] || '')"
            @select="
              (text) =>
                onEntryPick(f.fieldCode, {
                  id: text,
                  title: text,
                  content: text,
                  remark: '',
                })
            "
          />
        </template>
      </div>
    </div>

    <!-- 健康信息：与中医病案同级分组（现病史 + 各类史） -->
    <div class="mr-health-block mb-4">
      <div class="mr-field-head mb-2">
        <span class="mr-field-label mr-field-label--section">健康信息</span>
      </div>
      <div class="mr-fields-grid">
        <div
          v-for="f in visibleHealthFields"
          :key="`health_${f.fieldCode}`"
          class="mr-field-block"
        >
          <div class="mr-field-head mb-1">
            <span class="mr-field-label mr-field-label--sub">{{ f.label }}</span>
            <div
              class="mr-field-search"
              :data-mr-module="f.fieldCode"
              data-mr-role="search"
            >
              <EntryKeywordBubble
                :ref="(el) => setSearchRef(f.fieldCode, el)"
                :field-code="f.fieldCode"
                :store-id="storeId"
                compact
                :show-common-in-bubble="showCommonInBubble"
                @select="(item) => onEntryPick(f.fieldCode, item)"
                @common-changed="commonChipsTick += 1"
              />
            </div>
          </div>
          <div :data-mr-module="f.fieldCode" data-mr-role="textarea">
            <Textarea
              :ref="(el) => setTextareaRef(f.fieldCode, el)"
              v-model:value="(form as any)[f.textKey]"
              :rows="2"
              :placeholder="`[选择] ${f.label}（双击放大）`"
              @dblclick="openFieldExpand(f.textKey, f.label)"
            />
          </div>
          <CommonDxOrderChips
            v-if="showCommonTags"
            :key="`entry_chips_${f.fieldCode}_${commonChipsTick}`"
            source="entry"
            :field-code="f.fieldCode"
            :field-value="String((form as any)[f.textKey] || '')"
            @select="
              (text) =>
                onEntryPick(f.fieldCode, {
                  id: text,
                  title: text,
                  content: text,
                  remark: '',
                })
            "
          />
        </div>
      </div>
    </div>

    <!-- 中医病案：置底全宽 -->
    <div class="mr-tcm-block mb-4">
      <div class="mr-field-head mb-2">
        <span class="mr-field-label mr-field-label--section">中医病案</span>
      </div>
      <div class="mb-2 flex gap-2">
        <div class="min-w-0 flex-1">
          <div class="mr-field-head mb-1">
            <span class="mr-field-label mr-field-label--sub">舌象</span>
            <div class="mr-field-search" data-mr-module="tongue" data-mr-role="search">
              <EntryKeywordBubble
                :ref="(el) => setSearchRef('tongue', el)"
                field-code="tongue"
                :store-id="storeId"
                placeholder="舌象词条"
                compact
                :show-common-in-bubble="showCommonInBubble"
                @select="(item) => onEntryPick('tongue', item)"
                @common-changed="commonChipsTick += 1"
              />
            </div>
          </div>
          <div data-mr-module="tongue" data-mr-role="textarea">
            <Input
              :ref="(el) => setTextareaRef('tongue', el)"
              v-model:value="form.tongue"
              placeholder="舌象"
              @dblclick="openFieldExpand('tongue', '舌象')"
            />
          </div>
          <CommonDxOrderChips
            v-if="showCommonTags"
            :key="`entry_chips_tongue_${commonChipsTick}`"
            source="entry"
            field-code="tongue"
            :field-value="form.tongue"
            @select="
              (text) =>
                onEntryPick('tongue', {
                  id: text,
                  title: text,
                  content: text,
                  remark: '',
                })
            "
          />
        </div>
        <div class="min-w-0 flex-1">
          <div class="mr-field-head mb-1">
            <span class="mr-field-label mr-field-label--sub">脉象</span>
            <div class="mr-field-search" data-mr-module="pulse" data-mr-role="search">
              <EntryKeywordBubble
                :ref="(el) => setSearchRef('pulse', el)"
                field-code="pulse"
                :store-id="storeId"
                placeholder="脉象词条"
                compact
                :show-common-in-bubble="showCommonInBubble"
                @select="(item) => onEntryPick('pulse', item)"
                @common-changed="commonChipsTick += 1"
              />
            </div>
          </div>
          <div data-mr-module="pulse" data-mr-role="textarea">
            <Input
              :ref="(el) => setTextareaRef('pulse', el)"
              v-model:value="form.pulse"
              placeholder="脉象"
              @dblclick="openFieldExpand('pulse', '脉象')"
            />
          </div>
          <CommonDxOrderChips
            v-if="showCommonTags"
            :key="`entry_chips_pulse_${commonChipsTick}`"
            source="entry"
            field-code="pulse"
            :field-value="form.pulse"
            @select="
              (text) =>
                onEntryPick('pulse', {
                  id: text,
                  title: text,
                  content: text,
                  remark: '',
                })
            "
          />
        </div>
      </div>
      <div class="mr-field-head mb-1">
        <span class="mr-field-label mr-field-label--sub">辨证 / 病案</span>
        <div class="mr-field-search" data-mr-module="tcm_case" data-mr-role="search">
          <EntryKeywordBubble
            :ref="(el) => setSearchRef('tcm_case', el)"
            field-code="tcm_case"
            :store-id="storeId"
            compact
            :show-common-in-bubble="showCommonInBubble"
            @select="(item) => onEntryPick('tcm_case', item)"
            @common-changed="commonChipsTick += 1"
          />
        </div>
      </div>
      <div class="mb-3" data-mr-module="tcm_case" data-mr-role="textarea">
        <Textarea
          :ref="(el) => setTextareaRef('tcm_case', el)"
          v-model:value="form.tcm_case"
          :rows="2"
          placeholder="[选择] 辨证/病案（双击放大）"
          @dblclick="openFieldExpand('tcm_case', '辨证/病案')"
        />
      </div>
      <CommonDxOrderChips
        v-if="showCommonTags"
        :key="`entry_chips_tcm_case_${commonChipsTick}`"
        class="mb-3"
        source="entry"
        field-code="tcm_case"
        :field-value="form.tcm_case"
        @select="
          (text) =>
            onEntryPick('tcm_case', {
              id: text,
              title: text,
              content: text,
              remark: '',
            })
        "
      />
      <div
        v-for="(tcmRow, tcmRowIdx) in tcmCaseSubRows"
        :key="`tcm_row_${tcmRowIdx}`"
        class="mb-2 flex gap-2"
      >
        <div
          v-for="(sub, colIdx) in tcmRow"
          :key="sub ? sub.fieldCode : `empty_${tcmRowIdx}_${colIdx}`"
          class="min-w-0 flex-1"
        >
          <template v-if="sub">
            <div class="mr-field-head mb-1">
              <span class="mr-field-label mr-field-label--sub">{{ sub.label }}</span>
              <div
                class="mr-field-search"
                :data-mr-module="sub.fieldCode"
                data-mr-role="search"
              >
                <EntryKeywordBubble
                  :ref="(el) => setSearchRef(sub.fieldCode, el)"
                  :source="sub.source"
                  :placeholder="`${sub.label}关键字`"
                  compact
                  @select="(item) => onEntryPick(sub.fieldCode, item)"
                />
              </div>
            </div>
            <div :data-mr-module="sub.fieldCode" data-mr-role="textarea">
              <Input
                :ref="(el) => setTextareaRef(sub.fieldCode, el)"
                v-model:value="(form as any)[sub.textKey]"
                :placeholder="sub.label"
                @dblclick="openFieldExpand(sub.textKey, sub.label)"
              />
            </div>
          </template>
        </div>
      </div>
    </div>

    <ExpandModal />
    <CiteHistoryDrawer />
    <HistoryImportModalHost />
    <AiMedicalRecordModal
      ref="aiMedicalRecordModalRef"
      @import="handleImportAiMedicalRecord"
      @sync-medical-record="handleSyncAiMedicalRecord"
    />
  </div>
</template>
<style scoped>
.medical-record-panel {
  padding: 8px 0 24px;
}
.mr-toolbar :deep(.ant-btn) {
  padding-inline: 6px;
  height: 28px;
}
/* 双列流式排布：字段从左到右、从上到下填满，不再一侧空一大块 */
.mr-fields-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
  margin-bottom: 8px;
}
.mr-field-block {
  min-width: 0;
}
.mr-field-head {
  display: flex;
  flex-wrap: nowrap;
  gap: 8px 12px;
  align-items: center;
  min-height: 28px;
}
.mr-field-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  min-width: 5.5em;
  font-size: 14px;
  font-weight: 600;
  line-height: 24px;
  white-space: nowrap;
  color: hsl(var(--foreground));
}
.mr-field-required {
  font-style: normal;
  font-weight: 700;
  color: #cf1322;
  margin-left: 2px;
}
/* 一级 label 前置色条：醒目分区 */
.mr-field-label::before {
  content: '';
  flex-shrink: 0;
  width: 3px;
  height: 14px;
  border-radius: 2px;
  background: hsl(var(--primary));
}
/* 区块标题（如中医病案）：更大、更醒目 */
.mr-field-label--section {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.mr-field-label--section::before {
  width: 4px;
  height: 16px;
  background: hsl(173 58% 39%);
}
/* 二级 label：圆点 + 更小更淡，一眼能区分层级 */
.mr-field-label--sub {
  min-width: 5em;
  font-size: 12px;
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}
.mr-field-label--sub::before {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: hsl(173 45% 45%);
  opacity: 0.9;
}
.mr-field-search {
  min-width: 0;
  flex: 1 1 auto;
}
.mr-health-block,
.mr-tcm-block {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed hsl(var(--border));
}
/* 体征一段话：标签 + 下划线输入横向流式排布 */
.vitals-para {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 14px;
  row-gap: 10px;
  line-height: 2;
  font-size: 13px;
  color: hsl(var(--muted-foreground));
}
.vitals-para .vital-chunk {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
}
.vitals-para .vital-label {
  color: hsl(var(--muted-foreground));
  font-size: 13px;
}
.vitals-para .vital-sep {
  color: hsl(var(--muted-foreground));
  margin: 0 2px;
}
.vitals-para :deep(.vital-input.ant-input-number),
.vitals-para :deep(.vital-input .ant-input-number) {
  width: 72px;
  border: none !important;
  border-bottom: 1px solid hsl(var(--border)) !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  background: transparent;
}
.vitals-para :deep(.vital-input--sm.ant-input-number),
.vitals-para :deep(.vital-input--sm .ant-input-number) {
  width: 64px;
}
.vitals-para :deep(.ant-input-number-input) {
  text-align: center;
  padding: 0 4px !important;
  height: 28px !important;
}
.vitals-para :deep(.ant-input-number-focused),
.vitals-para :deep(.ant-input-number:hover) {
  border-bottom-color: hsl(var(--primary)) !important;
  box-shadow: none !important;
}
.vitals-para :deep(.ant-input-number-handler-wrap) {
  display: none;
}
</style>
