Files
his/openhis-ui-vue3/src/views/inpatientDoctor/home/components/applicationShow/examineApplication.vue
2026-05-14 11:47:18 +08:00

1149 lines
35 KiB
Vue
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* @Author: sjjh
* @Date: 2025-09-05 21:16:06
* @Description: 检查申请
-->
<template>
<div class="report-container">
<div class="report-section">
<div class="report-title">
<span>检查申请</span>
<el-icon
class="report-refresh-icon"
:class="{ 'is-loading': loading }"
@click="handleRefresh"
>
<Refresh />
</el-icon>
</div>
<!-- 筛选表单 -->
<div class="filter-form">
<el-form :inline="true" :model="filterForm" class="filter-form-content">
<el-form-item label="申请日期">
<el-date-picker
v-model="filterForm.dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
clearable
style="width: 240px"
/>
</el-form-item>
<el-form-item label="申请单状态">
<el-select
v-model="filterForm.status"
placeholder="请选择"
clearable
style="width: 150px"
>
<el-option label="全部" value="" />
<el-option label="待签发" value="0" />
<el-option label="已签发" value="1" />
<el-option label="已校对" value="2" />
<el-option label="待接收" value="3" />
<el-option label="已接收" value="4" />
<el-option label="已检查" value="5" />
<el-option label="已出报告" value="6" />
<el-option label="已作废" value="7" />
</el-select>
</el-form-item>
<el-form-item label="关键字">
<el-input
v-model="filterForm.keyword"
placeholder="申请单号 / 检查项目名称"
clearable
style="width: 220px"
@keyup.enter="handleSearch"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch" :loading="loading">
<el-icon><Search /></el-icon>
查询
</el-button>
<el-button @click="handleReset">
<el-icon><Refresh /></el-icon>
重置
</el-button>
</el-form-item>
</el-form>
</div>
<div class="report-table-wrapper">
<el-table
v-loading="loading"
:data="tableData"
border
size="small"
height="100%"
style="width: 100%"
>
<template #empty>
<div class="empty-data">
<el-empty description="暂无匹配记录" :image-size="80" />
</div>
</template>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="patientName" label="患者姓名" width="120" />
<el-table-column prop="name" label="申请单名称" width="140" />
<el-table-column prop="createTime" label="创建时间" width="160" />
<el-table-column prop="prescriptionNo" label="申请单号" width="140" />
<el-table-column prop="requesterId_dictText" label="申请者" width="120" />
<el-table-column label="申请单状态" width="120" align="center">
<template #default="scope">
<el-tag :type="getStatusTagType(scope.row.status)" effect="plain" round>
{{ parseStatus(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="280" align="center" fixed="right">
<template #default="scope">
<!-- 详情 - 所有状态都显示 -->
<el-button link type="primary" @click="handleViewDetail(scope.row)">详情</el-button>
<!-- 待签发修改删除 -->
<template v-if="scope.row.status === '0' || scope.row.status === 0">
<el-button link type="primary" @click="handleEdit(scope.row)">修改</el-button>
<el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
<!-- 已签发撤回 -->
<template v-else-if="scope.row.status === '1' || scope.row.status === 1">
<el-button link type="warning" @click="handleRecall(scope.row)">撤回</el-button>
</template>
<!-- 已校对/待接收打印 -->
<template v-else-if="scope.row.status === '2' || scope.row.status === 2 || scope.row.status === '3' || scope.row.status === 3">
<el-button link type="primary" @click="handlePrint(scope.row)">打印</el-button>
</template>
<!-- 已接收/已检查看报告 -->
<template v-else-if="scope.row.status === '4' || scope.row.status === 4 || scope.row.status === '5' || scope.row.status === 5">
<el-button link type="success" @click="handleViewReport(scope.row)">看报告</el-button>
</template>
<!-- 已出报告打印看报告 -->
<template v-else-if="scope.row.status === '6' || scope.row.status === 6">
<el-button link type="primary" @click="handlePrint(scope.row)">打印</el-button>
<el-button link type="success" @click="handleViewReport(scope.row)">看报告</el-button>
</template>
<!-- 已作废无额外按钮 -->
<template v-else-if="scope.row.status === '7' || scope.row.status === 7">
</template>
<!-- 其他/未知状态仅详情 -->
<template v-else>
</template>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- 详情弹窗 -->
<el-dialog
v-model="detailDialogVisible"
title="检查申请详情"
width="800px"
destroy-on-close
top="5vh"
:close-on-click-modal="false"
>
<div v-if="currentDetail" class="applicationShow-container">
<div class="applicationShow-container-content">
<el-descriptions title="基本信息" :column="2">
<el-descriptions-item label="患者姓名">{{
currentDetail.patientName || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单名称">{{
currentDetail.name || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单状态">{{
parseStatus(currentDetail.status)
}}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{
currentDetail.createTime || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单号">{{
currentDetail.prescriptionNo || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请者">{{
currentDetail.requesterId_dictText || '-'
}}</el-descriptions-item>
<el-descriptions-item label="就诊ID">{{
currentDetail.encounterId || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单ID">{{
currentDetail.requestFormId || '-'
}}</el-descriptions-item>
</el-descriptions>
</div>
<div v-if="descJsonData && hasMatchedFields" class="applicationShow-container-content">
<el-descriptions title="申请单描述" :column="2">
<template v-for="(value, key) in descJsonData" :key="key">
<el-descriptions-item v-if="isFieldMatched(key)" :label="getFieldLabel(key)">
{{ transformField(key, value) || '-' }}
</el-descriptions-item>
</template>
</el-descriptions>
</div>
<div
v-if="currentDetail.requestFormDetailList && currentDetail.requestFormDetailList.length"
class="applicationShow-container-table"
>
<el-table :data="currentDetail.requestFormDetailList" border>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="adviceName" label="医嘱名称" />
<el-table-column prop="quantity" label="数量" width="80" align="center" />
<el-table-column prop="unitCode_dictText" label="单位" width="100" />
<el-table-column prop="totalPrice" label="总价" width="100" align="right" />
</el-table>
</div>
</div>
<template #footer>
<el-button @click="detailDialogVisible = false">关闭</el-button>
</template>
</el-dialog>
<!-- 修改申请单弹窗 - 复用检查申请单组件 -->
<el-dialog
v-model="editDialogVisible"
title="修改检查申请"
width="1200px"
destroy-on-close
top="5vh"
:close-on-click-modal="false"
>
<MedicalExaminations
v-if="editDialogVisible"
ref="editFormRef"
:is-edit-mode="true"
:edit-data="editingRow"
:external-patient-info="patientInfo"
/>
<template #footer>
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleEditSubmit">确认</el-button>
</template>
</el-dialog>
<!-- 查看报告弹窗 -->
<el-dialog
v-model="reportDialogVisible"
:title="'检查报告 - ' + (reportData?.prescriptionNo || '')"
width="900px"
destroy-on-close
top="5vh"
:close-on-click-modal="false"
>
<div v-loading="reportLoading" class="report-viewer">
<!-- 报告基本信息 -->
<div v-if="reportData" class="report-viewer-container">
<el-descriptions title="报告信息" :column="2" border size="small">
<el-descriptions-item label="患者姓名">{{ reportData.patientName || reportRow?.patientName || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请单号">{{ reportData.prescriptionNo || reportRow?.prescriptionNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请单名称">{{ reportData.name || reportRow?.name || '-' }}</el-descriptions-item>
<el-descriptions-item label="报告时间">{{ reportData.reportTime || '-' }}</el-descriptions-item>
<el-descriptions-item label="诊断意见" :span="2">{{ reportData.diagnosis || reportData.conclusion || '-' }}</el-descriptions-item>
</el-descriptions>
<!-- 报告详细内容 -->
<div v-if="reportData.content" class="report-content-section">
<div class="section-title">报告内容</div>
<div class="report-content-text">{{ reportData.content }}</div>
</div>
<!-- 影像预览 - PACS链接 -->
<div v-if="reportData.imageUrl || reportData.pacsUrl" class="report-image-section">
<div class="section-title">
影像预览
<el-button
v-if="reportData.imageUrl || reportData.pacsUrl"
type="primary"
size="small"
plain
style="margin-left: 12px;"
@click="openPacsLink"
>
<el-icon><Link /></el-icon>
打开PACS影像
</el-button>
</div>
<iframe
v-if="reportData.imageUrl"
:src="reportData.imageUrl"
class="report-iframe"
frameborder="0"
/>
<el-empty v-else-if="!reportData.imageUrl && reportData.pacsUrl" description="点击上方按钮打开PACS影像" :image-size="60" />
</div>
<!-- 完全无数据时的提示 -->
<el-empty v-if="!reportData.content && !reportData.imageUrl && !reportData.pacsUrl" description="暂无详细报告数据" :image-size="60" />
</div>
<!-- 未获取到报告 -->
<el-empty v-else description="暂未生成报告" :image-size="80" />
</div>
<template #footer>
<el-button @click="reportDialogVisible = false">关闭</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {computed, getCurrentInstance, ref, watch, nextTick} from 'vue';
import {Refresh, Search, Link} from '@element-plus/icons-vue';
import {patientInfo} from '../../store/patient.js';
import {getCheck, deleteRequestForm, withdrawRequestForm, getTestResult} from './api';
import {getDepartmentList} from '@/api/public.js';
import {getApplicationList, saveCheckd} from '../order/applicationForm/api';
import MedicalExaminations from '../order/applicationForm/medicalExaminations.vue';
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const loading = ref(false);
const detailDialogVisible = ref(false);
const currentDetail = ref(null);
const descJsonData = ref(null);
const orgOptions = ref([]);
const editForm = ref({
name: '',
targetDepartment: '',
symptom: '',
sign: '',
clinicalDiagnosis: '',
otherDiagnosis: '',
relatedResult: '',
attention: '',
examinationPurpose: '',
medicalHistorySummary: '',
});
// 报告弹窗相关
const reportDialogVisible = ref(false);
const reportLoading = ref(false);
const reportData = ref(null);
const reportRow = ref(null);
// 获取近7天的日期范围作为默认值
const getDefaultDateRange = () => {
const now = new Date();
const endDate = now.toISOString().split('T')[0];
const startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
return [startDate, endDate];
};
// 筛选表单数据
const filterForm = ref({
dateRange: getDefaultDateRange(), // 默认近一周
status: '', // 申请单状态
keyword: '', // 关键字搜索
});
const fetchData = async () => {
if (!patientInfo.value?.encounterId) {
tableData.value = [];
loading.value = false;
return;
}
loading.value = true;
try {
// 构建查询参数
const params = { encounterId: patientInfo.value.encounterId };
// 添加日期范围筛选
if (filterForm.value.dateRange && filterForm.value.dateRange.length === 2) {
params.startDate = filterForm.value.dateRange[0];
params.endDate = filterForm.value.dateRange[1];
}
// 添加状态筛选
if (filterForm.value.status !== '' && filterForm.value.status !== undefined) {
params.status = filterForm.value.status;
}
// 添加关键字搜索
if (filterForm.value.keyword && filterForm.value.keyword.trim()) {
params.keyword = filterForm.value.keyword.trim();
}
const res = await getCheck(params);
if (res.code === 200 && res.data) {
const raw = res.data?.records || res.data;
const list = Array.isArray(raw) ? raw : [raw];
console.log('API返回的原始数据:', JSON.stringify(list, null, 2));
tableData.value = list.filter(Boolean);
console.log('tableData设置后的第一条:', tableData.value[0]);
} else {
tableData.value = [];
}
} catch (e) {
console.warn('查询检查申请失败:', e.message);
tableData.value = [];
} finally {
loading.value = false;
}
};
const handleRefresh = async () => {
if (loading.value || !patientInfo.value?.encounterId) return;
await fetchData();
};
/**
* 查询按钮处理
*/
const handleSearch = async () => {
if (!patientInfo.value?.encounterId) {
proxy.$modal?.msgWarning?.('请先选择患者');
return;
}
await fetchData();
};
/**
* 重置按钮处理
*/
const handleReset = () => {
filterForm.value.dateRange = getDefaultDateRange();
filterForm.value.status = '';
filterForm.value.keyword = '';
fetchData();
};
/**
* 解析申请单状态
* @param {string|number} status - 状态码
* @returns {string} 状态文本
*/
const parseStatus = (status) => {
const statusMap = {
'0': '待签发',
'1': '已签发',
'2': '已校对',
'3': '待接收',
'4': '已接收',
'5': '已检查',
'6': '已出报告',
'7': '已作废',
};
return statusMap[String(status)] || '-';
};
/**
* 获取状态标签类型 - 参考临床医嘱样式
* @param {string|number} status - 状态码
* @returns {string} el-tag type
*/
const getStatusTagType = (status) => {
const typeMap = {
'0': 'primary', // 待签发 - 蓝色
'1': 'success', // 已签发 - 绿色
'2': 'success', // 已校对 - 绿色
'3': 'primary', // 待接收 - 蓝色
'4': 'primary', // 已接收 - 蓝色
'5': 'success', // 已检查 - 绿色
'6': 'success', // 已出报告 - 绿色
'7': 'danger', // 已作废 - 红色
};
return typeMap[String(status)] || 'info';
};
const labelMap = {
categoryType: '项目类别',
targetDepartment: '发往科室',
urgencyLevel: '紧急程度',
allergyHistory: '过敏史',
examinationPurpose: '检查目的',
expectedExaminationTime: '期望检查时间',
medicalHistorySummary: '病史摘要',
allergyConfirmed: '过敏确认',
symptom: '症状',
sign: '体征',
clinicalDiagnosis: '临床诊断',
otherDiagnosis: '其他诊断',
relatedResult: '相关结果',
attention: '注意事项',
};
// Fields that need value transformation before display
const transformField = (key, value) => {
if (key === 'urgencyLevel') {
return value === 'emergency' ? '急诊' : '普通';
}
if (key === 'allergyConfirmed') {
return value === true || value === 'true' ? '已口头确认' : '未确认';
}
return value;
};
const isFieldMatched = (key) => {
return key in labelMap;
};
const getFieldLabel = (key) => {
return labelMap[key] || key;
};
const hasMatchedFields = computed(() => {
if (!descJsonData.value) return false;
return Object.keys(descJsonData.value).some((key) => isFieldMatched(key));
});
/** 查询科室 */
const getLocationInfo = async () => {
try {
const res = await getDepartmentList();
orgOptions.value = Array.isArray(res.data) ? res.data : [];
} catch (e) {
console.warn('科室列表加载失败:', e.message);
orgOptions.value = [];
}
};
// 递归查找树形科室节点
const findTreeItem = (list, id) => {
if (!list || list.length === 0) return null;
for (const item of list) {
if (item.id == id) return item;
if (item.children && item.children.length > 0) {
const found = findTreeItem(item.children, id);
if (found) return found;
}
}
return null;
};
const handleViewDetail = async (row) => {
// 确保科室数据已加载,以便将 ID 解析为名称
if (!orgOptions.value || orgOptions.value.length === 0) {
await getLocationInfo();
}
currentDetail.value = row;
// 解析 descJson
if (row.descJson) {
try {
const obj = JSON.parse(row.descJson);
// 将发往科室 ID 转换为名称
if (obj.targetDepartment) {
const deptItem = findTreeItem(orgOptions.value, obj.targetDepartment);
obj.targetDepartment = deptItem ? deptItem.name : obj.targetDepartment;
}
descJsonData.value = obj;
} catch (e) {
console.error('解析 descJson 失败:', e);
descJsonData.value = null;
}
} else {
descJsonData.value = null;
}
detailDialogVisible.value = true;
};
/**
* 删除申请单 - 仅待签发状态可用
*/
const handleDelete = async (row) => {
try {
await proxy.$modal?.confirm?.('确认删除该检查申请单?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
});
const res = await deleteRequestForm({ requestFormId: row.requestFormId });
if (res.code === 200) {
proxy.$modal?.msgSuccess?.('删除成功');
fetchData();
} else {
proxy.$modal?.msgError?.(res.msg || '删除失败');
}
} catch (e) {
// 用户取消操作,不做处理
}
};
/**
* 撤回申请单 - 仅已签发状态可用
*/
const handleRecall = async (row) => {
try {
await proxy.$modal?.confirm?.('确认撤回该申请单?撤回后状态将变更为"待签发"。', '提示', {
confirmButtonText: '确定撤回',
cancelButtonText: '取消',
type: 'warning',
});
const res = await withdrawRequestForm({ requestFormId: row.requestFormId });
if (res.code === 200) {
proxy.$modal?.msgSuccess?.('撤回成功');
fetchData();
} else {
proxy.$modal?.msgError?.(res.msg || '撤回失败');
}
} catch (e) {
// 用户取消操作,不做处理
}
};
/**
* 打印申请单 - 已校对/待接收/已接收/已检查状态可用
* 打印内容与详情展示一致,并包含申请单条码
*/
const handlePrint = async (row) => {
try {
proxy.$modal?.msgInfo?.('正在生成打印预览...');
// 确保科室数据已加载,用于解析发往科室名称
if (!orgOptions.value || orgOptions.value.length === 0) {
await new Promise((resolve) => {
getDepartmentList().then((res) => {
orgOptions.value = res.data || [];
resolve();
});
});
}
// 解析 descJson
let descData = {};
if (row.descJson) {
try {
const obj = JSON.parse(row.descJson);
// 将发往科室ID转换为名称
if (obj.targetDepartment) {
obj.targetDepartment = recursionFun(obj.targetDepartment);
}
descData = obj;
} catch (e) {
console.error('解析 descJson 失败:', e);
}
}
// 构建诊疗项目表格行
let detailRowsHtml = '';
const detailList = row.requestFormDetailList || [];
if (detailList.length > 0) {
detailList.forEach((item, index) => {
detailRowsHtml += `
<tr>
<td style="text-align:center;padding:6px 8px;border:1px solid #ddd;">${index + 1}</td>
<td style="padding:6px 8px;border:1px solid #ddd;">${item.adviceName || '-'}</td>
<td style="text-align:center;padding:6px 8px;border:1px solid #ddd;">${item.quantity || '-'}</td>
<td style="padding:6px 8px;border:1px solid #ddd;">${item.unitCode_dictText || '-'}</td>
<td style="text-align:right;padding:6px 8px;border:1px solid #ddd;">${item.totalPrice != null ? '¥' + Number(item.totalPrice).toFixed(2) : '-'}</td>
</tr>`;
});
}
// 构建 descJson 字段行(与详情弹窗展示的字段一致)
const fieldKeys = ['targetDepartment', 'symptom', 'sign', 'clinicalDiagnosis', 'otherDiagnosis', 'relatedResult', 'attention'];
let descFieldsHtml = '';
fieldKeys.forEach((key) => {
const label = labelMap[key] || key;
if (descData[key] != null && descData[key] !== '') {
descFieldsHtml += `
<div class="info-row">
<span class="label">${label}</span>
<span class="value">${descData[key]}</span>
</div>`;
}
});
// 构建完整打印HTML
const printContent = `
<div class="print-wrapper">
<!-- 标题 -->
<div class="print-header">
<div class="print-title">检查申请单</div>
<div class="print-meta">打印时间:${new Date().toLocaleString()}</div>
</div>
<!-- 基本信息 -->
<div class="print-section">
<div class="section-title">基本信息</div>
<div class="info-grid">
<div class="info-row"><span class="label">患者姓名:</span><span class="value">${row.patientName || '-'}</span></div>
<div class="info-row"><span class="label">申请单名称:</span><span class="value">${row.name || '-'}</span></div>
<div class="info-row"><span class="label">申请单状态:</span><span class="value">${parseStatus(row.status)}</span></div>
<div class="info-row"><span class="label">创建时间:</span><span class="value">${row.createTime || '-'}</span></div>
<div class="info-row"><span class="label">申请单号:</span><span class="value">${row.prescriptionNo || '-'}</span></div>
<div class="info-row"><span class="label">申请者:</span><span class="value">${row.requesterId_dictText || '-'}</span></div>
<div class="info-row"><span class="label">就诊ID</span><span class="value">${row.encounterId || '-'}</span></div>
<div class="info-row"><span class="label">申请单ID</span><span class="value">${row.requestFormId || '-'}</span></div>
</div>
</div>
${descFieldsHtml ? `
<!-- 申请单描述 -->
<div class="print-section">
<div class="section-title">申请单描述</div>
${descFieldsHtml}
</div>` : ''}
${detailRowsHtml ? `
<!-- 诊疗项目 -->
<div class="print-section">
<div class="section-title">诊疗项目</div>
<table class="detail-table">
<thead>
<tr>
<th style="width:50px;padding:8px;border:1px solid #ddd;background:#f5f7fa;text-align:center;">序号</th>
<th style="padding:8px;border:1px solid #ddd;background:#f5f7fa;text-align:left;">医嘱名称</th>
<th style="width:60px;padding:8px;border:1px solid #ddd;background:#f5f7fa;text-align:center;">数量</th>
<th style="width:60px;padding:8px;border:1px solid #ddd;background:#f5f7fa;text-align:center;">单位</th>
<th style="width:80px;padding:8px;border:1px solid #ddd;background:#f5f7fa;text-align:right;">总价</th>
</tr>
</thead>
<tbody>${detailRowsHtml}</tbody>
</table>
</div>` : ''}
<!-- 条码区 -->
<div class="barcode-section">
<div class="barcode-container">
<div class="barcode-number">${row.prescriptionNo || ''}</div>
<div class="barcode-label">申请单号 / 扫码核验</div>
</div>
</div>
<div class="print-footer">
<div class="footer-line">本申请单仅供院内使用,请勿外传</div>
</div>
</div>
`;
// 打开新窗口打印
const printWindow = window.open('', '_blank');
if (!printWindow) {
proxy.$modal?.msgError?.('无法打开打印窗口,请检查浏览器弹窗设置');
return;
}
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>检查申请单 - 打印</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
font-size: 12px;
color: #333;
padding: 20px;
}
.print-wrapper {
max-width: 210mm;
margin: 0 auto;
}
.print-header {
text-align: center;
padding-bottom: 12px;
margin-bottom: 16px;
border-bottom: 2px solid #333;
}
.print-title {
font-size: 20px;
font-weight: bold;
letter-spacing: 4px;
margin-bottom: 6px;
}
.print-meta {
font-size: 11px;
color: #666;
}
.print-section {
margin-bottom: 16px;
}
.section-title {
font-size: 14px;
font-weight: bold;
margin-bottom: 10px;
padding-bottom: 4px;
border-bottom: 1px solid #ddd;
}
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px 16px;
}
.info-row {
font-size: 12px;
line-height: 1.8;
}
.info-row .label {
font-weight: 600;
color: #555;
}
.info-row .value {
color: #333;
}
.detail-table {
width: 100%;
border-collapse: collapse;
margin-top: 6px;
}
.detail-table th {
font-size: 11px;
font-weight: 600;
color: #555;
}
.detail-table td {
font-size: 12px;
}
.barcode-section {
margin-top: 24px;
padding-top: 16px;
border-top: 1px dashed #ccc;
text-align: center;
}
.barcode-container {
display: inline-block;
padding: 12px 24px;
border: 2px solid #333;
border-radius: 6px;
background: #fff;
}
.barcode-number {
font-family: 'Libre Barcode 128', 'Libre Barcode 39', 'Code128', 'C', monospace;
font-size: 42px;
letter-spacing: 4px;
color: #000;
line-height: 1.2;
}
.barcode-label {
font-size: 10px;
color: #888;
margin-top: 4px;
letter-spacing: 2px;
}
.print-footer {
margin-top: 20px;
text-align: center;
}
.footer-line {
font-size: 10px;
color: #aaa;
}
@media print {
body { padding: 0; }
.print-wrapper { max-width: none; }
.barcode-section { page-break-inside: avoid; }
}
</style>
</head>
<body>
${printContent}
</body>
</html>
`);
printWindow.document.close();
// 等待内容渲染后打印
printWindow.onload = function() {
setTimeout(() => {
printWindow.print();
proxy.$modal?.closeAll?.();
}, 300);
};
} catch (error) {
console.error('打印失败:', error);
proxy.$modal?.msgError?.('打印失败: ' + (error.message || '未知错误'));
}
};
/**
* 查看报告 - 仅已出报告状态可用
* 调用报告查询接口弹窗展示结构化报告或影像预览PACS链接
*/
const handleViewReport = async (row) => {
reportRow.value = row;
reportDialogVisible.value = true;
reportLoading.value = true;
reportData.value = null;
try {
const res = await getTestResult({ prescriptionNo: row.prescriptionNo });
if (res.code === 200) {
if (res.data) {
// 支持两种返回格式:
// 1. res.data 为对象(结构化报告):含 patientName, prescriptionNo, reportTime, diagnosis/content, imageUrl/pacsUrl
// 2. res.data 为字符串报告URL映射到 imageUrl 以支持iframe预览
if (typeof res.data === 'string') {
reportData.value = {
prescriptionNo: row.prescriptionNo,
imageUrl: res.data,
};
} else if (typeof res.data === 'object') {
reportData.value = {
...res.data,
prescriptionNo: res.data.prescriptionNo || row.prescriptionNo,
};
}
} else {
reportData.value = null;
}
} else {
reportData.value = null;
proxy.$modal?.msgWarning?.(res.msg || '暂未生成报告');
}
} catch (e) {
console.error('获取报告失败:', e);
reportData.value = null;
proxy.$modal?.msgError?.('获取报告失败');
} finally {
reportLoading.value = false;
}
};
/**
* 打开PACS影像链接
*/
const openPacsLink = () => {
const url = reportData.value?.pacsUrl || reportData.value?.imageUrl;
if (url) {
window.open(url, '_blank');
}
};
// ========== 修改申请单相关 ==========
const editDialogVisible = ref(false);
const editFormRef = ref(null);
const editingRow = ref(null);
// 修改申请单 - 复用检查申请单弹窗
const handleEdit = (row) => {
editingRow.value = { ...row };
editDialogVisible.value = true;
// 弹窗打开后手动调用getList确保数据加载
nextTick(() => {
editFormRef.value?.getList?.();
editFormRef.value?.getLocationInfo?.();
editFormRef.value?.getDiagnosisList?.();
});
};
// 编辑弹窗确认提交
const handleEditSubmit = () => {
// 调用MedicalExaminations组件的submit方法
if (editFormRef.value?.submit) {
editFormRef.value.submit();
}
};
watch(
() => patientInfo.value?.encounterId,
(val) => {
if (val) {
fetchData();
getLocationInfo();
} else {
tableData.value = [];
filterForm.value.dateRange = getDefaultDateRange();
filterForm.value.status = '';
filterForm.value.keyword = '';
}
},
{ immediate: true }
);
defineExpose({
refresh: fetchData,
});
</script>
<style scoped lang="scss">
.report-container {
display: flex;
flex-direction: column;
gap: 12px;
padding: 8px 0;
height: 100%;
}
.report-section {
background: #fff;
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.report-title {
font-weight: 600;
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 8px;
}
.filter-form {
padding: 12px 8px;
border-bottom: 1px solid #ebeef5;
background-color: #fafafa;
}
.filter-form-content {
:deep(.el-form-item) {
margin-bottom: 0;
margin-right: 16px;
}
:deep(.el-form-item__label) {
font-weight: 500;
}
}
.report-table-wrapper {
flex: 1;
min-height: 0;
overflow: auto;
padding: 0 8px;
}
.empty-data {
padding: 40px 0;
display: flex;
justify-content: center;
align-items: center;
}
.report-refresh-icon {
cursor: pointer;
color: #909399;
transition: color 0.2s;
font-size: 18px;
}
.report-refresh-icon:hover {
color: #409eff;
}
.report-refresh-icon.is-loading {
animation: rotating 2s linear infinite;
}
@keyframes rotating {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
:deep(.el-dialog__body) {
padding-top: 0 !important;
}
.applicationShow-container {
display: flex;
flex-direction: column;
max-height: 70vh;
width: 100%;
overflow-y: auto;
.applicationShow-container-content {
flex-shrink: 0;
margin-bottom: 0px;
}
.applicationShow-container-table {
flex-shrink: 0;
max-height: 3000px;
overflow: auto;
}
}
// 报告弹窗样式
.report-viewer {
min-height: 200px;
padding: 8px 0;
}
.report-viewer-container {
.report-content-section {
margin-top: 16px;
padding: 12px;
background: #fafafa;
border-radius: 6px;
border: 1px solid #eee;
.section-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 10px;
color: #303133;
display: flex;
align-items: center;
}
.report-content-text {
font-size: 13px;
line-height: 1.8;
color: #606266;
white-space: pre-wrap;
}
}
.report-image-section {
margin-top: 16px;
.section-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 10px;
color: #303133;
display: flex;
align-items: center;
}
.report-iframe {
width: 100%;
height: 480px;
border: 1px solid #dcdfe6;
border-radius: 4px;
}
}
}
// 状态标签样式 - 参考临床医嘱
:deep(.el-tag) {
border-radius: 2px;
padding: 0 8px;
height: 24px;
line-height: 22px;
font-size: 12px;
border-width: 1px;
}
:deep(.el-tag--info.is-plain) {
background: #f4f4f5;
border-color: #e9e9eb;
color: #909399;
}
:deep(.el-tag--primary.is-plain) {
background: #ecf5ff;
border-color: #d9ecff;
color: #409eff;
}
:deep(.el-tag--success.is-plain) {
background: #f0f9eb;
border-color: #e1f3d8;
color: #67c23a;
}
:deep(.el-tag--warning.is-plain) {
background: #fdf6ec;
border-color: #faecd8;
color: #e6a23c;
}
:deep(.el-tag--danger.is-plain) {
background: #fef0f0;
border-color: #fde2e2;
color: #f56c6c;
}
</style>