<template>
|
<div class="transport-detail">
|
<el-tabs v-model="activeTab">
|
<!-- 基础信息 -->
|
<el-tab-pane label="基础信息" name="basic">
|
<el-descriptions :column="2" border>
|
<el-descriptions-item label="转运单号">{{
|
transportData.id
|
}}</el-descriptions-item>
|
<el-descriptions-item label="案例编号">{{
|
transportData.caseNo
|
}}</el-descriptions-item>
|
<el-descriptions-item label="捐献者姓名">{{
|
transportData.donorName
|
}}</el-descriptions-item>
|
<el-descriptions-item label="性别">{{
|
transportData.gender
|
}}</el-descriptions-item>
|
<el-descriptions-item label="年龄"
|
>{{ transportData.age }}岁</el-descriptions-item
|
>
|
<el-descriptions-item label="疾病诊断">{{
|
transportData.diagnosis
|
}}</el-descriptions-item>
|
<el-descriptions-item label="出发医院">{{
|
transportData.hospitalName
|
}}</el-descriptions-item>
|
<el-descriptions-item label="目的医院">{{
|
transportData.destinationHospital
|
}}</el-descriptions-item>
|
<el-descriptions-item label="计划转运时间">{{
|
transportData.transportTime
|
}}</el-descriptions-item>
|
<el-descriptions-item label="负责协调员">{{
|
transportData.coordinator
|
}}</el-descriptions-item>
|
<el-descriptions-item label="转运状态">
|
<el-tag :type="transportData.status | statusFilter">
|
{{ transportData.statusText }}
|
</el-tag>
|
</el-descriptions-item>
|
<el-descriptions-item label="创建时间">{{
|
transportData.createTime
|
}}</el-descriptions-item>
|
<el-descriptions-item
|
label="完成时间"
|
v-if="transportData.completedTime"
|
>
|
{{ transportData.completedTime }}
|
</el-descriptions-item>
|
</el-descriptions>
|
</el-tab-pane>
|
|
<!-- 转运详情 -->
|
<el-tab-pane label="转运详情" name="transport">
|
<el-descriptions :column="1" border>
|
<el-descriptions-item label="出发地点">{{
|
transportData.departureLocation
|
}}</el-descriptions-item>
|
<el-descriptions-item label="目的地">{{
|
transportData.destinationHospital
|
}}</el-descriptions-item>
|
<el-descriptions-item
|
label="当前位置"
|
v-if="transportData.currentLocation"
|
>
|
{{ transportData.currentLocation }}
|
</el-descriptions-item>
|
<el-descriptions-item
|
label="预计到达时间"
|
v-if="transportData.estimatedTime"
|
>
|
{{ transportData.estimatedTime }}
|
</el-descriptions-item>
|
<el-descriptions-item label="转运距离" v-if="transportData.distance">
|
{{ transportData.distance }}
|
</el-descriptions-item>
|
<el-descriptions-item label="转运时长" v-if="transportData.duration">
|
{{ transportData.duration }}
|
</el-descriptions-item>
|
</el-descriptions>
|
</el-tab-pane>
|
|
<!-- 团队成员 -->
|
<el-tab-pane label="团队成员" name="team">
|
<el-descriptions :column="2" border>
|
<el-descriptions-item label="协调员">{{
|
transportData.coordinator
|
}}</el-descriptions-item>
|
<el-descriptions-item label="协调员电话">
|
{{ getContactPhone("协调员电话") }}
|
</el-descriptions-item>
|
<el-descriptions-item
|
label="急诊科医生"
|
v-if="transportData.emergencyDoctor"
|
>
|
{{ transportData.emergencyDoctor }}
|
</el-descriptions-item>
|
<el-descriptions-item label="急诊医生电话">
|
{{ getContactPhone("急诊医生电话") }}
|
</el-descriptions-item>
|
<el-descriptions-item label="护士" v-if="transportData.nurse">
|
{{ transportData.nurse }}
|
</el-descriptions-item>
|
<el-descriptions-item label="护士电话">
|
{{ getContactPhone("护士电话") }}
|
</el-descriptions-item>
|
<el-descriptions-item label="司机" v-if="transportData.driver">
|
{{ transportData.driver }}
|
</el-descriptions-item>
|
<el-descriptions-item label="司机电话">
|
{{ getContactPhone("司机电话") }}
|
</el-descriptions-item>
|
<el-descriptions-item
|
label="ICU评估医生"
|
v-if="transportData.icuDoctor"
|
>
|
{{ transportData.icuDoctor }}
|
</el-descriptions-item>
|
<el-descriptions-item label="ICU医生电话">
|
{{ getContactPhone("ICU医生电话") }}
|
</el-descriptions-item>
|
</el-descriptions>
|
</el-tab-pane>
|
<el-tab-pane label="附件信息" name="attachments">
|
<el-card class="attachment-card">
|
<div slot="header" class="clearfix">
|
<span>附件列表</span>
|
<!-- <el-button
|
style="float: right; padding: 3px 0"
|
type="text"
|
@click="handleUpload"
|
>
|
上传附件
|
</el-button> -->
|
</div>
|
|
<el-table :data="attachmentList" style="width: 100%">
|
<el-table-column label="文件名" width="300">
|
<template slot-scope="scope">
|
<i class="el-icon-document" style="margin-right: 8px;"></i>
|
<span>{{ scope.row.fileName }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="文件类型" width="120">
|
<template slot-scope="scope">
|
<el-tag size="small">{{ scope.row.fileType }}</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="大小" width="100">
|
<template slot-scope="scope">
|
<span>{{ formatFileSize(scope.row.fileSize) }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="上传时间" width="180">
|
<template slot-scope="scope">
|
<span>{{ scope.row.uploadTime }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作">
|
<template slot-scope="scope">
|
<el-button size="mini" @click="handlePreview(scope.row)"
|
>预览</el-button
|
>
|
<el-button
|
size="mini"
|
type="success"
|
@click="handleDownload(scope.row)"
|
>下载</el-button
|
>
|
<el-button
|
size="mini"
|
type="danger"
|
@click="handleDelete(scope.row)"
|
>删除</el-button
|
>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-card>
|
</el-tab-pane>
|
<!-- 备注信息 -->
|
<el-tab-pane label="备注信息" name="remarks" v-if="transportData.remarks">
|
<el-card>
|
<div class="remarks-content">
|
{{ transportData.remarks }}
|
</div>
|
</el-card>
|
</el-tab-pane>
|
</el-tabs>
|
<!-- PDF预览弹窗 -->
|
<el-dialog
|
:title="previewTitle"
|
:append-to-body="true"
|
:visible.sync="pdfPreviewVisible"
|
width="90%"
|
top="5vh"
|
:close-on-click-modal="true"
|
class="pdf-preview-dialog"
|
@close="handlePdfDialogClose"
|
>
|
<div class="pdf-preview-container" v-loading="pdfLoading">
|
<!-- PDF控制工具栏 -->
|
<div class="pdf-toolbar">
|
<el-button-group>
|
<el-button
|
size="mini"
|
@click="changePage(currentPage - 1)"
|
:disabled="currentPage <= 1"
|
icon="el-icon-arrow-left"
|
>
|
上一页
|
</el-button>
|
<el-button size="mini" disabled>
|
第 {{ currentPage }} 页 / 共 {{ pageCount }} 页
|
</el-button>
|
<el-button
|
size="mini"
|
@click="changePage(currentPage + 1)"
|
:disabled="currentPage >= pageCount"
|
icon="el-icon-arrow-right"
|
>
|
下一页
|
</el-button>
|
</el-button-group>
|
|
<el-button-group class="zoom-controls">
|
<el-button size="mini" @click="zoomOut" :disabled="scale <= 50">
|
<i class="el-icon-zoom-out"></i> 缩小
|
</el-button>
|
<el-button size="mini" disabled> {{ scale }}% </el-button>
|
<el-button size="mini" @click="zoomIn" :disabled="scale >= 200">
|
<i class="el-icon-zoom-in"></i> 放大
|
</el-button>
|
<el-button size="mini" @click="resetZoom">
|
<i class="el-icon-refresh-left"></i> 重置
|
</el-button>
|
</el-button-group>
|
|
<el-button
|
size="mini"
|
type="success"
|
@click="downloadPdf(currentFile)"
|
icon="el-icon-download"
|
>
|
下载
|
</el-button>
|
</div>
|
|
<!-- PDF渲染区域 -->
|
<div class="pdf-viewport">
|
<pdf
|
ref="pdf"
|
:src="pdfUrl"
|
:page="currentPage"
|
:rotate="pageRotate"
|
@num-pages="pageCount = $event"
|
@page-loaded="currentPage = $event"
|
@loaded="loadPdfHandler"
|
@error="pdfErrorHandler"
|
:style="{
|
width: scale + '%',
|
transform: 'scale(' + scale / 100 + ')',
|
transformOrigin: '0 0'
|
}"
|
></pdf>
|
</div>
|
</div>
|
</el-dialog>
|
|
<!-- 图片预览弹窗(使用Element UI自带预览) -->
|
<el-dialog
|
:append-to-body="true"
|
:title="previewTitle"
|
:visible.sync="imagePreviewVisible"
|
width="60%"
|
top="10vh"
|
:close-on-click-modal="true"
|
>
|
<div class="image-preview-container">
|
<img :src="previewUrl" alt="预览图片" class="preview-image" />
|
</div>
|
</el-dialog>
|
|
<!-- 不支持预览的文件类型 -->
|
<el-dialog
|
:title="previewTitle"
|
:visible.sync="unsupportedPreviewVisible"
|
width="400px"
|
:close-on-click-modal="true"
|
>
|
<div class="unsupported-preview">
|
<el-alert
|
title="该文件格式不支持在线预览,请下载后查看"
|
type="warning"
|
show-icon
|
:closable="false"
|
/>
|
<div style="text-align: center; margin-top: 20px;">
|
<el-button type="primary" @click="handleDownload(currentFile)">
|
<i class="el-icon-download"></i> 下载文件
|
</el-button>
|
</div>
|
</div>
|
</el-dialog>
|
<div class="detail-footer">
|
<el-button @click="handleClose">关闭</el-button>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import pdf from "vue-pdf";
|
|
export default {
|
name: "TransportDetail",
|
components: {
|
pdf
|
},
|
props: {
|
transportData: {
|
type: Object,
|
default: () => ({})
|
}
|
},
|
filters: {
|
statusFilter(status) {
|
const statusMap = {
|
pending: "warning",
|
transporting: "primary",
|
completed: "success",
|
cancelled: "danger"
|
};
|
return statusMap[status];
|
}
|
},
|
data() {
|
return {
|
activeTab: "basic",
|
// 附件相关数据
|
attachmentList: [
|
{
|
id: 1,
|
fileName: "转运交接单.jpg",
|
fileType: "docx",
|
fileSize: 102400,
|
uploadTime: "2024-12-19 10:30:00",
|
fileUrl: "https://img95.699pic.com/photo/40142/8262.jpg_wh860.jpg"
|
},
|
{
|
id: 2,
|
fileName: "医疗记录.pdf",
|
fileType: "pdf",
|
fileSize: 2048000,
|
uploadTime: "2024-12-19 11:20:00",
|
fileUrl:
|
"http://192.168.100.10:8080/profile/upload/2025/12/19/(吴龙8.7)每日工作总结1766131266142.pdf"
|
},
|
{
|
id: 3,
|
fileName: "患者照片.jpg",
|
fileType: "jpg",
|
fileSize: 512000,
|
uploadTime: "2024-12-19 14:15:00",
|
fileUrl: "https://img95.699pic.com/photo/40019/3490.jpg_wh860.jpg"
|
}
|
],
|
// PDF预览相关数据
|
pdfPreviewVisible: false,
|
pdfLoading: false,
|
pdfUrl: "",
|
currentPage: 1,
|
pageCount: 0,
|
scale: 100,
|
pageRotate: 0,
|
|
// 图片预览相关
|
imagePreviewVisible: false,
|
|
// 不支持预览相关
|
unsupportedPreviewVisible: false,
|
|
// 通用预览数据
|
previewTitle: "",
|
previewUrl: "",
|
currentFile: null
|
};
|
},
|
methods: {
|
// 获取联系方式
|
getContactPhone(role) {
|
if (this.transportData.contacts) {
|
const contact = this.transportData.contacts.find(
|
item => item.role === role
|
);
|
return contact ? contact.phone : "未填写";
|
}
|
return "未填写";
|
},
|
// 关闭弹框
|
handleClose() {
|
this.$emit("close");
|
},
|
// 获取文件类型
|
getFileType(fileName) {
|
const extension = fileName
|
.split(".")
|
.pop()
|
.toLowerCase();
|
const imageTypes = ["jpg", "jpeg", "png", "gif", "bmp", "webp"];
|
const pdfTypes = ["pdf"];
|
|
if (imageTypes.includes(extension)) return "image";
|
if (pdfTypes.includes(extension)) return "pdf";
|
return "other";
|
},
|
|
// 文件预览主入口
|
handlePreview(file) {
|
this.currentFile = file;
|
this.previewTitle = `预览 - ${file.fileName}`;
|
this.previewUrl = file.fileUrl;
|
const fileType = this.getFileType(file.fileName);
|
|
switch (fileType) {
|
case "pdf":
|
this.previewPdf(file);
|
break;
|
case "image":
|
this.previewImage(file);
|
break;
|
default:
|
this.previewUnsupported(file);
|
break;
|
}
|
},
|
|
// PDF预览方法 [1,2](@ref)
|
previewPdf(file) {
|
this.pdfPreviewVisible = true;
|
this.pdfLoading = true;
|
this.currentPage = 1;
|
this.scale = 100;
|
this.pageRotate = 0;
|
// 设置PDF源 [4](@ref)
|
this.pdfUrl = file.fileUrl;
|
},
|
|
// PDF加载完成回调 [1,2](@ref)
|
loadPdfHandler() {
|
this.pdfLoading = false;
|
this.currentPage = 1;
|
},
|
|
// PDF加载错误处理 [4](@ref)
|
pdfErrorHandler(error) {
|
console.error("PDF加载失败:", error);
|
this.pdfLoading = false;
|
this.$message.error("PDF文件加载失败,请尝试下载后查看");
|
this.pdfPreviewVisible = false;
|
},
|
|
// 翻页功能 [2](@ref)
|
changePage(newPage) {
|
if (newPage < 1 || newPage > this.pageCount) return;
|
|
this.currentPage = newPage;
|
},
|
|
// 缩放功能 [2,3](@ref)
|
zoomIn() {
|
if (this.scale >= 200) {
|
this.$message.info("已放大到最大比例");
|
return;
|
}
|
this.scale += 10;
|
},
|
|
zoomOut() {
|
if (this.scale <= 50) {
|
this.$message.info("已缩小到最小比例");
|
return;
|
}
|
this.scale -= 10;
|
},
|
|
resetZoom() {
|
this.scale = 100;
|
},
|
|
// 图片预览方法
|
previewImage(file) {
|
this.imagePreviewVisible = true;
|
},
|
|
// 不支持预览的文件类型
|
previewUnsupported(file) {
|
this.unsupportedPreviewVisible = true;
|
},
|
|
// PDF对话框关闭处理
|
handlePdfDialogClose() {
|
this.pdfUrl = "";
|
this.currentPage = 1;
|
this.pageCount = 0;
|
},
|
|
// 文件下载
|
handleDownload(file) {
|
const link = document.createElement("a");
|
link.href = file.fileUrl;
|
link.download = file.fileName;
|
link.style.display = "none";
|
document.body.appendChild(link);
|
link.click();
|
document.body.removeChild(link);
|
|
this.$message.success("开始下载文件");
|
},
|
|
// 专用PDF下载方法
|
downloadPdf(file) {
|
this.handleDownload(file);
|
},
|
|
// 文件删除
|
handleDelete(file) {
|
this.$confirm("确定要删除这个附件吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning"
|
}).then(() => {
|
this.attachmentList = this.attachmentList.filter(
|
item => item.id !== file.id
|
);
|
this.$message.success("删除成功");
|
});
|
},
|
// 上传附件
|
handleUpload() {
|
this.$message.info("上传功能待实现");
|
},
|
|
// 原有方法保持不变
|
getContactPhone(role) {
|
if (this.transportData.contacts) {
|
const contact = this.transportData.contacts.find(
|
item => item.role === role
|
);
|
return contact ? contact.phone : "未填写";
|
}
|
return "未填写";
|
},
|
|
handleClose() {
|
this.$emit("close");
|
},
|
|
formatFileSize(bytes) {
|
if (bytes === 0) return "0 B";
|
const k = 1024;
|
const sizes = ["B", "KB", "MB", "GB"];
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.transport-detail {
|
padding: 0 20px;
|
}
|
|
/* PDF预览对话框样式 */
|
.pdf-preview-dialog {
|
margin-top: 5vh !important;
|
}
|
|
.pdf-preview-dialog >>> .el-dialog {
|
min-height: 80vh;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.pdf-preview-dialog >>> .el-dialog__body {
|
flex: 1;
|
padding: 0;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.pdf-preview-container {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
}
|
|
/* PDF工具栏样式 */
|
.pdf-toolbar {
|
padding: 15px 20px;
|
background: #f5f7fa;
|
border-bottom: 1px solid #ebeef5;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 10px;
|
}
|
|
.zoom-controls {
|
margin: 0 15px;
|
}
|
|
/* PDF视图区域样式 */
|
.pdf-viewport {
|
flex: 1;
|
overflow: auto;
|
padding: 20px;
|
background: #f8f9fa;
|
display: flex;
|
justify-content: center;
|
align-items: flex-start;
|
}
|
|
/* 图片预览样式 */
|
.image-preview-container {
|
text-align: center;
|
padding: 20px;
|
}
|
|
.preview-image {
|
max-width: 100%;
|
max-height: 70vh;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
}
|
|
/* 响应式设计 */
|
@media (max-width: 768px) {
|
.pdf-toolbar {
|
flex-direction: column;
|
gap: 10px;
|
}
|
|
.zoom-controls {
|
margin: 10px 0;
|
}
|
|
.pdf-preview-dialog {
|
width: 95% !important;
|
}
|
}
|
|
.detail-footer {
|
text-align: center;
|
margin-top: 20px;
|
padding-top: 20px;
|
border-top: 1px solid #ebeef5;
|
}
|
|
.remarks-content {
|
padding: 15px;
|
line-height: 1.6;
|
color: #606266;
|
}
|
|
::v-deep .el-descriptions__label {
|
width: 120px;
|
background-color: #f5f7fa;
|
font-weight: bold;
|
}
|
</style>
|