yxh
yxh
7 天以前 09dc74e264b6262cbe41c9c8476e24705871d4a6
src/views/ecg/doctor/components/RoutinePanel.vue
@@ -1,43 +1,84 @@
<!-- 常规检查 医生界面-->
<template>
  <el-form class="patient-compact-form" ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
    <!--
      【本需求】紧急加做操作提示(编辑区上方,常驻)
      紧急病人不排队:在下面三个输入框任一个里输入后按回车,查到预约记录即可直接做检查。
    -->
    <el-alert type="warning" :closable="false" class="emergency-tip">
      <template #title>
        <span class="emergency-tip__text">
          有紧急病人时,请输入<span class="emergency-tip__key">申请单号</span>、或<span class="emergency-tip__key">就诊号</span>、或<span class="emergency-tip__key">患者编号</span>后按<span class="emergency-tip__enter">回车键</span>,查到病人预约记录即可做检查!!!
        </span>
      </template>
    </el-alert>
    <!-- ===== 编辑区(需要录入的字段)===== -->
    <el-row :gutter="20">
      <el-col :span="6">
        <el-form-item label="申请单号" prop="applyNo">
          <el-input v-model="formData.applyNo" placeholder="请输入申请单号" />
        </el-form-item>
      </el-col>
       <el-col :span="6">
        <el-form-item label="检查项目" prop="">
          {{ formData?.checkType && getCheckTypeName(formData?.checkType) }}
        </el-form-item>
      </el-col>
        <el-col :span="6">
        <el-form-item label="患者编号" prop="patId">
          <el-input v-model="formData.patId" placeholder="请输入患者编号" @input="getRentInfoByPatId" />
          <Barcode v-if="displayBarCode" :value="displayBarCode" :width="100" />
          <el-button @click="copyBarcode()">复制</el-button>
        </el-form-item>
      </el-col>
      <el-col :span="6">
        <el-form-item label="患者姓名" prop="patName">
          <el-input v-model="formData.patName" placeholder="请输入患者姓名" />
        </el-form-item>
      </el-col>
    </el-row>
      <el-row :gutter="4">
        <el-col :xs="24" :sm="12" :md="12" :lg="6">
          <el-form-item label="申请单号" prop="applyNo">
            <!-- 【本需求:紧急加做】回车即按申请单号查近一个月的预约 -->
            <el-input
              v-model="formData.applyNo"
              placeholder="请输入申请单号"
              @keyup.enter="searchEmergencyCandidates('applyNo')"
            />
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="12" :md="12" :lg="6">
          <el-form-item label="检查项目" prop="">
            {{ formData?.checkType && getCheckTypeName(formData?.checkType) }}
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="12" :md="12" :lg="6">
          <el-form-item label="就诊号" prop="episodeId">
            <!-- 【本需求:紧急加做】回车即按就诊号查近一个月的预约 -->
            <el-input
              v-model="formData.episodeId"
              placeholder="请输入就诊流水号"
              @keyup.enter="searchEmergencyCandidates('episodeId')"
            />
            <!--
              【本需求】条码从「患者编号」挪到这里(就诊号下方):
                · 内容 = 就诊号;默认是否显示由「检查类型 → 是否显示条码」配置决定;
                · 医生可用切换按钮手动显隐(显示中→「隐藏」;隐藏中→「条码」);
                · 「复制」只在条码显示时出现。
            -->
            <div v-if="showBarcodeToggle || showBarCode" class="barcode-row">
              <Barcode v-if="showBarCode" :value="barcodeContent" :width="100" />
              <el-button v-if="showBarcodeToggle" size="small" @click="toggleBarcode()">
                {{ barcodeToggleLabel }}
              </el-button>
              <el-button v-if="showCopyButton" size="small" :disabled="!barcodeContent" @click="copyBarcode()">
                复制
              </el-button>
            </div>
          </el-form-item>
        </el-col>
        <!-- 【本需求】患者姓名这一列已去掉:下方 PatientInfoBlock 已有姓名展示 -->
        <el-col :xs="24" :sm="12" :md="12" :lg="6">
          <el-form-item label="患者编号" prop="patId">
            <!-- 【本需求:紧急加做】回车即按患者编号查近一个月的预约 -->
            <el-input
              v-model="formData.patId"
              placeholder="请输入患者编号"
              @input="getRentInfoByPatId"
              @keyup.enter="searchEmergencyCandidates('patId')"
            />
          </el-form-item>
        </el-col>
      </el-row>
    <!-- ===== 患者信息(需求1:18 项统一展示,**一行四列**)=====
         原先本面板把 18 项手写在多行 el-col(span=6/18 混排),
         现统一改用 PatientInfoBlock 组件,与预约签到/设备领用/装机/拆机各页**口径一致**。 -->
    <PatientInfoBlock :data="formData" check-type-field="checkType" :span="6" />
    <el-row>     
      <el-col :span="6">
      <el-col :xs="24" :sm="12" :md="12" :lg="6">
        <el-form-item label="检查时间" prop="rentTime">
          <el-date-picker v-model="formData.rentTime" type="date" value-format="x" placeholder="选择时间" />
        </el-form-item>
      </el-col> 
      <el-col :span="18">
      <el-col :xs="24" :sm="24" :md="12" :lg="18">
        <el-form-item label="备注" prop="remark">
          <el-input v-model="formData.remark" placeholder="请输入备注" />
        </el-form-item>
@@ -50,8 +91,8 @@
  <el-button size="small" @click="resetForm()">重 置</el-button>
  <el-button size="small" @click="yddownload()" :loading="yddownloadLoading" :disabled="yddownloadLoading">平板运动心电图知情同意书</el-button>
  <el-button size="small" @click="sgdownload()" :loading="sgdownloadLoading" :disabled="sgdownloadLoading">食管心脏电生理诊疗知情同意书</el-button>
  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeConfirm" :disabled="formLoading">确费</el-button>
  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeCancel" :disabled="formLoading">取消确费</el-button>
  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeConfirm" :disabled="formLoading || formData.id == null">确费</el-button>
  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeCancel" :disabled="formLoading || formData.id == null">取消确费</el-button>
  </div>
  <!-- 医生装机列表 -->
@@ -145,13 +186,84 @@
      @pagination="getList"
    />
  </div>
  <!--
    【本需求:紧急患者不排队直接检查】预约选择框
    触发:在「申请单号 / 就诊号 / 患者编号」任一输入框内按回车。
    多条预约时弹此框,按预约时间倒序(最近的在前)。
  -->
  <Dialog v-model="emergencyVisible" title="选择预约记录(紧急加做)" width="880px" append-to-body>
    <el-alert type="warning" :closable="false" class="mb-10px">
      <template #title>
        <span class="text-13px">
          找到 {{ emergencyList.length }} 条预约记录:**点选一行**(整行高亮 + 左侧蓝条 + 「已选」标签)后点「选择并检查」,
          也可直接**双击**该行。选中后可直接检查,完成后同样进入「已完成列表」(不排队、不占号)。
        </span>
      </template>
    </el-alert>
    <el-table
      ref="emergencyTableRef"
      class="emergency-table"
      :data="emergencyList"
      v-loading="emergencyLoading"
      highlight-current-row
      border
      max-height="360px"
      :row-class-name="emergencyRowClass"
      @row-click="(row) => (emergencySelected = row)"
      @current-change="(row) => (emergencySelected = row)"
      @row-dblclick="(row) => confirmEmergency(row)"
    >
      <!-- 【本需求】选中标识列:选中行显示「✓ 已选」,避免只靠背景色分辨不清 -->
      <el-table-column label="选择" width="80" align="center" fixed="left">
        <template #default="scope">
          <el-tag v-if="isEmergencySelected(scope.row)" type="primary" effect="dark" size="small">
            ✓ 已选
          </el-tag>
          <span v-else class="text-gray-400">—</span>
        </template>
      </el-table-column>
      <el-table-column label="预约日期" align="center" prop="bookDate" width="120">
        <template #default="scope">{{ formatDate(scope.row.bookDate, 'YYYY-MM-DD') }}</template>
      </el-table-column>
      <el-table-column label="时段" align="center" width="120">
        <template #default="scope">{{ formatTimeslot(scope.row.bookTimeslot) }}</template>
      </el-table-column>
      <el-table-column label="检查项目" align="center" min-width="130">
        <template #default="scope">{{ getCheckTypeName(scope.row.bookCheckType) }}</template>
      </el-table-column>
      <el-table-column label="患者名称" align="center" prop="patName" min-width="100" />
      <el-table-column label="患者编号" align="center" prop="patId" min-width="110" />
      <el-table-column label="申请单号" align="center" prop="applyNo" min-width="130" />
      <el-table-column label="状态" align="center" width="90">
        <template #default="scope">
          <dict-tag :type="DICT_TYPE.ECG_STATUS" :value="scope.row.status" />
        </template>
      </el-table-column>
    </el-table>
    <template #footer>
      <!-- 底部回显已选哪一条,避免选错 -->
      <span v-if="emergencySelected" class="emergency-selected-hint">
        已选:{{ formatDate(emergencySelected.bookDate, 'YYYY-MM-DD') }}
        {{ formatTimeslot(emergencySelected.bookTimeslot) }}
        {{ getCheckTypeName(emergencySelected.bookCheckType) }}
        <span class="text-gray-500">({{ emergencySelected.patName }})</span>
      </span>
      <el-button @click="emergencyVisible = false">取 消</el-button>
      <el-button type="primary" :disabled="!emergencySelected" @click="confirmEmergency()">
        选择并检查
      </el-button>
    </template>
  </Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { DevRentApi, DevRentVO } from '@/api/ecg/devrent'
import { dateFormatter } from '@/utils/formatTime'
import { dateFormatter, formatDate } from '@/utils/formatTime'
import { formatTimeslot } from '@/utils/formatter'
import { AppointmentApi, AppointmentVO } from '@/api/ecg/appointment'
import { JobRecordApi, JobRecordVO } from '@/api/ecg/jobrecord'
import { isStringEmpty } from '@/utils/stringUtil'
import { calculateAge, curDayEnd, curDayStart, formatTimestamp } from '@/utils/dateUtil'
@@ -239,7 +351,6 @@
    formData.value.doctorAdviceNo = queueVO?.doctorAdviceNo
  formData.value.patIdentityId = queueVO?.patIdentityId
  getFreeRentInfo(formData.value)
  copyBarcode()
}
defineExpose({ setPatient, getList: () => getList() }) // 提供 setPatient 方法,用于设置患者
@@ -304,7 +415,106 @@
})
const formRef = ref() // 表单 Ref
const displayBarCode = ref<string>()
// =====================================================================================
// 【本需求:紧急患者不排队直接检查】
//   在「申请单号 / 就诊号 / 患者编号」任一输入框回车 → 查近一个月、本窗口检查项目的预约记录
//   → 1 条直接读入;多条弹选择框(按预约时间倒序)→ 读入后可直接「检查完成」
//   → 后端在"今天没有待检查单"时按预约单补建,从而像排队患者一样进入「已完成列表」
// =====================================================================================
const emergencyMode = ref(false) // 当前表单是否来自"紧急加做"
const emergencyVisible = ref(false) // 选择框
const emergencyLoading = ref(false)
const emergencyList = ref<AppointmentVO[]>([])
const emergencySelected = ref<AppointmentVO | undefined>()
/** 选择表格引用(保留:后续如需 scrollToRow 等能力可用) */
const emergencyTableRef = ref<any>()
/** 选中判断(模板里用,避免直接比较对象引用) */
const isEmergencySelected = (row: AppointmentVO) =>
  null != emergencySelected.value && emergencySelected.value.id === row?.id
/** 选中行加 is-selected 类,配合下方样式做「整行高亮 + 左侧蓝条 + 加粗」 */
const emergencyRowClass = ({ row }: { row: AppointmentVO }) =>
  isEmergencySelected(row) ? 'is-selected' : ''
/** 本窗口(诊室)开展的检查项目,用于过滤候选预约;为空表示不限制 */
const currentWindowCheckTypes = (): number[] | undefined => {
  const fromProp = props.room?.checkTypes
  const types =
    Array.isArray(fromProp) && fromProp.length > 0 ? fromProp : (roomStore.room?.checkTypes as number[] | undefined)
  return Array.isArray(types) && types.length > 0 ? [...types] : undefined
}
/** 回车:按输入框里的值查预约候选 */
const searchEmergencyCandidates = async (field: 'applyNo' | 'episodeId' | 'patId') => {
  const code = String((formData.value as Record<string, any>)[field] ?? '').trim()
  if (!code) return
  emergencyLoading.value = true
  try {
    const list = (await AppointmentApi.getEmergencyCandidates(code, currentWindowCheckTypes())) as AppointmentVO[]
    const rows = Array.isArray(list) ? list : []
    if (rows.length === 0) {
      message.warning('近一个月内没有找到本窗口检查项目的预约记录')
      return
    }
    if (rows.length === 1) {
      applyAppointment(rows[0])
      message.success('已读入预约记录,可直接点「检查完成」')
      return
    }
    emergencyList.value = rows
    emergencySelected.value = undefined
    emergencyVisible.value = true
  } finally {
    emergencyLoading.value = false
  }
}
/** 选择框确认(也支持双击行直接确认) */
const confirmEmergency = (row?: AppointmentVO) => {
  const target = row ?? emergencySelected.value
  if (!target) return
  applyAppointment(target)
  emergencyVisible.value = false
}
/**
 * 把预约单读入表单。
 * 注意:这里是"紧急加做",**不排队**——不建 queue 行、不取号;
 * 「检查完成」时由后端按需补建「待检查」检查单(见 DevRentServiceImpl#prepareEmergencyDevRent)。
 */
const applyAppointment = (appt: AppointmentVO) => {
  resetForm()
  emergencyMode.value = true
  formData.value.applyNo = appt.applyNo
  formData.value.episodeId = appt.episodeId
  formData.value.patId = appt.patId
  formData.value.patName = appt.patName
  formData.value.checkType = appt.bookCheckType
  formData.value.patGender = appt.patGender
  formData.value.patBirthday = appt.patBirthday
  formData.value.patSrc = appt.patSrc
  formData.value.tolerance = appt.tolerance
  formData.value.doctor = appt.doctor
  formData.value.doctorTime = appt.doctorTime
  formData.value.registerDate = appt.registerDate
  formData.value.paid = appt.paid
  formData.value.doctorAdviceNo = appt.doctorAdviceNo
  formData.value.patMobile = appt.patMobile
  formData.value.patPhone = appt.patPhone
  formData.value.patIdentityId = appt.patIdentityId
  formData.value.outpatientNo = appt.outpatientNo
  formData.value.patWardDesc = appt.patWardDesc
  formData.value.patBedNo = appt.patBedNo
  formData.value.medicalCard = appt.medicalCard
  // 条码/打印小票依赖 patDetails.source
  formData.value.patDetails = {
    source: appt.patSrc,
    appointmentId: appt.id
  } as unknown as typeof formData.value.patDetails
  message.success('已读入预约记录,可直接点「检查完成」')
}
/** 提交表单 */
const submitForm = async () => {
@@ -315,12 +525,16 @@
  try {
    formData.value.roomId = props.room.roomId
    formData.value.bedNo = props.room.bedNo
    const data = formData.value as unknown as DevRentVO
    await DevRentApi.routineFinish(data)
    // 【本需求:紧急患者不排队直接检查】带上"紧急加做"标记:
    //   后端据此在「今天没有待检查单」时按预约单补建一行,从而能正常完成并写入「已完成列表」
    const data = formData.value as unknown as DevRentVO & { emergency?: boolean }
    data.emergency = emergencyMode.value
    // 后端 routine-finish 已返回本次完成的检查单 id(紧急加做时是服务端新建的那条)
    const rentId = (await DevRentApi.routineFinish(data)) as unknown as number | string | undefined
    // 自动确费
    // 自动确费:用返回的 rentId;无 id 时静默跳过(不再弹「请先检查」)
    if (needAutoFeeConfirm(formData.value.checkType)) {
      feeConfirm()
      feeConfirm(rentId)
    }
    message.success(t('操作成功'))
@@ -360,6 +574,9 @@
    roomId: props.room.roomId,
    bedNo: props.room.bedNo
  }
  // 【本需求】换患者/重置时:条码显隐回到"跟随配置默认",紧急加做标记清空
  barcodeVisible.value = null
  emergencyMode.value = false
  formRef.value?.resetFields()
}
const yddownload = async () => {
@@ -439,7 +656,6 @@
  formData.value.patId = tempPatId
  getFreeRentInfo(formData.value)
  copyBarcode()
}
const getFreeRentInfo = async (devRentVO) => {
@@ -570,14 +786,21 @@
  message.success(t('操作成功'))
}
const feeConfirm = async () => {
  if (formData.value.id == null) {
    message.error(t('请先检查'))
/**
 * 确费。
 * @param rentId 本次检查完成返回的检查单 id;不传则用表单里的 id。
 * 【本次修复】原实现在 id 为空时弹「请先检查」—— 紧急加做患者没有 id,点「检查完成」会先弹这个错,
 * 再弹「操作成功」,让人误以为操作失败。现在改为静默跳过(按钮本身也会在无 id 时禁用)。
 */
const feeConfirm = async (rentId?: number | string | null) => {
  const id = rentId ?? formData.value.id
  if (id == null || id === '') {
    console.warn('[feeConfirm] 无检查单 id,跳过确费')
    return
  }
  try {
    const result = await DevRentApi.feeConfirm(formData.value.id)
    const result = await DevRentApi.feeConfirm(id as number)
    if (0 == result) {
      //message.success(t('确费操作成功'))
    }
@@ -587,8 +810,9 @@
}
const feeCancel = async () => {
  if (formData.value.id == null) {
    message.error(t('请先检查'))
  // 【本次修复】无检查单 id 时静默跳过(按钮已禁用),不再弹「请先检查」
  if (formData.value.id == null || formData.value.id === '') {
    console.warn('[feeCancel] 无检查单 id,跳过取消确费')
    return
  }
@@ -601,40 +825,57 @@
    // 框架 会给出 后台的 错误信息
  }
}
/**
 * 【本需求】患者条码:位置在「就诊号」下方,内容 = 就诊号(episodeId),可显隐
 *
 *  · 默认可见性 = 「检查类型 → 是否显示条码」配置里**包含该患者来源**
 *      - 已勾选该来源 → 默认显示
 *      - 未配置 / 配置里没有该来源 → 默认不显示(例如住院(3)通常不会勾选)
 *  · 医生可用按钮手动覆盖默认:显示中 → 「隐藏」;隐藏中 → 「条码」
 *  · 「复制」按钮只在条码显示时出现
 */
const barcodeVisible = ref<boolean | null>(null) // null = 未手动操作,跟随配置默认
const getDisplayBarcode = (): string => {
  if (formData.value.checkType == null) return ''
const patSourceValue = computed<number | null>(() => {
  const source = formData.value.patDetails?.source ?? formData.value.patSrc
  return source === null || source === undefined || source === '' ? null : Number(source)
})
  // 【本次修复】「患者条码显示」未配置(null/空)→ 不显示(按现场确认口径)
  const displayBarcode: number[] | undefined = checkTypeStore.getCheckTypeDispBarCode(formData.value.checkType!)
  if (displayBarcode == null || displayBarcode.length === 0) return ''
/** 配置口径:该检查类型的「显示条码」是否包含当前患者来源 */
const barcodeEnabled = computed<boolean>(() => {
  if (formData.value.checkType == null) return false
  const displayBarcode: number[] | undefined = checkTypeStore.getCheckTypeDispBarCode(formData.value.checkType)
  if (displayBarcode == null || displayBarcode.length === 0) return false
  const patSource = patSourceValue.value
  if (patSource == null) return false
  return displayBarcode.map(Number).includes(patSource)
})
  // 【本次修复】来源优先取 patDetails.source,缺失时回退到平铺的 patSrc。
  // 原来只读 patDetails.source,而 patDetails 原先只在"能查到待检查单"时才被赋值,
  // 大多数情况下是 undefined → 条码永远不显示。
  const patSource = formData.value.patDetails?.source ?? formData.value.patSrc
  if (patSource == null) return ''
  if (!displayBarcode.map(Number).includes(Number(patSource))) return ''
/** 条码 / 复制的内容:统一取「就诊号」 */
const barcodeContent = computed<string>(() => formData.value.episodeId ?? '')
  return getBarcode()
}
/** 实际是否显示:手动覆盖优先,否则跟配置默认 */
const barcodeVisibleEffective = computed<boolean>(() => barcodeVisible.value ?? barcodeEnabled.value)
const getBarcode = (): string => {
  if (formData.value.checkType == null) return ''
/** 条码:可见且内容非空才渲染 */
const showBarCode = computed<boolean>(() => barcodeVisibleEffective.value && barcodeContent.value !== '')
  const patSource = formData.value.patDetails?.source ?? formData.value.patSrc
  if (patSource == null) return ''
/** 「复制」按钮:只在条码显示时出现 */
const showCopyButton = computed<boolean>(() => showBarCode.value)
  // 门诊/急诊 → 申请单号;住院/体检 → 就诊流水号
  if (1 === Number(patSource) || 2 === Number(patSource)) return formData.value.applyNo ?? ''
  else if (3 === Number(patSource) || 4 === Number(patSource)) return formData.value.episodeId ?? ''
/** 切换按钮:只要有就诊号就给(不受配置限制,配置只管"默认是否显示") */
const showBarcodeToggle = computed<boolean>(() => barcodeContent.value !== '')
  return ''
/** 切换按钮文案:显示中 → 隐藏;隐藏中 → 条码 */
const barcodeToggleLabel = computed<string>(() => (showBarCode.value ? '隐藏' : '条码'))
const toggleBarcode = () => {
  barcodeVisible.value = !barcodeVisibleEffective.value
}
const copyBarcode = async () => {
  displayBarCode.value = getDisplayBarcode()
  await navigator.clipboard.writeText(getBarcode())
  if (!barcodeContent.value) return
  await navigator.clipboard.writeText(barcodeContent.value)
}
/** 初始化 **/
@@ -647,6 +888,73 @@
<style scoped lang="scss">
/* 【本次需求】「已完成列表」标题栏:左侧主色竖线 + 加粗小标题,紧凑高度不挤压表格 */
/* 【本需求】编辑区上方的「紧急加做」操作提示:一行显示、醒目但不占高度 */
.emergency-tip {
  padding: 4px 10px;
  margin-bottom: 6px;
  :deep(.el-alert__title) {
    padding: 0;
    font-size: 13px;
    line-height: 20px;
  }
  &__text {
    color: var(--el-color-warning-dark-2);
  }
  /* 关键字段/按键做强调,方便一眼看懂要输什么、按什么 */
  &__key {
    font-weight: 600;
    color: var(--el-color-danger);
  }
  &__enter {
    padding: 0 4px;
    margin: 0 2px;
    border: 1px solid var(--el-color-danger);
    border-radius: 3px;
    font-weight: 600;
    color: var(--el-color-danger);
    background-color: var(--el-color-danger-light-9);
  }
}
/* 【本需求】紧急加做:预约选择框的「选中行」要足够明显
   (原来只有默认的浅色 current-row 背景,现场反馈"只是变深一点,看不清") */
.emergency-table {
  :deep(.el-table__row) {
    cursor: pointer;
  }
  :deep(.el-table__row:hover > td) {
    background-color: var(--el-color-primary-light-9) !important;
  }
  /* 选中行:主色背景 + 加粗 + 左侧 4px 主色条 */
  :deep(.el-table__row.is-selected > td) {
    background-color: var(--el-color-primary-light-6) !important;
    color: var(--el-color-primary-dark-2);
    font-weight: 600;
  }
  :deep(.el-table__row.is-selected > td:first-child) {
    box-shadow: inset 4px 0 0 var(--el-color-primary);
  }
}
/* 选择框底部「已选」回显 */
.emergency-selected-hint {
  float: left;
  line-height: 32px;
  font-size: 13px;
  color: var(--el-color-primary);
  font-weight: 600;
}
/* 【本需求】就诊号下方的条码行:条码 + [隐藏|条码] + [复制] 同一行,紧凑不撑高 */
.barcode-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  flex-wrap: wrap;
}
.records-title {
  display: flex;
  align-items: center;