<template>
  <!--
    医生小程序病历面板
    诊断/医嘱与处方同源：emit 打开父页常用诊断/常用医嘱弹窗
    其余字段走病历词条抽屉
    模板禁止 ?? ?. 与 :class 方法调用
  -->
  <view class="mr-panel">
    <scroll-view scroll-y class="mr-scroll" :enable-back-to-top="true">
      <view class="mr-scroll-inner">

        <!-- 诊断卡片 -->
        <view class="mr-card mr-card--primary">
          <view class="mr-card__header">
            <view class="mr-card__header-dot mr-card__header-dot--primary" />
            <text class="mr-card__title">诊断</text>
            <text class="mr-card__sync-badge">与处方同步</text>
          </view>
          <view class="mr-entry-btn" @click="onOpenDiagnosis">
            <text class="mr-entry-btn__icon">+</text>
            <text class="mr-entry-btn__text">{{ diagnosisReadonly ? '去选择常用诊断' : '选择常用诊断' }}</text>
            <text class="mr-entry-btn__arrow">›</text>
          </view>
          <u-input
              v-model="localDiagnosis"
              type="textarea"
              :auto-height="true"
              :disabled="diagnosisReadonly"
              :placeholder="diagnosisReadonly ? '请通过常用诊断选择' : '临床诊断'"
              :custom-style="areaStyle"
              @input="emitDiagnosis"
          />
        </view>

        <view v-for="item in leftFields" :key="item.code" class="mr-card">
          <view class="mr-card__header">
            <view class="mr-card__header-dot" />
            <text class="mr-card__title">{{ item.label }}</text>
          </view>
          <!-- 中医病案：舌脉 → 辨证 → 证候|疾病 → 治法 -->
          <view v-if="item.code === 'tcm_case'">
            <view class="mr-tcm-tongue-row">
              <view class="mr-entry-btn mr-entry-btn--half" @click="openEntry('tongue')">
                <text class="mr-entry-btn__icon">+</text>
                <text class="mr-entry-btn__text">舌象词条</text>
                <text class="mr-entry-btn__arrow">›</text>
              </view>
              <view class="mr-entry-btn mr-entry-btn--half" @click="openEntry('pulse')">
                <text class="mr-entry-btn__icon">+</text>
                <text class="mr-entry-btn__text">脉象词条</text>
                <text class="mr-entry-btn__arrow">›</text>
              </view>
            </view>
            <view class="mr-tcm-input-row">
              <u-input v-model="form.tongue" placeholder="舌象" class="flex-1 m-r-8" />
              <u-input v-model="form.pulse" placeholder="脉象" class="flex-1" />
            </view>
            <view class="mr-entry-btn" @click="openEntry('tcm_case')">
              <text class="mr-entry-btn__icon">+</text>
              <text class="mr-entry-btn__text">选择辨证/病案词条</text>
              <text class="mr-entry-btn__arrow">›</text>
            </view>
            <u-input
                v-model="form.tcm_case"
                type="textarea"
                :auto-height="true"
                placeholder="辨证/病案"
                :custom-style="areaStyle"
                class="m-b-8"
            />
            <view
                v-for="row in tcmCaseSubRows"
                :key="row.key"
                class="mr-tcm-sub-row"
            >
              <view
                  v-for="(sub, colIdx) in row.cols"
                  :key="sub._key"
                  class="mr-tcm-sub-col"
                  :class="{ 'mr-tcm-sub-col--left': colIdx === 0 }"
              >
                <view v-if="!sub._empty">
                  <text class="mr-sub-label">{{ sub.label }}</text>
                  <view class="mr-entry-btn" @click="openTcmEntry(sub)">
                    <text class="mr-entry-btn__icon">+</text>
                    <text class="mr-entry-btn__text">选择{{ sub.label }}</text>
                    <text class="mr-entry-btn__arrow">›</text>
                  </view>
                  <u-input v-model="form[sub.code]" :placeholder="sub.label" />
                </view>
              </view>
            </view>
          </view>
          <view
              v-else-if="item.code === 'doctor_order'"
              class="mr-entry-btn"
              @click="onOpenDoctorOrder"
          >
            <text class="mr-entry-btn__icon">+</text>
            <text class="mr-entry-btn__text">选择常用医嘱</text>
            <text class="mr-entry-btn__arrow">›</text>
          </view>
          <view
              v-else
              class="mr-entry-btn"
              @click="openEntry(item.code)"
          >
            <text class="mr-entry-btn__icon">+</text>
            <text class="mr-entry-btn__text">选择{{ item.label }}词条</text>
            <text class="mr-entry-btn__arrow">›</text>
          </view>
          <u-input
              v-if="item.code === 'doctor_order'"
              v-model="localAdvice"
              type="textarea"
              :auto-height="true"
              placeholder="医嘱（与处方同步）"
              :custom-style="areaStyle"
              @input="emitAdvice"
          />
          <u-input
              v-else-if="item.code !== 'tcm_case'"
              v-model="form[item.code]"
              type="textarea"
              :auto-height="true"
              :placeholder="item.label"
              :custom-style="areaStyle"
          />
        </view>

        <view v-for="item in rightFields" :key="item.code" class="mr-card">
          <view class="mr-card__header">
            <view class="mr-card__header-dot mr-card__header-dot--secondary" />
            <text class="mr-card__title">{{ item.label }}</text>
          </view>
          <view class="mr-entry-btn" @click="openEntry(item.code)">
            <text class="mr-entry-btn__icon">+</text>
            <text class="mr-entry-btn__text">选择{{ item.label }}词条</text>
            <text class="mr-entry-btn__arrow">›</text>
          </view>
          <!-- 体征：网格卡片式 -->
          <view v-if="item.code === 'physical_exam'" class="vitals-grid">
            <view class="vital-cell">
              <text class="vital-cell__label">体温</text>
              <text class="vital-cell__unit">°C</text>
              <input
                  class="vital-cell__input"
                  type="digit"
                  :value="form.temperature"
                  placeholder="—"
                  @input="onVitalInput('temperature', $event)"
              />
            </view>
            <view class="vital-cell">
              <text class="vital-cell__label">身高</text>
              <text class="vital-cell__unit">cm</text>
              <input
                  class="vital-cell__input"
                  type="digit"
                  :value="form.height"
                  placeholder="—"
                  @input="onVitalInput('height', $event)"
              />
            </view>
            <view class="vital-cell">
              <text class="vital-cell__label">体重</text>
              <text class="vital-cell__unit">kg</text>
              <input
                  class="vital-cell__input"
                  type="digit"
                  :value="form.weight"
                  placeholder="—"
                  @input="onVitalInput('weight', $event)"
              />
            </view>
            <view class="vital-cell">
              <text class="vital-cell__label">呼吸</text>
              <text class="vital-cell__unit">次/分</text>
              <input
                  class="vital-cell__input"
                  type="number"
                  :value="form.respiratory_rate"
                  placeholder="—"
                  @input="onVitalInput('respiratory_rate', $event)"
              />
            </view>
            <view class="vital-cell vital-cell--bp">
              <text class="vital-cell__label">血压</text>
              <text class="vital-cell__unit">mmHg</text>
              <view class="vital-cell__bp-row">
                <input
                    class="vital-cell__input vital-cell__input--bp"
                    type="number"
                    :value="form.bp_systolic"
                    placeholder="收缩"
                    @input="onVitalInput('bp_systolic', $event)"
                />
                <text class="vital-cell__bp-sep">/</text>
                <input
                    class="vital-cell__input vital-cell__input--bp"
                    type="number"
                    :value="form.bp_diastolic"
                    placeholder="舒张"
                    @input="onVitalInput('bp_diastolic', $event)"
                />
              </view>
            </view>
          </view>
          <u-input
              v-model="form[item.code]"
              type="textarea"
              :auto-height="true"
              :placeholder="item.label"
              :custom-style="areaStyle"
          />
        </view>

      </view>
    </scroll-view>

    <!-- 底部操作栏：与处方发送栏一致；仅病历 Tab 可见（避免 probe 时 fixed 穿透） -->
    <view v-if="active" class="mr-bottom safe-area-inset-bottom">
      <view class="mr-bottom-left flex-row flex-ali-center">
        <view class="mr-btn-text mr-btn-text--danger" @click="onClear">清空</view>
        <view class="mr-btn-text" @click="onOpenCiteDrawer">引用历史</view>
      </view>
      <view class="flex-row flex-ali-center">
        <!-- 无 VIP ai_medical_record 时隐藏入口 -->
        <view
          v-if="canUseAiMedicalRecord"
          class="mr-ai-btn"
          @click="onOpenAiModal"
        >
          <text class="mr-ai-btn__icon">✦</text>
          <text class="mr-ai-btn__text">AI写病历</text>
        </view>
        <u-button
            :throttle-time="0"
            shape="circle"
            :custom-style="saveBtnStyle"
            @click="onSave"
        >
          保存病历
        </u-button>
      </view>
    </view>

    <!--
      引用/词条抽屉用 u-popup：本页顶部已有返回拦截 page-container，
      微信限制一页只能有一个 page-container，不能再套第二个。
    -->
    <u-popup
        v-model="citeShow"
        mode="bottom"
        border-radius="24"
        :safe-area-inset-bottom="true"
        :mask-close-able="true"
        height="78%"
        z-index="10090"
        @close="closeCiteDrawer"
    >
      <view class="cite-drawer">
        <view class="drawer-handle" />
        <view class="drawer-header">
          <text class="drawer-header__title">引用历史病历</text>
          <text class="drawer-header__count">共 {{ citeList.length }} 条</text>
        </view>
        <scroll-view scroll-y class="cite-scroll">
          <view v-if="citeLoading" class="drawer-empty">加载中…</view>
          <block v-else>
            <view v-if="!citeList.length" class="drawer-empty">暂无历史病历</view>
            <block v-else>
              <view
                  v-for="row in citeList"
                  :key="row.id"
                  class="cite-item"
                  :class="{ 'cite-item--active': citeActiveId == row.id }"
                  @click="onSelectCite(row)"
              >
                <view class="cite-item__check" :class="{ 'cite-item__check--on': citeActiveId == row.id }">
                  <text v-if="citeActiveId == row.id" class="cite-item__check-icon">✓</text>
                </view>
                <view class="cite-item__body">
                  <view class="cite-item__title">{{ row._title }}</view>
                  <view class="cite-item__meta">
                    <text class="cite-tag">挂号 #{{ row.register_id || '-' }}</text>
                    <text v-if="row._isCurrent" class="cite-tag cite-tag--warn">本次挂号</text>
                    <text class="cite-time">{{ row.created_at || '—' }}</text>
                  </view>
                  <view v-if="row.chief_complaint" class="cite-item__sub">主诉：{{ row.chief_complaint }}</view>
                </view>
              </view>
            </block>
          </block>
        </scroll-view>
        <view v-if="citeActiveRecord" class="cite-preview">
          <view class="cite-preview__row">
            <text class="cite-preview__label">诊断</text>
            <text class="cite-preview__val">{{ citeActiveRecord.diagnosis || '—' }}</text>
          </view>
          <view class="cite-preview__row">
            <text class="cite-preview__label">医嘱</text>
            <text class="cite-preview__val">{{ citeActiveRecord.doctor_order || '—' }}</text>
          </view>
          <text
              v-if="citeActiveRecord._isCurrent"
              class="cite-preview__tip"
          >当前选中的是本次挂号病历，引用后会覆盖编辑区内容</text>
        </view>
        <view class="cite-footer safe-area-inset-bottom">
          <u-button
              :throttle-time="0"
              shape="circle"
              :disabled="!citeActiveId"
              :custom-style="citeConfirmStyle"
              @click="onConfirmCite"
          >
            引用此病历
          </u-button>
        </view>
      </view>
    </u-popup>

    <u-popup
        v-model="entryShow"
        mode="bottom"
        border-radius="24"
        :safe-area-inset-bottom="true"
        :mask-close-able="true"
        height="85%"
        z-index="10090"
        @close="closeEntryDrawer"
    >
      <!-- 词条抽屉：头固定 + 列表区可滑（与诊断弹窗同结构，避免 scroll-view 高度塌缩） -->
      <view class="entry-drawer">
        <view class="entry-drawer__hd">
          <view class="drawer-handle" />
          <view class="drawer-header">
            <text class="drawer-header__title">选择词条</text>
            <text class="drawer-header__count">{{ entryKeyword ? ('搜到 ' + entryList.length + ' 条') : ('共 ' + entryList.length + ' 条') }}</text>
          </view>
          <u-input
              v-model="entryKeyword"
              placeholder="搜索名称/内容/首拼"
              :custom-style="entrySearchStyle"
              @input="onEntryKeywordInput"
          />
        </view>
        <scroll-view scroll-y class="entry-scroll" enable-flex>
          <view class="entry-scroll-inner">
            <view
                v-for="row in entryList"
                :key="row.id"
                class="entry-row"
                @click="pickEntry(row)"
            >
              <view class="entry-row-top">
                <view class="entry-row-name">
                  <!-- 非 H5 :key 仅支持简单变量，禁止 't'+pi 这类拼接 -->
                  <block v-for="(p, pi) in (row._titleParts || [])" :key="pi">
                    <text v-if="p.hit" class="hit-text">{{ p.text }}</text>
                    <text v-else>{{ p.text }}</text>
                  </block>
                </view>
                <text v-if="entryKeyword" class="entry-score">{{ row.match_score || 0 }}%</text>
              </view>
              <!-- 正文多行展示，行高收紧以一屏多看几条 -->
              <view v-if="row.content" class="entry-row-content">
                <block v-for="(p, pi) in (row._contentParts || [])" :key="pi">
                  <text v-if="p.hit" class="hit-text">{{ p.text }}</text>
                  <text v-else>{{ p.text }}</text>
                </block>
              </view>
              <view
                  v-if="row.remark || (entryKeyword && row.pinyin_initials)"
                  class="entry-row-meta"
              >
                <text v-if="row.remark" class="entry-remark-tag">{{ row.remark }}</text>
                <text v-if="entryKeyword && row.pinyin_initials" class="entry-py-tag">
                  <block v-for="(p, pi) in (row._pyParts || [])" :key="pi">
                    <text v-if="p.hit" class="hit-text">{{ p.text }}</text>
                    <text v-else>{{ p.text }}</text>
                  </block>
                </text>
              </view>
            </view>
            <view v-if="!entryList.length" class="drawer-empty">暂无词条</view>
          </view>
        </scroll-view>
      </view>
    </u-popup>

    <!-- AI写病历：历史抽屉 + 二级生成（与出方一致） -->
    <!-- 注意：模板禁止 || {} / ?? / ?.，空对象字面量会编译成 WXML 的 $ 报错 -->
    <AiMedicalRecordDrawer
        v-model="aiShow"
        :register-id="registerId"
        :store-id="storeId"
        :patient-name="patientName"
        :patient-sex="patientSex"
        :patient-age="patientAge"
        :chief-complaint="(form && form.chief_complaint) || ''"
        :medical-record="form"
        @overlay-change="onAiOverlayChange"
        @import="onAiConfirmImport"
    />
  </view>
</template>
<script>
/**
 * 病历面板：与处方诊断/医嘱双向同步
 * 诊断/医嘱选用走父页常用诊断、常用医嘱弹窗
 */
import {
  clearMedicalRecordApi,
  getMedicalRecordApi,
  getTraditionalChineseMedicineJson,
  listMedicalRecordByPatientApi,
  saveMedicalRecordApi,
  searchMedicalRecordEntryApi,
} from '@/api/reception.js'
import AiMedicalRecordDrawer from './AiMedicalRecordDrawer.vue'
import { PrescriptionStorage } from '../utils/prescriptionStorage.js'
import {
  applyDictRankAndHighlight,
  splitHighlight,
} from '../utils/dictSearchRank.js'

function emptyForm() {
  return {
    chief_complaint: '',
    present_illness: '',
    tcm_disease: '',
    tcm_syndrome: '',
    tcm_method: '',
    tongue: '',
    pulse: '',
    tcm_case: '',
    treatment_advice: '',
    doctor_order: '',
    diagnosis: '',
    family_history: '',
    epidemic_history: '',
    past_history: '',
    menstrual_history: '',
    marital_history: '',
    personal_history: '',
    allergy_history: '',
    physical_exam: '',
    auxiliary_exam: '',
    temperature: '',
    height: '',
    weight: '',
    respiratory_rate: '',
    bp_systolic: '',
    bp_diastolic: '',
    user_patient_id: 0,
  }
}

/**
 * 月经史仅女；婚育史男>22或女>20；个人史始终
 */
function isHistoryFieldVisible(fieldCode, sex, age) {
  if (fieldCode === 'menstrual_history') {
    return Number(sex) === 2
  }
  if (fieldCode === 'marital_history') {
    const s = Number(sex)
    const a = Number(age) || 0
    return (s === 1 && a > 22) || (s === 2 && a > 20)
  }
  return true
}

/**
 * 拼出 首拼(全拼) 展示（与 PC 病历气泡一致）
 */
function formatPyDisplayOf(item) {
  if (!item) return ''
  const display = String(item.pinyin_display || '').trim()
  if (display) return display
  const initials = String(item.pinyin_initials || '').trim()
  if (initials.indexOf('(') >= 0 && initials.slice(-1) === ')') return initials
  const abbr = String(item.pinyin || initials || item.initials_of_pinyin || '').trim()
  const full = String(item.pinyin_full || '').trim()
  if (!abbr && !full) return ''
  if (!full || abbr.toLowerCase() === full.toLowerCase()) return abbr || full
  if (!abbr) return '(' + full + ')'
  return abbr + '(' + full + ')'
}

export default {
  name: 'MedicalRecordPanel',
  components: {
    AiMedicalRecordDrawer,
  },
  props: {
    registerId: { type: [Number, String], default: 0 },
    storeId: { type: [Number, String], default: 0 },
    userPatientId: { type: [Number, String], default: 0 },
    diagnosis: { type: String, default: '' },
    medicalAdvice: { type: String, default: '' },
    /** 在线复诊：诊断只读，必须点选 */
    diagnosisReadonly: { type: Boolean, default: false },
    /** 是否处于病历 Tab（控制底部栏；probe 时必须为 false，否则 fixed 会穿透到处方） */
    active: { type: Boolean, default: false },
    /** 门店是否开通病历 VIP（medical_record）；无则不请求病历接口，避免弹错 */
    canUseMedicalRecord: { type: Boolean, default: false },
    /** 就诊人姓名（AI 确认步展示） */
    patientName: { type: String, default: '' },
    /** 就诊人性别 1男2女 */
    patientSex: { type: [Number, String], default: 0 },
    /** 就诊人年龄 */
    patientAge: { type: [Number, String], default: 0 },
    /** 门店是否开通 AI写病历 VIP（ai_medical_record） */
    canUseAiMedicalRecord: { type: Boolean, default: false },
  },
  data() {
    const tcmCaseSubFields = [
      { code: 'tcm_syndrome', label: '中医证候', tcmType: 'syndrome', _key: 'tcm_syndrome' },
      { code: 'tcm_disease', label: '中医疾病', tcmType: 'diseases', _key: 'tcm_disease' },
      { code: 'tcm_method', label: '中医治法', tcmType: 'method', _key: 'tcm_method' },
    ]
    return {
      form: emptyForm(),
      localDiagnosis: '',
      localAdvice: '',
      entryShow: false,
      entryField: '',
      entryList: [],
      entryKeyword: '',
      entrySearchTimer: null,
      entrySearchStyle: {
        background: '#f4f6f8',
        borderRadius: '14rpx',
        padding: '12rpx 20rpx',
        border: '1rpx solid #e8ecef',
      },
      /** 引用历史抽屉 */
      citeShow: false,
      citeLoading: false,
      citeList: [],
      citeActiveId: 0,
      saveBtnStyle: {
        backgroundColor: '#6ACDBB',
        color: '#fff',
        height: '86rpx',
        width: '220rpx',
      },
      citeConfirmStyle: {
        backgroundColor: '#6ACDBB',
        color: '#fff',
        height: '86rpx',
        width: '100%',
      },
      hydrating: false,
      // AI写病历抽屉显隐
      aiShow: false,
      _draftTimer: null,
      areaStyle: { background: '#f4f6f8', borderRadius: '12rpx', padding: '18rpx', minHeight: '80rpx', fontSize: '28rpx', color: '#1a2530', lineHeight: '1.6' },
      leftFields: [
        { code: 'chief_complaint', label: '主诉' },
        { code: 'present_illness', label: '现病史' },
        { code: 'tcm_case', label: '中医病案' },
        { code: 'treatment_advice', label: '治疗意见' },
        { code: 'doctor_order', label: '医嘱' },
      ],
      /** 中医病案内嵌：证候→疾病→治法（一行两列；_key 供小程序 :key 绑定） */
      tcmCaseSubFields,
      tcmCaseSubRows: [
        {
          key: 'r0',
          cols: [tcmCaseSubFields[0], tcmCaseSubFields[1]],
        },
        {
          key: 'r1',
          cols: [tcmCaseSubFields[2], { _key: 'empty', _empty: true }],
        },
      ],
      /** 中医三典当前抽屉类型 diseases|syndrome|method，空=病历词条 */
      entryTcmType: '',
      allRightFields: [
        { code: 'family_history', label: '家族史' },
        { code: 'epidemic_history', label: '流行病学史' },
        { code: 'past_history', label: '既往史' },
        { code: 'menstrual_history', label: '月经史' },
        { code: 'marital_history', label: '婚育史' },
        { code: 'personal_history', label: '个人史' },
        { code: 'allergy_history', label: '过敏史' },
        { code: 'physical_exam', label: '体征检查' },
        { code: 'auxiliary_exam', label: '辅助检查' },
      ],
    }
  },
  computed: {
    /** 右栏按性别年龄过滤月经史/婚育史 */
    rightFields() {
      const sex = Number(this.patientSex || 0)
      const age = Number(this.patientAge || 0)
      return (this.allRightFields || []).filter((f) =>
          isHistoryFieldVisible(f.code, sex, age),
      )
    },
    sexLabel() {
      const s = Number(this.patientSex)
      if (s === 1) return '男'
      if (s === 2) return '女'
      return '未知'
    },
    /** props 优先，其次病历回填 */
    effectivePatientId() {
      return Number(this.userPatientId || this.form.user_patient_id || 0)
    },
    /** 引用抽屉当前选中记录 */
    citeActiveRecord() {
      const id = Number(this.citeActiveId || 0)
      if (!id) return null
      const list = this.citeList || []
      for (let i = 0; i < list.length; i++) {
        if (Number(list[i].id) === id) return list[i]
      }
      return null
    },
  },
  watch: {
    registerId: {
      immediate: true,
      handler() {
        this.tryLoad()
      },
    },
    canUseMedicalRecord() {
      this.tryLoad()
    },
    diagnosis(v) {
      this.localDiagnosis = v || ''
      this.schedulePersistDraft()
    },
    medicalAdvice(v) {
      this.localAdvice = v || ''
      this.schedulePersistDraft()
    },
    form: {
      deep: true,
      handler() {
        this.schedulePersistDraft()
      },
    },
    /** 抽屉开合同步给父页，用于 page-container 返回拦截 */
    citeShow() {
      this.emitOverlayChange()
    },
    entryShow() {
      this.emitOverlayChange()
    },
    aiShow() {
      this.emitOverlayChange()
    },
  },
  methods: {
    /**
     * 仅在有病历 VIP 时拉病历；普通诊所静默跳过，不弹「未开通 VIP」
     */
    tryLoad() {
      if (!this.registerId || !this.canUseMedicalRecord) {
        return
      }
      this.load()
    },
    /**
     * 通知父页：病历侧是否有弹层打开（与处方弹层共用返回拦截）
     */
    emitOverlayChange() {
      this.$emit('overlay-change', !!(this.citeShow || this.entryShow || this.aiShow))
    },
    /**
     * 供父页返回键先关抽屉（不退开方页）
     */
    closeOverlays() {
      this.citeShow = false
      this.entryShow = false
      this.entryTcmType = ''
      this.closeAiModal()
    },
    closeAiModal() {
      this.aiShow = false
    },
    onAiOverlayChange(open) {
      this.aiShow = !!open
      this.emitOverlayChange()
    },
    /**
     * 打开 AI 写病历：先进历史抽屉（无历史则自动弹出生成框）
     */
    onOpenAiModal() {
      if (!this.canUseAiMedicalRecord) {
        uni.showToast({ title: '当前门店未开通AI写病历', icon: 'none' })
        return
      }
      if (!this.registerId) {
        uni.showToast({ title: '挂号无效', icon: 'none' })
        return
      }
      if (!this.effectivePatientId) {
        uni.showToast({ title: '请先选择患者', icon: 'none' })
        return
      }
      this.aiShow = true
    },
    closeCiteDrawer() {
      this.citeShow = false
    },
    closeEntryDrawer() {
      this.entryShow = false
      this.entryTcmType = ''
    },
    emitDiagnosis() {
      if (this.diagnosisReadonly) return
      this.$emit('update:diagnosis', this.localDiagnosis || '')
      this.schedulePersistDraft()
    },
    emitAdvice() {
      this.$emit('update:medicalAdvice', this.localAdvice || '')
      this.schedulePersistDraft()
    },
    onOpenDiagnosis() {
      this.$emit('open-diagnosis')
    },
    onOpenDoctorOrder() {
      this.$emit('open-doctor-order')
    },
    /**
     * 体征原生 input 回填（不用 u-input，避免撑满成表单行）
     */
    onVitalInput(field, e) {
      const val = e && e.detail ? e.detail.value : ''
      this.form[field] = val
      this.schedulePersistDraft()
    },
    schedulePersistDraft() {
      if (this.hydrating || !this.registerId) return
      if (this._draftTimer) clearTimeout(this._draftTimer)
      this._draftTimer = setTimeout(() => {
        this.persistDraft()
      }, 300)
    },
    persistDraft() {
      if (!this.registerId || this.hydrating) return
      PrescriptionStorage.saveMedicalRecordDraft(this.registerId, this.getPayload())
    },
    applyDraft(draft) {
      if (!draft) return
      this.form = Object.assign(emptyForm(), draft, {
        user_patient_id: this.userPatientId || draft.user_patient_id || 0,
      })
      if (draft.diagnosis) {
        this.localDiagnosis = draft.diagnosis
        this.$emit('update:diagnosis', draft.diagnosis)
      }
      if (draft.doctor_order || draft.medicalAdvice) {
        this.localAdvice = draft.doctor_order || draft.medicalAdvice || ''
        this.$emit('update:medicalAdvice', this.localAdvice)
      }
    },
    async load() {
      this.hydrating = true
      try {
        const mrParams = { register_id: this.registerId }
        const mrStoreId = Number(this.storeId || 0)
        if (mrStoreId > 0) mrParams.store_id = mrStoreId
        const res = await getMedicalRecordApi(mrParams)
        // Laravel jok 在 result；兼容 data / 已解包
        const data = (res && (res.result != null ? res.result : res.data)) || res || {}
        this.form = Object.assign(emptyForm(), data)
        const draft = PrescriptionStorage.loadMedicalRecordDraft(this.registerId)
        if (draft) {
          this.applyDraft(draft)
        } else {
          if (!this.diagnosis && data.diagnosis) {
            this.$emit('update:diagnosis', data.diagnosis)
          }
          if (!this.medicalAdvice && data.doctor_order) {
            this.$emit('update:medicalAdvice', data.doctor_order)
          }
          this.localDiagnosis = this.diagnosis || data.diagnosis || ''
          this.localAdvice = this.medicalAdvice || data.doctor_order || ''
        }
        if (this.diagnosis) this.localDiagnosis = this.diagnosis
        if (this.medicalAdvice) this.localAdvice = this.medicalAdvice
      } catch (e) {
        // 有 VIP 才请求；若仍失败（网络等）仅回填本地草稿，不再靠 VIP 文案探测
        const draft = PrescriptionStorage.loadMedicalRecordDraft(this.registerId)
        if (draft) {
          this.applyDraft(draft)
        }
      } finally {
        this.hydrating = false
      }
    },
    getPayload() {
      return Object.assign({}, this.form, {
        register_id: Number(this.registerId),
        store_id: Number(this.storeId || 0),
        user_patient_id: this.effectivePatientId,
        diagnosis: this.localDiagnosis,
        doctor_order: this.localAdvice,
        medicalAdvice: this.localAdvice,
      })
    },
    /**
     * 外部局部回写病历（AI 出方预览点改），同步表单与草稿，不强制落库
     */
    patchFields(partial) {
      if (!partial || typeof partial !== 'object') return
      const keys = Object.keys(partial)
      for (let i = 0; i < keys.length; i++) {
        const k = keys[i]
        const val = partial[k] == null ? '' : String(partial[k])
        if (k === 'diagnosis') {
          this.localDiagnosis = val
          this.form.diagnosis = val
          this.$emit('update:diagnosis', val)
          continue
        }
        if (k === 'doctor_order' || k === 'medicalAdvice') {
          this.localAdvice = val
          this.form.doctor_order = val
          this.$emit('update:medicalAdvice', val)
          continue
        }
        if (Object.prototype.hasOwnProperty.call(this.form, k)) {
          this.form[k] = val
        }
      }
      this.persistDraft()
    },
    async onSave() {
      await saveMedicalRecordApi(this.getPayload())
      this.persistDraft()
      uni.showToast({ title: '病历已保存', icon: 'success' })
    },
    /**
     * 确认导入：回填表单草稿（含可编辑主诉），不自动保存病历
     */
    onAiConfirmImport(payload) {
      const fields = (payload && payload.fields) || {}
      const chief = String((payload && payload.chief_complaint) || '').trim()
      Object.keys(fields).forEach((k) => {
        if (k === 'chief_complaint' || k === 'name') return
        if (k === 'diagnosis') {
          const dx = fields[k] == null ? '' : String(fields[k])
          this.form.diagnosis = dx
          this.localDiagnosis = dx
          this.$emit('update:diagnosis', dx)
          return
        }
        if (Object.prototype.hasOwnProperty.call(this.form, k)) {
          this.form[k] = fields[k] == null ? '' : String(fields[k])
        }
      })
      if (chief) this.form.chief_complaint = chief
      this.schedulePersistDraft()
      this.closeAiModal()
      uni.showToast({ title: '已导入，请核对后保存', icon: 'none' })
    },
    async onClear() {
      const clearParams = { register_id: this.registerId }
      const clearStoreId = Number(this.storeId || 0)
      if (clearStoreId > 0) clearParams.store_id = clearStoreId
      await clearMedicalRecordApi(clearParams)
      const keepPatient = this.effectivePatientId
      this.form = emptyForm()
      this.form.user_patient_id = keepPatient
      this.localDiagnosis = ''
      this.localAdvice = ''
      this.$emit('update:diagnosis', '')
      this.$emit('update:medicalAdvice', '')
      PrescriptionStorage.clearMedicalRecordDraft(this.registerId)
      uni.showToast({ title: '已清空', icon: 'none' })
    },
    /**
     * 打开引用历史抽屉：拉列表，默认选中非本次挂号的最近一条
     */
    async onOpenCiteDrawer() {
      const patientId = this.effectivePatientId
      if (!patientId) {
        uni.showToast({ title: '无就诊人', icon: 'none' })
        return
      }
      this.citeShow = true
      this.citeLoading = true
      this.citeList = []
      this.citeActiveId = 0
      try {
        const citeParams = {
          user_patient_id: patientId,
          limit: 50,
        }
        const citeStoreId = Number(this.storeId || 0)
        if (citeStoreId > 0) citeParams.store_id = citeStoreId
        const res = await listMedicalRecordByPatientApi(citeParams)
        const list = this.unwrapCiteList(res)
        const exclude = Number(this.registerId || 0)
        this.citeList = list.map((row) => {
          const dx = String((row && row.diagnosis) || '').trim()
          let title = '挂号 #' + ((row && row.register_id) || '-')
          if (dx) {
            title = dx.length > 28 ? dx.slice(0, 28) + '…' : dx
          }
          return Object.assign({}, row, {
            _title: title,
            _isCurrent: exclude > 0 && Number(row.register_id) === exclude,
          })
        })
        this.citeActiveId = this.pickDefaultCiteId(this.citeList)
      } catch (e) {
        this.citeList = []
        this.citeActiveId = 0
        const msg = (e && e.message) || (e && e.msg) || '加载失败'
        uni.showToast({ title: String(msg), icon: 'none' })
      } finally {
        this.citeLoading = false
      }
    },
    /** Laravel jok 在 result；兼容 data / 直接数组 */
    unwrapCiteList(res) {
      if (Array.isArray(res)) return res
      if (!res || typeof res !== 'object') return []
      if (Array.isArray(res.result)) return res.result
      if (Array.isArray(res.data)) return res.data
      if (Array.isArray(res.list)) return res.list
      if (res.result && Array.isArray(res.result.list)) return res.result.list
      return []
    },
    /**
     * 默认选中：优先「非当前挂号」最近一条，否则第一条
     */
    pickDefaultCiteId(rows) {
      if (!rows || !rows.length) return 0
      const exclude = Number(this.registerId || 0)
      if (exclude > 0) {
        for (let i = 0; i < rows.length; i++) {
          if (Number(rows[i].register_id) !== exclude) {
            return Number(rows[i].id)
          }
        }
      }
      return Number(rows[0].id)
    },
    onSelectCite(row) {
      if (!row) return
      this.citeActiveId = Number(row.id)
    },
    /**
     * 确认引用：把选中病历回填到表单（不直接调 latest）
     */
    onConfirmCite() {
      const data = this.citeActiveRecord
      if (!data) {
        uni.showToast({ title: '请选择病历', icon: 'none' })
        return
      }
      const patientId = this.effectivePatientId
      this.form = Object.assign(emptyForm(), data, {
        user_patient_id: patientId,
      })
      if (data.diagnosis) {
        this.localDiagnosis = data.diagnosis
        this.$emit('update:diagnosis', data.diagnosis)
      }
      if (data.doctor_order) {
        this.localAdvice = data.doctor_order
        this.$emit('update:medicalAdvice', data.doctor_order)
      }
      this.persistDraft()
      this.citeShow = false
      uni.showToast({ title: '已引用', icon: 'success' })
    },
    async openEntry(fieldCode) {
      // 诊断/医嘱不走病历词条
      if (fieldCode === 'diagnosis' || fieldCode === 'doctor_order') {
        return
      }
      this.entryField = fieldCode
      this.entryTcmType = ''
      this.entryKeyword = ''
      this.entryShow = true
      await this.loadEntryList()
    },
    /**
     * 打开中医三典选择（疾病/证候/治法）
     */
    async openTcmEntry(item) {
      if (!item || !item.tcmType) return
      this.entryField = item.code
      this.entryTcmType = item.tcmType
      this.entryKeyword = ''
      this.entryShow = true
      await this.loadEntryList()
    },
    /** 词条关键字输入防抖（u-input 的 @input 可能先于 v-model，以事件值为准） */
    onEntryKeywordInput(val) {
      if (typeof val === 'string') {
        this.entryKeyword = val
      }
      if (this.entrySearchTimer) clearTimeout(this.entrySearchTimer)
      this.entrySearchTimer = setTimeout(() => {
        this.loadEntryList()
      }, 500)
    },
    /**
     * 解析病历词条接口列表（Laravel jok 在 result，兼容 data）
     */
    unwrapEntryList(res) {
      if (Array.isArray(res)) return res
      if (!res || typeof res !== 'object') return []
      if (Array.isArray(res.result)) return res.result
      if (Array.isArray(res.data)) return res.data
      return []
    },
    /**
     * 拉取词条或中医字典，并做匹配度排序 + 高亮拆分
     */
    async loadEntryList() {
      try {
        const kw = (this.entryKeyword || '').trim()
        let list = []
        // 小程序侧统一前端打分，保证有匹配度排序；后端若已打分则 apply 内会优先用
        let mode = 'frontend'
        if (this.entryTcmType) {
          list = await this.fetchTcmDictList(this.entryTcmType, kw)
        } else {
          // uni 会把 undefined 序列化成字符串 "undefined"，无值时不要塞进 params
          const params = { field_code: this.entryField }
          if (kw) params.keyword = kw
          const sid = Number(this.storeId || 0)
          if (sid > 0) params.store_id = sid
          const res = await searchMedicalRecordEntryApi(params)
          list = this.unwrapEntryList(res)
          if (list[0] && list[0].rank_mode) {
            mode = String(list[0].rank_mode)
          }
          list = list.map((row) =>
              Object.assign({}, row, {
                pinyin_initials: formatPyDisplayOf(row),
              }),
          )
        }
        const ranked = applyDictRankAndHighlight(
            list,
            kw,
            (row) => String((row.title || '') + ' ' + (row.content || '')),
            mode,
            (row) => String(row.pinyin_initials || row.pinyin || ''),
        )
        this.entryList = ranked.map((row) =>
            Object.assign({}, row, {
              _titleParts: splitHighlight(row.title || '', kw) || [],
              _contentParts: splitHighlight(row.content || '', kw) || [],
              _pyParts: splitHighlight(row.pinyin_initials || '', kw) || [],
            }),
        )
      } catch (e) {
        this.entryList = []
      }
    },
    /**
     * 从本地/接口中医术语表过滤出候选列表
     */
    async fetchTcmDictList(tcmType, kw) {
      const all = await getTraditionalChineseMedicineJson()
      const rows = (all && all[tcmType]) || []
      const k = (kw || '').toLowerCase()
      const result = []
      for (let i = 0; i < rows.length; i++) {
        const item = rows[i] || {}
        const name = String(item.name || '').trim()
        if (!name) continue
        const py = formatPyDisplayOf(item)
        const pyRaw = [
          item.pinyin_display,
          item.pinyin_initials,
          item.initials_of_pinyin,
          item.pinyin_full,
        ]
            .map((v) => String(v || '').toLowerCase())
            .join(' ')
        const alias = String(item.alias || '')
        if (
            kw &&
            name.indexOf(kw) < 0 &&
            name.toLowerCase().indexOf(k) < 0 &&
            pyRaw.indexOf(k) < 0 &&
            alias.indexOf(kw) < 0
        ) {
          continue
        }
        result.push({
          id: item.id || name,
          title: name,
          content: name,
          remark: '中医字典',
          pinyin_initials: py,
        })
      }
      return kw ? result : result.slice(0, 80)
    },
    pickEntry(row) {
      const text = row.content || row.title || ''
      const field = this.entryField
      if (field === 'tongue' || field === 'pulse') {
        this.form[field] = text
      } else if (
          field === 'tcm_disease' ||
          field === 'tcm_syndrome' ||
          field === 'tcm_method'
      ) {
        this.form[field] = this.appendCommaText(this.form[field] || '', text)
      } else {
        this.form[field] = this.appendText(this.form[field] || '', text)
      }
      this.entryShow = false
      this.entryTcmType = ''
      this.schedulePersistDraft()
    },
    appendText(base, add) {
      if (!add) return base || ''
      if (!base) return add
      return base + (base.endsWith('\n') ? '' : '\n') + add
    },
    /** 中文逗号拼接，去重 */
    appendCommaText(base, add) {
      if (!add) return base || ''
      const parts = String(base || '')
          .split(/[，,]/)
          .map((s) => s.trim())
          .filter(Boolean)
      if (parts.indexOf(add) >= 0) return parts.join('，')
      parts.push(add)
      return parts.join('，')
    },
  },
}
</script>
<style scoped>
/* ─── 面板容器 ─── */
.mr-panel {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-sizing: border-box;
  background: #f4f6f8;
}
.mr-scroll {
  flex: 1;
  height: 0;
  min-height: 0;
}
.mr-scroll-inner {
  padding: 24rpx 28rpx 220rpx;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}

/* ─── 字段卡片 ─── */
.mr-card {
  background: #fff;
  border-radius: 24rpx;
  padding: 28rpx 28rpx 20rpx;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.mr-card--primary {
  background: linear-gradient(135deg, #f0faf8 0%, #fff 60%);
  border: 1rpx solid #d6f0eb;
}
.mr-card__header {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12rpx;
  margin-bottom: 18rpx;
}
.mr-card__header-dot {
  width: 8rpx;
  height: 32rpx;
  border-radius: 4rpx;
  background: #6ACDBB;
  flex-shrink: 0;
}
.mr-card__header-dot--secondary {
  background: #9BB8C4;
}
.mr-card__header-dot--primary {
  background: #6ACDBB;
}
.mr-card__title {
  font-size: 30rpx;
  font-weight: 700;
  color: #1a2530;
  flex: 1;
}
.mr-card__sync-badge {
  font-size: 20rpx;
  color: #6ACDBB;
  background: rgba(106, 205, 187, 0.12);
  padding: 4rpx 16rpx;
  border-radius: 20rpx;
  border: 1rpx solid rgba(106, 205, 187, 0.35);
  flex-shrink: 0;
}

/* ─── 词条入口按钮 ─── */
.mr-entry-btn {
  display: flex;
  flex-direction: row;
  align-items: center;
  background: #f4f6f8;
  border-radius: 14rpx;
  padding: 18rpx 20rpx;
  margin-bottom: 14rpx;
  border: 1rpx dashed #d8dde3;
  gap: 10rpx;
}
.mr-entry-btn__icon {
  font-size: 28rpx;
  color: #6ACDBB;
  font-weight: 700;
  flex-shrink: 0;
  line-height: 1;
}
.mr-entry-btn__text {
  font-size: 26rpx;
  color: #7a8a96;
  flex: 1;
}
.mr-entry-btn__arrow {
  font-size: 32rpx;
  color: #c0c8d0;
  flex-shrink: 0;
  line-height: 1;
}

/* ─── 中医病案：舌脉行 ─── */
.mr-tcm-tongue-row {
  display: flex;
  flex-direction: row;
  gap: 16rpx;
  margin-bottom: 0;
}
.mr-entry-btn--half {
  flex: 1;
  margin-bottom: 14rpx;
}
.mr-tcm-input-row {
  display: flex;
  flex-direction: row;
  gap: 16rpx;
  margin-bottom: 14rpx;
}
.mr-tcm-sub-row {
  display: flex;
  flex-direction: row;
  gap: 16rpx;
  margin-bottom: 8rpx;
}
.mr-tcm-sub-col {
  flex: 1;
  min-width: 0;
}
.mr-sub-label {
  display: block;
  font-size: 24rpx;
  color: #8a9399;
  margin-bottom: 8rpx;
  padding-left: 4rpx;
}

/* ─── 体征网格 ─── */
.vitals-grid {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 16rpx;
  margin-bottom: 16rpx;
}
.vital-cell {
  flex: 1 1 calc(33.33% - 12rpx);
  min-width: 160rpx;
  background: #f4f6f8;
  border-radius: 16rpx;
  padding: 20rpx 18rpx 16rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6rpx;
}
.vital-cell--bp {
  flex: 1 1 100%;
  flex-direction: column;
  align-items: center;
}
.vital-cell__label {
  font-size: 22rpx;
  color: #8a9399;
  text-align: center;
}
.vital-cell__unit {
  font-size: 20rpx;
  color: #b0b8c2;
  text-align: center;
}
.vital-cell__input {
  width: 100%;
  height: 56rpx;
  font-size: 34rpx;
  font-weight: 600;
  color: #1a2530;
  text-align: center;
  background: transparent;
  border: none;
  border-bottom: 2rpx solid #d0d8e0;
  box-sizing: border-box;
  padding: 0 4rpx;
}
.vital-cell__bp-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 16rpx;
  width: 100%;
  justify-content: center;
}
.vital-cell__input--bp {
  width: 160rpx;
  flex-shrink: 0;
}
.vital-cell__bp-sep {
  font-size: 36rpx;
  color: #b0b8c2;
  font-weight: 300;
}

/* ─── 底部操作栏 ─── */
.mr-bottom {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 20rpx 28rpx;
  background: rgba(255, 255, 255, 0.96);
  border-top: 1rpx solid #edf0f2;
  z-index: 99;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.06);
}
.mr-bottom-left {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
}
.mr-btn-text {
  font-size: 26rpx;
  color: #6ACDBB;
  padding: 12rpx 20rpx;
  flex-shrink: 0;
  border-radius: 40rpx;
}
.mr-btn-text--danger {
  color: #f55353;
}
.mr-ai-btn {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8rpx;
  padding: 14rpx 28rpx;
  margin-right: 16rpx;
  border-radius: 40rpx;
  background: rgba(106, 205, 187, 0.1);
  border: 1rpx solid rgba(106, 205, 187, 0.4);
}
.mr-ai-btn__icon {
  font-size: 22rpx;
  color: #6ACDBB;
  line-height: 1;
}
.mr-ai-btn__text {
  font-size: 26rpx;
  color: #6ACDBB;
  font-weight: 600;
}

/* ─── 通用抽屉结构 ─── */
.drawer-handle {
  width: 80rpx;
  height: 8rpx;
  border-radius: 4rpx;
  background: #e0e4e8;
  margin: 0 auto 28rpx;
}
.drawer-header {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24rpx;
}
.drawer-header__title {
  font-size: 34rpx;
  font-weight: 700;
  color: #1a2530;
}
.drawer-header__count {
  font-size: 24rpx;
  color: #8a9399;
  background: #f4f6f8;
  padding: 6rpx 18rpx;
  border-radius: 20rpx;
}
.drawer-empty {
  padding: 80rpx 0;
  text-align: center;
  font-size: 28rpx;
  color: #b0b8c2;
}

/* ─── 引用历史抽屉 ─── */
.cite-drawer {
  height: 100%;
  background: #fff;
  padding: 28rpx 28rpx 0;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
}
.cite-scroll {
  flex: 1;
  height: 0;
  min-height: 200rpx;
}
.cite-item {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 20rpx;
  padding: 22rpx 20rpx;
  margin-bottom: 12rpx;
  border-radius: 18rpx;
  background: #f7f8fa;
  border: 2rpx solid transparent;
  transition: all 0.2s;
}
.cite-item--active {
  border-color: #6ACDBB;
  background: rgba(106, 205, 187, 0.08);
}
.cite-item__check {
  width: 44rpx;
  height: 44rpx;
  border-radius: 50%;
  border: 2rpx solid #d0d8e0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-top: 4rpx;
}
.cite-item__check--on {
  background: #6ACDBB;
  border-color: #6ACDBB;
}
.cite-item__check-icon {
  font-size: 24rpx;
  color: #fff;
  line-height: 1;
}
.cite-item__body {
  flex: 1;
  min-width: 0;
}
.cite-item__title {
  font-size: 28rpx;
  font-weight: 700;
  color: #1a2530;
  word-break: break-all;
  margin-bottom: 10rpx;
}
.cite-item__meta {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 10rpx;
  align-items: center;
}
.cite-tag {
  font-size: 20rpx;
  color: #5a6672;
  background: #edf0f2;
  padding: 4rpx 14rpx;
  border-radius: 10rpx;
}
.cite-tag--warn {
  color: #d46b08;
  background: #fff3e0;
}
.cite-time {
  font-size: 20rpx;
  color: #b0b8c2;
}
.cite-item__sub {
  margin-top: 8rpx;
  font-size: 24rpx;
  color: #7a8a96;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cite-preview {
  margin-top: 8rpx;
  padding: 18rpx 20rpx;
  border-top: 1rpx solid #edf0f2;
  border-radius: 16rpx;
  background: #f7f8fa;
}
.cite-preview__row {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 12rpx;
  margin-bottom: 10rpx;
}
.cite-preview__label {
  font-size: 22rpx;
  color: #8a9399;
  flex-shrink: 0;
  padding-top: 4rpx;
  min-width: 56rpx;
}
.cite-preview__val {
  font-size: 26rpx;
  color: #1a2530;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cite-preview__tip {
  display: block;
  margin-top: 8rpx;
  font-size: 22rpx;
  color: #d46b08;
}
.cite-footer {
  padding: 20rpx 0 28rpx;
}

/* ─── 词条选择抽屉（紧凑列表 + 可滑） ─── */
.entry-drawer {
  height: 100%;
  min-height: 0;
  background: #fff;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  overflow: hidden;
}
.entry-drawer__hd {
  flex-shrink: 0;
  padding: 20rpx 28rpx 12rpx;
}
.entry-drawer__hd .drawer-handle {
  margin-bottom: 16rpx;
}
.entry-drawer__hd .drawer-header {
  margin-bottom: 16rpx;
}
.entry-scroll {
  flex: 1;
  height: 0;
  min-height: 0;
  overflow: hidden;
}
.entry-scroll-inner {
  padding: 0 28rpx;
  padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
  box-sizing: border-box;
}
.entry-row {
  padding: 16rpx 0;
  border-bottom: 1rpx solid #f0f2f4;
}
.entry-row-top {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12rpx;
}
.entry-row-name {
  flex: 1;
  min-width: 0;
  font-size: 28rpx;
  font-weight: 700;
  color: #1a2530;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.entry-score {
  flex-shrink: 0;
  font-size: 20rpx;
  font-weight: 700;
  color: #ff7043;
  background: rgba(255, 112, 67, 0.1);
  padding: 2rpx 12rpx;
  border-radius: 10rpx;
}
.entry-row-content {
  margin-top: 6rpx;
  font-size: 26rpx;
  color: #4a5560;
  line-height: 1.45;
  /* 约 3 行高度；用 max-height 兼容高亮多 text 节点 */
  max-height: 114rpx;
  overflow: hidden;
  word-break: break-all;
}
.entry-row-meta {
  margin-top: 8rpx;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 8rpx;
}
.entry-remark-tag,
.entry-py-tag {
  font-size: 20rpx;
  color: #8a9399;
  background: #f0f2f4;
  padding: 2rpx 12rpx;
  border-radius: 8rpx;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hit-text {
  color: #e64e1f;
  background: rgba(255, 210, 90, 0.5);
  border-radius: 4rpx;
}

/* ─── AI写病历入口（保留原 ai-modal 样式供 AiMedicalRecordDrawer 使用） ─── */
.ai-modal {
  padding: 32rpx;
  background: #fff;
  box-sizing: border-box;
}
.ai-modal__title {
  font-size: 34rpx;
  font-weight: bold;
  margin-bottom: 24rpx;
  text-align: center;
}
.ai-modal__row {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 16rpx;
}
.ai-modal__label {
  font-size: 26rpx;
  color: #666;
  flex-shrink: 0;
}
.ai-modal__val {
  font-size: 28rpx;
  color: #2a2e35;
  flex: 1;
}
.m-t-16 {
  margin-top: 16rpx;
}
.ai-modal__textarea {
  width: 100%;
  min-height: 160rpx;
  margin-top: 12rpx;
  padding: 16rpx;
  font-size: 28rpx;
  background: #f7f8fa;
  border-radius: 12rpx;
  box-sizing: border-box;
}
.ai-modal__tip {
  margin-top: 16rpx;
  font-size: 22rpx;
  color: #999;
  line-height: 1.5;
}
.ai-modal__loading,
.ai-modal__empty {
  padding: 48rpx 0;
  text-align: center;
  color: #999;
  font-size: 28rpx;
}
.ai-modal__preview {
  max-height: 560rpx;
  margin-bottom: 8rpx;
}
.ai-preview-chief {
  font-size: 26rpx;
  color: #666;
  background: #f7f8fa;
  padding: 16rpx;
  border-radius: 8rpx;
  margin-bottom: 16rpx;
}
.ai-preview-item {
  border: 1rpx solid #eee;
  border-radius: 12rpx;
  padding: 20rpx;
  margin-bottom: 16rpx;
}
.ai-preview-item__label {
  display: block;
  font-size: 22rpx;
  color: #999;
  margin-bottom: 8rpx;
}
.ai-preview-item__val {
  display: block;
  font-size: 28rpx;
  color: #2a2e35;
  white-space: pre-wrap;
  word-break: break-all;
}
.ai-modal__actions {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 16rpx;
  margin-top: 24rpx;
}
.ai-btn {
  padding: 16rpx 28rpx;
  border-radius: 40rpx;
  font-size: 26rpx;
}
.ai-btn--ghost {
  color: #666;
  background: #f2f3f5;
}
.ai-btn--primary {
  color: #fff;
  background: #6acdbb;
}
.ai-btn--disabled {
  opacity: 0.45;
}
</style>
