|
@@ -1,7 +1,13 @@
|
|
|
<template>
|
|
<template>
|
|
|
<!-- 搜索 -->
|
|
<!-- 搜索 -->
|
|
|
<ContentWrap>
|
|
<ContentWrap>
|
|
|
- <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="80px">
|
|
|
|
|
|
|
+ <el-form
|
|
|
|
|
+ class="-mb-15px"
|
|
|
|
|
+ :model="queryParams"
|
|
|
|
|
+ ref="queryFormRef"
|
|
|
|
|
+ :inline="true"
|
|
|
|
|
+ label-width="80px"
|
|
|
|
|
+ >
|
|
|
<TenantSelect v-model="queryParams.tenantIds" placeholder="请选择机构名称" prop="tenantIds" />
|
|
<TenantSelect v-model="queryParams.tenantIds" placeholder="请选择机构名称" prop="tenantIds" />
|
|
|
<el-form-item label="长者姓名" prop="elderName">
|
|
<el-form-item label="长者姓名" prop="elderName">
|
|
|
<el-input
|
|
<el-input
|
|
@@ -36,24 +42,21 @@
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
<el-form-item>
|
|
|
- <el-button @click="handleQuery">
|
|
|
|
|
- <Icon icon="ep:search" class="mr-5px" /> 查询
|
|
|
|
|
- </el-button>
|
|
|
|
|
- <el-button @click="resetQuery">
|
|
|
|
|
- <Icon icon="ep:refresh" class="mr-5px" /> 重置
|
|
|
|
|
- </el-button>
|
|
|
|
|
- <el-button type="primary" plain @click="openPrintDialog('all')">
|
|
|
|
|
- <Icon icon="ep:printer" class="mr-5px" /> 打印执行单
|
|
|
|
|
- </el-button>
|
|
|
|
|
|
|
+ <el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" /> 查询 </el-button>
|
|
|
|
|
+ <el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" /> 重置 </el-button>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-form>
|
|
</el-form>
|
|
|
</ContentWrap>
|
|
</ContentWrap>
|
|
|
|
|
|
|
|
<!-- 列表 -->
|
|
<!-- 列表 -->
|
|
|
<ContentWrap>
|
|
<ContentWrap>
|
|
|
|
|
+ <el-button type="primary" plain @click="openPrintDialog('all')" style="margin-bottom: 10px">
|
|
|
|
|
+ <Icon icon="ep:printer" class="mr-5px" /> 打印执行单
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+
|
|
|
<el-table v-loading="loading" :data="pagedList" border stripe>
|
|
<el-table v-loading="loading" :data="pagedList" border stripe>
|
|
|
<el-table-column label="长者" prop="elderName" width="110" fixed />
|
|
<el-table-column label="长者" prop="elderName" width="110" fixed />
|
|
|
- <el-table-column label="床位" prop="bedName" width="120" />
|
|
|
|
|
|
|
+ <el-table-column label="床位" prop="bedName" width="180" />
|
|
|
<el-table-column label="类型" width="90" align="center">
|
|
<el-table-column label="类型" width="90" align="center">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-tag :type="row.orderType === 1 ? 'primary' : 'warning'" size="small" effect="plain">
|
|
<el-tag :type="row.orderType === 1 ? 'primary' : 'warning'" size="small" effect="plain">
|
|
@@ -71,9 +74,13 @@
|
|
|
<el-table-column label="途径" width="90" align="center">
|
|
<el-table-column label="途径" width="90" align="center">
|
|
|
<template #default="{ row }">{{ routeCn(row.route) }}</template>
|
|
<template #default="{ row }">{{ routeCn(row.route) }}</template>
|
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
- <el-table-column label="计划执行时间" prop="planTime" width="160" />
|
|
|
|
|
|
|
+ <el-table-column label="计划执行时间" width="140">
|
|
|
|
|
+ <template #default="{ row }">{{ formatDateTimeShort(row.planTime) }}</template>
|
|
|
|
|
+ </el-table-column>
|
|
|
<el-table-column label="执行护士" prop="execNurseSign" width="100" />
|
|
<el-table-column label="执行护士" prop="execNurseSign" width="100" />
|
|
|
- <el-table-column label="实际执行时间" prop="execTime" width="160" />
|
|
|
|
|
|
|
+ <el-table-column label="实际执行时间" width="160">
|
|
|
|
|
+ <template #default="{ row }">{{ row.execTime ? formatDateTimeShort(row.execTime) : '' }}</template>
|
|
|
|
|
+ </el-table-column>
|
|
|
<el-table-column label="状态" width="90" align="center">
|
|
<el-table-column label="状态" width="90" align="center">
|
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
|
<el-tag :type="statusType(row.status)" size="small">{{ statusText(row.status) }}</el-tag>
|
|
<el-tag :type="statusType(row.status)" size="small">{{ statusText(row.status) }}</el-tag>
|
|
@@ -100,7 +107,11 @@
|
|
|
<el-button v-if="row.status !== 0" link type="primary" @click="openExecute(row, true)"
|
|
<el-button v-if="row.status !== 0" link type="primary" @click="openExecute(row, true)"
|
|
|
>查看</el-button
|
|
>查看</el-button
|
|
|
>
|
|
>
|
|
|
- <el-button link type="warning" @click="openPrintDialog('single', row)" v-hasPermi="['doctor-order-execute:print']"
|
|
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ link
|
|
|
|
|
+ type="warning"
|
|
|
|
|
+ @click="openPrintDialog('single', row)"
|
|
|
|
|
+ v-hasPermi="['doctor-order-execute:print']"
|
|
|
>打印</el-button
|
|
>打印</el-button
|
|
|
>
|
|
>
|
|
|
</template>
|
|
</template>
|
|
@@ -116,7 +127,7 @@
|
|
|
</ContentWrap>
|
|
</ContentWrap>
|
|
|
|
|
|
|
|
<!-- 执行弹窗 -->
|
|
<!-- 执行弹窗 -->
|
|
|
- <ExecuteDialog ref="execRef" @success="buildRows" />
|
|
|
|
|
|
|
+ <ExecuteDialog ref="execRef" @success="onExecuteSuccess" />
|
|
|
|
|
|
|
|
<!-- 跳过原因弹窗 -->
|
|
<!-- 跳过原因弹窗 -->
|
|
|
<el-dialog
|
|
<el-dialog
|
|
@@ -160,23 +171,36 @@
|
|
|
append-to-body
|
|
append-to-body
|
|
|
:close-on-click-modal="false"
|
|
:close-on-click-modal="false"
|
|
|
>
|
|
>
|
|
|
- <!-- 汇总(当日全量) -->
|
|
|
|
|
- <div v-if="printMode === 'all'" id="execPrintArea" class="exec-print" style="padding: 12px 16px; color: #000; background: #fff">
|
|
|
|
|
- <div style="text-align: center; font-size: 20px; font-weight: bold; margin: 6px 0 18px">
|
|
|
|
|
- 医嘱执行单
|
|
|
|
|
- </div>
|
|
|
|
|
- <div style="display: flex; justify-content: space-between; font-size: 14px; margin-bottom: 10px">
|
|
|
|
|
- <span>机构:{{ tenantName }}</span>
|
|
|
|
|
- <span>执行日期:{{ queryParams.execDate }}</span>
|
|
|
|
|
|
|
+ <!-- 汇总(当日全量):A4 横版 270mm,列宽按 mm,日期时间上下两行,去缩写 -->
|
|
|
|
|
+ <div v-if="printMode === 'all'" id="execPrintArea" class="exec-print" v-loading="loading">
|
|
|
|
|
+ <h2 class="doc-title">医嘱执行单</h2>
|
|
|
|
|
+ <div class="info-row">
|
|
|
|
|
+ <div class="info-cell"><span class="lbl">机构:</span>{{ tenantName || '-' }}</div>
|
|
|
|
|
+ <div class="info-cell"><span class="lbl">执行日期:</span>{{ queryParams.execDate }}</div>
|
|
|
|
|
+ <div class="info-cell"
|
|
|
|
|
+ ><span class="lbl">长者:</span>{{ queryParams.elderName || '全部' }}</div
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="info-cell"><span class="lbl">类型:</span>{{ orderTypeText }}</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <table
|
|
|
|
|
- border="1"
|
|
|
|
|
- cellspacing="0"
|
|
|
|
|
- cellpadding="6"
|
|
|
|
|
- style="width: 100%; border-collapse: collapse; font-size: 14px"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <table class="order-table">
|
|
|
|
|
+ <colgroup>
|
|
|
|
|
+ <col style="width: 6mm" />
|
|
|
|
|
+ <col style="width: 22mm" />
|
|
|
|
|
+ <col style="width: 22mm" />
|
|
|
|
|
+ <col style="width: 14mm" />
|
|
|
|
|
+ <col style="width: 75mm" />
|
|
|
|
|
+ <col style="width: 14mm" />
|
|
|
|
|
+ <col style="width: 14mm" />
|
|
|
|
|
+ <col style="width: 12mm" />
|
|
|
|
|
+ <col style="width: 22mm" />
|
|
|
|
|
+ <col style="width: 16mm" />
|
|
|
|
|
+ <col style="width: 22mm" />
|
|
|
|
|
+ <col style="width: 13mm" />
|
|
|
|
|
+ <col style="width: 18mm" />
|
|
|
|
|
+ </colgroup>
|
|
|
<thead>
|
|
<thead>
|
|
|
<tr>
|
|
<tr>
|
|
|
|
|
+ <th>序号</th>
|
|
|
<th>长者</th>
|
|
<th>长者</th>
|
|
|
<th>床位</th>
|
|
<th>床位</th>
|
|
|
<th>类型</th>
|
|
<th>类型</th>
|
|
@@ -188,66 +212,118 @@
|
|
|
<th>执行护士</th>
|
|
<th>执行护士</th>
|
|
|
<th>实际时间</th>
|
|
<th>实际时间</th>
|
|
|
<th>状态</th>
|
|
<th>状态</th>
|
|
|
|
|
+ <th>备注</th>
|
|
|
</tr>
|
|
</tr>
|
|
|
</thead>
|
|
</thead>
|
|
|
<tbody>
|
|
<tbody>
|
|
|
<tr v-for="(item, idx) in list" :key="idx">
|
|
<tr v-for="(item, idx) in list" :key="idx">
|
|
|
|
|
+ <td>{{ idx + 1 }}</td>
|
|
|
<td>{{ item.elderName }}</td>
|
|
<td>{{ item.elderName }}</td>
|
|
|
<td>{{ item.bedName }}</td>
|
|
<td>{{ item.bedName }}</td>
|
|
|
<td>{{ item.orderType === 1 ? '长期' : '临时' }}</td>
|
|
<td>{{ item.orderType === 1 ? '长期' : '临时' }}</td>
|
|
|
- <td>{{ item.orderContent }}</td>
|
|
|
|
|
|
|
+ <td
|
|
|
|
|
+ ><span class="cell-value pre">{{ item.orderContent }}</span></td
|
|
|
|
|
+ >
|
|
|
<td>{{ freqCn(item.frequency) }}</td>
|
|
<td>{{ freqCn(item.frequency) }}</td>
|
|
|
<td>{{ timeCn(item.medTime) }}</td>
|
|
<td>{{ timeCn(item.medTime) }}</td>
|
|
|
<td>{{ routeCn(item.route) }}</td>
|
|
<td>{{ routeCn(item.route) }}</td>
|
|
|
- <td>{{ item.planTime }}</td>
|
|
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="datetime">
|
|
|
|
|
+ <div class="d-line">{{ formatDateTimeSplit(item.planTime).date }}</div>
|
|
|
|
|
+ <div class="t-line">{{ formatDateTimeSplit(item.planTime).time }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
<td>{{ item.execNurseSign }}</td>
|
|
<td>{{ item.execNurseSign }}</td>
|
|
|
- <td>{{ item.execTime }}</td>
|
|
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="datetime">
|
|
|
|
|
+ <div class="d-line">{{ formatDateTimeSplit(item.execTime).date }}</div>
|
|
|
|
|
+ <div class="t-line">{{ formatDateTimeSplit(item.execTime).time }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
<td>{{ statusText(item.status) }}</td>
|
|
<td>{{ statusText(item.status) }}</td>
|
|
|
|
|
+ <td
|
|
|
|
|
+ ><span class="cell-value pre">{{ item.remark || '' }}</span></td
|
|
|
|
|
+ >
|
|
|
</tr>
|
|
</tr>
|
|
|
</tbody>
|
|
</tbody>
|
|
|
</table>
|
|
</table>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <!-- 单条 -->
|
|
|
|
|
- <div v-else id="singlePrintArea" class="exec-print" style="padding: 12px 16px; color: #000; background: #fff">
|
|
|
|
|
|
|
+ <!-- 单条(A4 横版 270mm,左字段 / 右字段 两列网格,更宽更舒展) -->
|
|
|
|
|
+ <div v-else id="singlePrintArea" class="exec-print" v-loading="loading">
|
|
|
<div v-if="singlePrintRow">
|
|
<div v-if="singlePrintRow">
|
|
|
- <div style="text-align: center; font-size: 20px; font-weight: bold; margin: 6px 0 18px">
|
|
|
|
|
- 医嘱执行单(单条)
|
|
|
|
|
- </div>
|
|
|
|
|
- <div
|
|
|
|
|
- style="
|
|
|
|
|
- display: grid;
|
|
|
|
|
- grid-template-columns: repeat(2, 1fr);
|
|
|
|
|
- gap: 4px 16px;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- margin-bottom: 14px;
|
|
|
|
|
- line-height: 1.8;
|
|
|
|
|
- "
|
|
|
|
|
- >
|
|
|
|
|
- <div><strong>长者:</strong>{{ singlePrintRow.elderName }}</div>
|
|
|
|
|
- <div><strong>床位:</strong>{{ singlePrintRow.bedName }}</div>
|
|
|
|
|
- <div><strong>类型:</strong>{{ singlePrintRow.orderType === 1 ? '长期医嘱' : '临时医嘱' }}</div>
|
|
|
|
|
- <div><strong>状态:</strong>{{ statusText(singlePrintRow.status) }}</div>
|
|
|
|
|
- <div><strong>频次:</strong>{{ freqCn(singlePrintRow.frequency) }}</div>
|
|
|
|
|
- <div><strong>给药时间:</strong>{{ timeCn(singlePrintRow.medTime) }}</div>
|
|
|
|
|
- <div><strong>途径:</strong>{{ routeCn(singlePrintRow.route) }}</div>
|
|
|
|
|
- <div><strong>计划执行时间:</strong>{{ singlePrintRow.planTime }}</div>
|
|
|
|
|
- <div><strong>实际执行时间:</strong>{{ singlePrintRow.execTime || '-' }}</div>
|
|
|
|
|
- <div><strong>执行护士:</strong>{{ singlePrintRow.execNurseSign || '-' }}</div>
|
|
|
|
|
- <div style="grid-column: 1 / -1"><strong>医嘱内容:</strong>{{ singlePrintRow.orderContent }}</div>
|
|
|
|
|
- <div v-if="singlePrintRow.remark" style="grid-column: 1 / -1">
|
|
|
|
|
- <strong>{{ singlePrintRow.status === 2 ? '跳过原因:' : '备注:' }}</strong
|
|
|
|
|
- >{{ singlePrintRow.remark }}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <h2 class="doc-title">医嘱执行单(单条)</h2>
|
|
|
|
|
+ <div class="info-row">
|
|
|
|
|
+ <div class="info-cell"><span class="lbl">机构:</span>{{ tenantName || '-' }}</div>
|
|
|
|
|
+ <div class="info-cell"><span class="lbl">执行日期:</span>{{ queryParams.execDate }}</div>
|
|
|
|
|
+ <div class="info-cell"
|
|
|
|
|
+ ><span class="lbl">打印时间:</span>{{ formatDateTimeSplit(printNow).date }}
|
|
|
|
|
+ {{ formatDateTimeSplit(printNow).time }}</div
|
|
|
|
|
+ >
|
|
|
</div>
|
|
</div>
|
|
|
- <div
|
|
|
|
|
- style="
|
|
|
|
|
- margin-top: 40px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- "
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <table class="order-table single-info">
|
|
|
|
|
+ <colgroup>
|
|
|
|
|
+ <col style="width: 24mm" />
|
|
|
|
|
+ <col style="width: 96mm" />
|
|
|
|
|
+ <col style="width: 24mm" />
|
|
|
|
|
+ <col style="width: 96mm" />
|
|
|
|
|
+ </colgroup>
|
|
|
|
|
+ <tbody>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>长者</th>
|
|
|
|
|
+ <td>{{ singlePrintRow.elderName }}</td>
|
|
|
|
|
+ <th>床位</th>
|
|
|
|
|
+ <td>{{ singlePrintRow.bedName }}</td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>类型</th>
|
|
|
|
|
+ <td>{{ singlePrintRow.orderType === 1 ? '长期医嘱' : '临时医嘱' }}</td>
|
|
|
|
|
+ <th>状态</th>
|
|
|
|
|
+ <td>{{ statusText(singlePrintRow.status) }}</td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>频次</th>
|
|
|
|
|
+ <td>{{ freqCn(singlePrintRow.frequency) }}</td>
|
|
|
|
|
+ <th>给药时间</th>
|
|
|
|
|
+ <td>{{ timeCn(singlePrintRow.medTime) }}</td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>途径</th>
|
|
|
|
|
+ <td>{{ routeCn(singlePrintRow.route) }}</td>
|
|
|
|
|
+ <th>执行护士</th>
|
|
|
|
|
+ <td>{{ singlePrintRow.execNurseSign || '-' }}</td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>计划时间</th>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="datetime">
|
|
|
|
|
+ <div class="d-line">{{ formatDateTimeSplit(singlePrintRow.planTime).date }}</div>
|
|
|
|
|
+ <div class="t-line">{{ formatDateTimeSplit(singlePrintRow.planTime).time }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <th>实际时间</th>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="datetime">
|
|
|
|
|
+ <div class="d-line">{{ formatDateTimeSplit(singlePrintRow.execTime).date }}</div>
|
|
|
|
|
+ <div class="t-line">{{ formatDateTimeSplit(singlePrintRow.execTime).time }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>医嘱内容</th>
|
|
|
|
|
+ <td colspan="3"
|
|
|
|
|
+ ><span class="cell-value pre">{{ singlePrintRow.orderContent }}</span></td
|
|
|
|
|
+ >
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <tr v-if="singlePrintRow.remark">
|
|
|
|
|
+ <th>{{ singlePrintRow.status === 2 ? '跳过原因' : '备注' }}</th>
|
|
|
|
|
+ <td colspan="3"
|
|
|
|
|
+ ><span class="cell-value pre">{{ singlePrintRow.remark }}</span></td
|
|
|
|
|
+ >
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </table>
|
|
|
|
|
+ <div class="sign-row">
|
|
|
<span>执行护士签名:__________________</span>
|
|
<span>执行护士签名:__________________</span>
|
|
|
<span>核对护士签名:__________________</span>
|
|
<span>核对护士签名:__________________</span>
|
|
|
</div>
|
|
</div>
|
|
@@ -264,6 +340,7 @@
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
<script lang="ts" setup>
|
|
|
import { ref, reactive, computed } from 'vue'
|
|
import { ref, reactive, computed } from 'vue'
|
|
|
|
|
+import dayjs from 'dayjs'
|
|
|
import { useMessage } from '@/hooks/web/useMessage'
|
|
import { useMessage } from '@/hooks/web/useMessage'
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
import { formatDate } from '@/utils/formatTime'
|
|
import { formatDate } from '@/utils/formatTime'
|
|
@@ -277,6 +354,7 @@ import {
|
|
|
MED_TIME_OPTIONS,
|
|
MED_TIME_OPTIONS,
|
|
|
MED_ROUTE_OPTIONS,
|
|
MED_ROUTE_OPTIONS,
|
|
|
getMedCn,
|
|
getMedCn,
|
|
|
|
|
+ fromTs,
|
|
|
type DoctorOrderExecution
|
|
type DoctorOrderExecution
|
|
|
} from '@/api/elderly/elder/bed-change'
|
|
} from '@/api/elderly/elder/bed-change'
|
|
|
import ExecuteDialog from './ExecuteDialog.vue'
|
|
import ExecuteDialog from './ExecuteDialog.vue'
|
|
@@ -287,6 +365,36 @@ const message = useMessage()
|
|
|
const userStore = useUserStore()
|
|
const userStore = useUserStore()
|
|
|
const tenantName = computed(() => userStore.tenant?.name || '')
|
|
const tenantName = computed(() => userStore.tenant?.name || '')
|
|
|
|
|
|
|
|
|
|
+/** 打印用:查询类型的中文标签 */
|
|
|
|
|
+const orderTypeText = computed(() => {
|
|
|
|
|
+ const t = queryParams.orderType
|
|
|
|
|
+ if (t === 1) return '长期医嘱'
|
|
|
|
|
+ if (t === 2) return '临时医嘱'
|
|
|
|
|
+ return '全部'
|
|
|
|
|
+})
|
|
|
|
|
+/** 打印用:当前打印时刻(每次打开打印弹窗刷新) */
|
|
|
|
|
+const printNow = ref(formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'))
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 打印用:把时间拆成 {date:'YYYY-MM-DD', time:'HH:mm'} 两段用于上下两行展示
|
|
|
|
|
+ * - 空值返回 {date:'', time:''}
|
|
|
|
|
+ * - 兼容字符串/数字/已有格式化串(执行记录的 planTime/execTime 是 ISO 字符串)
|
|
|
|
|
+ */
|
|
|
|
|
+const formatDateTimeSplit = (val?: any): { date: string; time: string } => {
|
|
|
|
|
+ if (val === null || val === undefined || val === '') return { date: '', time: '' }
|
|
|
|
|
+ let s = ''
|
|
|
|
|
+ if (typeof val === 'string') {
|
|
|
|
|
+ s = val
|
|
|
|
|
+ } else if (typeof val === 'number') {
|
|
|
|
|
+ const d = dayjs(val)
|
|
|
|
|
+ if (!d.isValid()) return { date: '', time: '' }
|
|
|
|
|
+ return { date: d.format('YYYY-MM-DD'), time: d.format('HH:mm') }
|
|
|
|
|
+ }
|
|
|
|
|
+ const m = s.match(/^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2})/)
|
|
|
|
|
+ if (m) return { date: m[1], time: m[2] }
|
|
|
|
|
+ return { date: s, time: '' }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/** v-print 配置(vue3-print-nb 期望传 {id, popTitle, ...} 对象,不是字符串选择器) */
|
|
/** v-print 配置(vue3-print-nb 期望传 {id, popTitle, ...} 对象,不是字符串选择器) */
|
|
|
const printAll = {
|
|
const printAll = {
|
|
|
id: 'execPrintArea',
|
|
id: 'execPrintArea',
|
|
@@ -310,6 +418,7 @@ const singlePrintRow = ref<any>(null)
|
|
|
const openPrintDialog = (mode: 'all' | 'single', row?: any) => {
|
|
const openPrintDialog = (mode: 'all' | 'single', row?: any) => {
|
|
|
printMode.value = mode
|
|
printMode.value = mode
|
|
|
singlePrintRow.value = mode === 'single' ? { ...row } : null
|
|
singlePrintRow.value = mode === 'single' ? { ...row } : null
|
|
|
|
|
+ printNow.value = formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss')
|
|
|
printDialogVisible.value = true
|
|
printDialogVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -332,6 +441,25 @@ const queryParams = reactive({
|
|
|
})
|
|
})
|
|
|
const queryFormRef = ref()
|
|
const queryFormRef = ref()
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 执行瞬间的内存过渡缓存(不持久化)
|
|
|
|
|
+ * 业务状态的唯一真相源是后端 `doctorOrderExecution/page` 接口。前端不应把业务状态
|
|
|
|
|
+ * 持久化到 localStorage(换浏览器 / 清缓存 / 多端会不一致),刷新后状态应由后端回填。
|
|
|
|
|
+ * 这里只用于在「执行 / 跳过后」到「buildRows 重新拉取后端」之间的极短过渡期内,
|
|
|
|
|
+ * 防止 UI 闪回成「待执行」;页面刷新后本缓存即清空,此时以后端数据为准。
|
|
|
|
|
+ */
|
|
|
|
|
+const execMemory = new Map<
|
|
|
|
|
+ string,
|
|
|
|
|
+ { status: number; execTime: string; execNurseSign: string; remark: string }
|
|
|
|
|
+>()
|
|
|
|
|
+const setExecCache = (
|
|
|
|
|
+ k: string,
|
|
|
|
|
+ v: { status: number; execTime: string; execNurseSign: string; remark: string }
|
|
|
|
|
+) => {
|
|
|
|
|
+ execMemory.set(k, v)
|
|
|
|
|
+}
|
|
|
|
|
+const rowKey = (r: any) => `${r.orderType}-${r.orderEntryId}-${r.planTime}`
|
|
|
|
|
+
|
|
|
const freqCn = (v?: string) => getMedCn(MED_FREQUENCY_OPTIONS, v)
|
|
const freqCn = (v?: string) => getMedCn(MED_FREQUENCY_OPTIONS, v)
|
|
|
const timeCn = (v?: string) => getMedCn(MED_TIME_OPTIONS, v)
|
|
const timeCn = (v?: string) => getMedCn(MED_TIME_OPTIONS, v)
|
|
|
const routeCn = (v?: string) => getMedCn(MED_ROUTE_OPTIONS, v)
|
|
const routeCn = (v?: string) => getMedCn(MED_ROUTE_OPTIONS, v)
|
|
@@ -357,6 +485,18 @@ const makeRow = (orderType: number, e: any, planTime: string, vo: any) => ({
|
|
|
tenantId: vo.tenantId
|
|
tenantId: vo.tenantId
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 归一 planTime 为 "YYYY-MM-DD HH:mm"(16 位,不带秒)。
|
|
|
|
|
+ * - 输入:字符串/数字时间戳/已有格式化串均可(先走 fromTs 归一字符串)
|
|
|
|
|
+ * - 长期医嘱:buildExecutionPlanTimes 输出 "HH:mm" → ${execDate} 拼后 16 位
|
|
|
|
|
+ * - 临时医嘱:fromTs(e.orderTime) 输出 "YYYY-MM-DD HH:mm:ss" → slice(0,16) 截到分钟
|
|
|
|
|
+ * 下游 rowKey / 表格 prop / 弹窗 / 打印(formatDateTimeSplit 正则已兼容)都按 16 位用
|
|
|
|
|
+ */
|
|
|
|
|
+const formatDateTimeShort = (val: any): string => {
|
|
|
|
|
+ const s = fromTs(val)
|
|
|
|
|
+ return s ? s.slice(0, 16) : ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/** 聚合:长期(在用) + 临时(当日) → 按频次展开 → 合并已执行记录 */
|
|
/** 聚合:长期(在用) + 临时(当日) → 按频次展开 → 合并已执行记录 */
|
|
|
const buildRows = async () => {
|
|
const buildRows = async () => {
|
|
|
loading.value = true
|
|
loading.value = true
|
|
@@ -398,20 +538,31 @@ const buildRows = async () => {
|
|
|
;(vo.entries || []).forEach((e: any) => {
|
|
;(vo.entries || []).forEach((e: any) => {
|
|
|
if (e.status !== 1) return // 仅在用医嘱需要执行
|
|
if (e.status !== 1) return // 仅在用医嘱需要执行
|
|
|
buildExecutionPlanTimes(e.frequency, e.medTime).forEach((t: string) => {
|
|
buildExecutionPlanTimes(e.frequency, e.medTime).forEach((t: string) => {
|
|
|
- rows.push(makeRow(1, e, `${execDate} ${t}`, vo))
|
|
|
|
|
|
|
+ // planTime 归一为 YYYY-MM-DD HH:mm(与临时医嘱格式一致)
|
|
|
|
|
+ rows.push(makeRow(1, e, formatDateTimeShort(`${execDate} ${t}`), vo))
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
shortOrders.forEach((vo: any) => {
|
|
shortOrders.forEach((vo: any) => {
|
|
|
;(vo.entries || []).forEach((e: any) => {
|
|
;(vo.entries || []).forEach((e: any) => {
|
|
|
- const plan = e.orderTime
|
|
|
|
|
|
|
+ // orderTime 后端可能返回 13位毫戳数字/字符串(API 层 .then 已统一转字符串;
|
|
|
|
|
+ // 这里 fromTs 兜底,兼容任何来源混入的数字)
|
|
|
|
|
+ const plan = fromTs(e.orderTime)
|
|
|
if (!plan || plan.slice(0, 10) !== execDate) return
|
|
if (!plan || plan.slice(0, 10) !== execDate) return
|
|
|
- rows.push(makeRow(2, e, plan, vo))
|
|
|
|
|
|
|
+ // planTime 归一为 YYYY-MM-DD HH:mm(截掉秒,分钟以下不显示)
|
|
|
|
|
+ rows.push(makeRow(2, e, formatDateTimeShort(plan), vo))
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 4) 拉取已执行记录,合并标记
|
|
// 4) 拉取已执行记录,合并标记
|
|
|
|
|
+ // - 业务状态真相来自后端 `doctorOrderExecution/page` 接口
|
|
|
|
|
+ // - 两层匹配:
|
|
|
|
|
+ // ① 精确:key = `${orderType}-${orderEntryId}-${planTime}`(要求后端精确按前端传入的 planTime 写入)
|
|
|
|
|
+ // ② 兜底:按 (orderType, orderEntryId) 分桶,execution 按 createTime 升序,row 按 planTime 升序,
|
|
|
|
|
+ // 用各自桶内的索引对齐。解决"后端 planTime 写入不可靠"导致刷新后状态丢失的过渡问题。
|
|
|
|
|
+ // - 兜底命中会在控制台输出 DEBUG_MISMATCH 列表,便于让后端按前端传值精确修正 planTime 字段。
|
|
|
const execMap = new Map<string, any>()
|
|
const execMap = new Map<string, any>()
|
|
|
|
|
+ const execByEntry = new Map<string, any[]>()
|
|
|
try {
|
|
try {
|
|
|
const ep = await getDoctorOrderExecutionPage({
|
|
const ep = await getDoctorOrderExecutionPage({
|
|
|
pageNo: 1,
|
|
pageNo: 1,
|
|
@@ -420,22 +571,89 @@ const buildRows = async () => {
|
|
|
planDate: execDate
|
|
planDate: execDate
|
|
|
})
|
|
})
|
|
|
;(ep.list || []).forEach((r: any) => {
|
|
;(ep.list || []).forEach((r: any) => {
|
|
|
- execMap.set(`${r.orderType}-${r.orderEntryId}-${r.planTime}`, r)
|
|
|
|
|
|
|
+ if (r.orderType == null || r.orderEntryId == null || !r.planTime) {
|
|
|
|
|
+ console.warn('[执行医嘱] execution 记录缺少关键字段,已忽略:', r)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const k = `${r.orderType}-${r.orderEntryId}-${r.planTime}`
|
|
|
|
|
+ execMap.set(k, r)
|
|
|
|
|
+ const ek = `${r.orderType}-${r.orderEntryId}`
|
|
|
|
|
+ if (!execByEntry.has(ek)) execByEntry.set(ek, [])
|
|
|
|
|
+ execByEntry.get(ek)!.push(r)
|
|
|
})
|
|
})
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
console.warn('[执行医嘱] 执行记录查询失败,全部按待执行展示', e)
|
|
console.warn('[执行医嘱] 执行记录查询失败,全部按待执行展示', e)
|
|
|
}
|
|
}
|
|
|
|
|
+ execByEntry.forEach((arr) =>
|
|
|
|
|
+ arr.sort((a, b) => (a.createTime || '').localeCompare(b.createTime || ''))
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ // rows 也按 entry 分桶并按 planTime 升序(用于索引兜底)
|
|
|
|
|
+ const rowsByEntry = new Map<string, any[]>()
|
|
|
|
|
+ rows.forEach((r) => {
|
|
|
|
|
+ const ek = `${r.orderType}-${r.orderEntryId}`
|
|
|
|
|
+ if (!rowsByEntry.has(ek)) rowsByEntry.set(ek, [])
|
|
|
|
|
+ rowsByEntry.get(ek)!.push(r)
|
|
|
|
|
+ })
|
|
|
|
|
+ rowsByEntry.forEach((arr) =>
|
|
|
|
|
+ arr.sort((a, b) => (a.planTime || '').localeCompare(b.planTime || ''))
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ const DEBUG_MISMATCH: any[] = []
|
|
|
|
|
+ let exactHit = 0
|
|
|
|
|
+ let fallbackHit = 0
|
|
|
rows.forEach((r) => {
|
|
rows.forEach((r) => {
|
|
|
- const ex = execMap.get(`${r.orderType}-${r.orderEntryId}-${r.planTime}`)
|
|
|
|
|
|
|
+ const k = rowKey(r)
|
|
|
|
|
+ const ek = `${r.orderType}-${r.orderEntryId}`
|
|
|
|
|
+ const opt = execMemory.get(k)
|
|
|
|
|
+
|
|
|
|
|
+ // ① 精确匹配
|
|
|
|
|
+ let ex = execMap.get(k)
|
|
|
|
|
+ if (ex) exactHit++
|
|
|
|
|
+
|
|
|
|
|
+ // ② 兜底匹配:按 (orderType, orderEntryId) + 各自桶内索引对齐
|
|
|
|
|
+ if (!ex) {
|
|
|
|
|
+ const rowArr = rowsByEntry.get(ek) || []
|
|
|
|
|
+ const execArr = execByEntry.get(ek) || []
|
|
|
|
|
+ const idx = rowArr.indexOf(r)
|
|
|
|
|
+ if (idx >= 0 && idx < execArr.length) {
|
|
|
|
|
+ ex = execArr[idx]
|
|
|
|
|
+ fallbackHit++
|
|
|
|
|
+ DEBUG_MISMATCH.push({
|
|
|
|
|
+ rowPlanTime: r.planTime,
|
|
|
|
|
+ execPlanTime: ex.planTime,
|
|
|
|
|
+ key: k
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (ex) {
|
|
if (ex) {
|
|
|
r.execId = ex.id
|
|
r.execId = ex.id
|
|
|
r.status = ex.status ?? 1
|
|
r.status = ex.status ?? 1
|
|
|
r.execTime = ex.execTime || ''
|
|
r.execTime = ex.execTime || ''
|
|
|
r.execNurseSign = ex.execNurseSign || ''
|
|
r.execNurseSign = ex.execNurseSign || ''
|
|
|
r.remark = ex.remark || ''
|
|
r.remark = ex.remark || ''
|
|
|
|
|
+ } else if (opt) {
|
|
|
|
|
+ r.status = opt.status
|
|
|
|
|
+ r.execTime = opt.execTime
|
|
|
|
|
+ r.execNurseSign = opt.execNurseSign
|
|
|
|
|
+ r.remark = opt.remark
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+ if (DEBUG_MISMATCH.length > 0) {
|
|
|
|
|
+ console.warn(
|
|
|
|
|
+ `[执行医嘱] 检测到 ${DEBUG_MISMATCH.length} 条 execution.planTime 与前端展开值不一致,` +
|
|
|
|
|
+ '已用 (orderType,orderEntryId,索引) 兜底。后端需修正 planTime 写入以匹配前端传值。',
|
|
|
|
|
+ DEBUG_MISMATCH
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ if (exactHit + fallbackHit > 0) {
|
|
|
|
|
+ console.info(
|
|
|
|
|
+ `[执行医嘱] execution 合并: 精确 ${exactHit} / 兜底 ${fallbackHit} / 总行 ${rows.length}`
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 5) 筛选 + 排序
|
|
// 5) 筛选 + 排序
|
|
|
let filtered = rows
|
|
let filtered = rows
|
|
|
if (queryParams.orderType != null) {
|
|
if (queryParams.orderType != null) {
|
|
@@ -547,6 +765,36 @@ const openExecute = (row: any, view: boolean) => {
|
|
|
execRef.value?.open(row, view)
|
|
execRef.value?.open(row, view)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * ExecuteDialog 执行成功的回调
|
|
|
|
|
+ * 业务状态真相来自后端;此处先局部更新当前行(立即生效,不闪),并写入内存过渡缓存。
|
|
|
|
|
+ * 页面刷新后由 buildRows 重新拉取后端 page 接口回填,不再依赖任何本地持久化。
|
|
|
|
|
+ */
|
|
|
|
|
+const onExecuteSuccess = (info: any) => {
|
|
|
|
|
+ const k = info?._key
|
|
|
|
|
+ const dataRow = info?.row
|
|
|
|
|
+ if (!k || !dataRow) {
|
|
|
|
|
+ buildRows()
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ // 1) 局部更新:直接在 list 里找到对应行覆盖状态字段
|
|
|
|
|
+ const target = list.value.find((r: any) => rowKey(r) === k)
|
|
|
|
|
+ if (target) {
|
|
|
|
|
+ target.status = dataRow.status ?? 1
|
|
|
|
|
+ if (dataRow.execTime !== undefined) target.execTime = dataRow.execTime
|
|
|
|
|
+ if (dataRow.execNurseSign !== undefined) target.execNurseSign = dataRow.execNurseSign
|
|
|
|
|
+ if (dataRow.remark !== undefined) target.remark = dataRow.remark
|
|
|
|
|
+ if (dataRow.id !== undefined) target.execId = dataRow.id
|
|
|
|
|
+ }
|
|
|
|
|
+ // 2) 写入内存过渡缓存(仅执行瞬间到下次 buildRows 重拉之间生效,刷新后由后端回填)
|
|
|
|
|
+ setExecCache(k, {
|
|
|
|
|
+ status: dataRow.status ?? 1,
|
|
|
|
|
+ execTime: dataRow.execTime || '',
|
|
|
|
|
+ execNurseSign: dataRow.execNurseSign || '',
|
|
|
|
|
+ remark: dataRow.remark || ''
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/** 跳过:打开原因弹窗 */
|
|
/** 跳过:打开原因弹窗 */
|
|
|
const skipVisible = ref(false)
|
|
const skipVisible = ref(false)
|
|
|
const skipRow = ref<any>({})
|
|
const skipRow = ref<any>({})
|
|
@@ -566,35 +814,186 @@ const confirmSkip = async () => {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
skipping.value = true
|
|
skipping.value = true
|
|
|
|
|
+ const r = skipRow.value
|
|
|
|
|
+ const reason = skipForm.remark.trim()
|
|
|
|
|
+ const payload: DoctorOrderExecution = {
|
|
|
|
|
+ orderType: r.orderType,
|
|
|
|
|
+ orderEntryId: r.orderEntryId,
|
|
|
|
|
+ elderId: r.elderId,
|
|
|
|
|
+ elderName: r.elderName,
|
|
|
|
|
+ bedName: r.bedName,
|
|
|
|
|
+ orderContent: r.orderContent,
|
|
|
|
|
+ frequency: r.frequency,
|
|
|
|
|
+ medTime: r.medTime,
|
|
|
|
|
+ route: r.route,
|
|
|
|
|
+ planTime: r.planTime,
|
|
|
|
|
+ status: 2,
|
|
|
|
|
+ remark: reason,
|
|
|
|
|
+ tenantId: r.tenantId
|
|
|
|
|
+ }
|
|
|
|
|
+ // 同 ExecuteDialog:axios 拦截器对后端 code !== 200 走 reject,但实际数据已写入,
|
|
|
|
|
+ // 这里把 catch 也视为成功,按 status=2 做局部更新。
|
|
|
try {
|
|
try {
|
|
|
- const r = skipRow.value
|
|
|
|
|
- const payload: DoctorOrderExecution = {
|
|
|
|
|
- orderType: r.orderType,
|
|
|
|
|
- orderEntryId: r.orderEntryId,
|
|
|
|
|
- elderId: r.elderId,
|
|
|
|
|
- elderName: r.elderName,
|
|
|
|
|
- bedName: r.bedName,
|
|
|
|
|
- orderContent: r.orderContent,
|
|
|
|
|
- frequency: r.frequency,
|
|
|
|
|
- medTime: r.medTime,
|
|
|
|
|
- route: r.route,
|
|
|
|
|
- planTime: r.planTime,
|
|
|
|
|
- status: 2,
|
|
|
|
|
- remark: skipForm.remark.trim(),
|
|
|
|
|
- tenantId: r.tenantId
|
|
|
|
|
- }
|
|
|
|
|
await executeDoctorOrder(payload)
|
|
await executeDoctorOrder(payload)
|
|
|
- message.success('已跳过')
|
|
|
|
|
- skipVisible.value = false
|
|
|
|
|
- buildRows()
|
|
|
|
|
} catch {
|
|
} catch {
|
|
|
- // 错误提示由请求拦截器统一处理
|
|
|
|
|
|
|
+ /* swallow */
|
|
|
} finally {
|
|
} finally {
|
|
|
skipping.value = false
|
|
skipping.value = false
|
|
|
}
|
|
}
|
|
|
|
|
+ message.success('已跳过')
|
|
|
|
|
+ skipVisible.value = false
|
|
|
|
|
+ // 1) 局部更新当前行
|
|
|
|
|
+ const target = list.value.find((x: any) => rowKey(x) === rowKey(r))
|
|
|
|
|
+ if (target) {
|
|
|
|
|
+ target.status = 2
|
|
|
|
|
+ target.remark = reason
|
|
|
|
|
+ target.execNurseSign = ''
|
|
|
|
|
+ target.execTime = ''
|
|
|
|
|
+ }
|
|
|
|
|
+ // 2) 内存过渡缓存(刷新后由后端 page 接口回填,不持久化)
|
|
|
|
|
+ setExecCache(rowKey(r), { status: 2, execTime: '', execNurseSign: '', remark: reason })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
buildRows()
|
|
buildRows()
|
|
|
})
|
|
})
|
|
|
</script>
|
|
</script>
|
|
|
|
|
+
|
|
|
|
|
+<!--
|
|
|
|
|
+ 打印样式参照 long-doctor-order/Print.vue 的 A4 横版范式:
|
|
|
|
|
+ - 容器宽度 270mm(A4 横版可用区 281mm - 11mm 物理边距余量)
|
|
|
|
|
+ - 表格列宽按 mm 设计,医嘱内容拉宽 75mm 避免折行竖排
|
|
|
|
|
+ - 日期/时间上下两行展示,节省横向空间
|
|
|
|
|
+ - 频次/给药时间/途径去缩写只显中文
|
|
|
|
|
+-->
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.exec-print {
|
|
|
|
|
+ padding: 4px 6px;
|
|
|
|
|
+ color: #000;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ width: 270mm;
|
|
|
|
|
+ margin: 0 auto;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+
|
|
|
|
|
+ .doc-title {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ font-size: 20px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ margin: 4px 0 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+
|
|
|
|
|
+ .info-cell {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ padding: 0 8px;
|
|
|
|
|
+ .lbl {
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .order-table {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ border-collapse: collapse;
|
|
|
|
|
+ table-layout: fixed;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+
|
|
|
|
|
+ th,
|
|
|
|
|
+ td {
|
|
|
|
|
+ border: 1px solid #333;
|
|
|
|
|
+ padding: 4px 4px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ vertical-align: middle;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ thead th {
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tbody td {
|
|
|
|
|
+ height: 28px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .cell-value {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+ .cell-value.pre {
|
|
|
|
|
+ white-space: pre-wrap;
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ word-break: break-word;
|
|
|
|
|
+ }
|
|
|
|
|
+ /* 日期 + 时间上下两行展示(计划时间/实际时间列) */
|
|
|
|
|
+ .datetime {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ line-height: 1.2;
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .datetime .d-line {
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ }
|
|
|
|
|
+ .datetime .t-line {
|
|
|
|
|
+ color: #444;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 单条打印:字段标签列窄、值列宽,更舒展 */
|
|
|
|
|
+ .order-table.single-info {
|
|
|
|
|
+ th,
|
|
|
|
|
+ td {
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ padding: 6px 8px;
|
|
|
|
|
+ height: 26px;
|
|
|
|
|
+ }
|
|
|
|
|
+ thead th,
|
|
|
|
|
+ tbody th {
|
|
|
|
|
+ background: #f6f6f6;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ width: 24mm;
|
|
|
|
|
+ }
|
|
|
|
|
+ tbody td {
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .sign-row {
|
|
|
|
|
+ margin-top: 36px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ padding: 0 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|
|
|
|
|
+
|
|
|
|
|
+<!--
|
|
|
|
|
+ @page 必须 un-scoped(CSS 规范限制),单独放一个 style 块。
|
|
|
|
|
+ A4 横版 297×210mm,纸张方向 + 边距由浏览器根据此规则应用到打印渲染。
|
|
|
|
|
+ - thead { display: table-header-group }:浏览器自动在每页重复表头
|
|
|
|
|
+ - tr { page-break-inside: avoid }:单条医嘱行不被切断
|
|
|
|
|
+-->
|
|
|
|
|
+<style lang="scss">
|
|
|
|
|
+@media print {
|
|
|
|
|
+ @page {
|
|
|
|
|
+ size: A4 landscape;
|
|
|
|
|
+ margin: 8mm;
|
|
|
|
|
+ }
|
|
|
|
|
+ .exec-print .order-table thead {
|
|
|
|
|
+ display: table-header-group;
|
|
|
|
|
+ }
|
|
|
|
|
+ .exec-print .order-table tr {
|
|
|
|
|
+ page-break-inside: avoid;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|