| | |
| | | caseData.name || "-" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="性别"> |
| | | <dict-tag |
| | | :options="dict.type.sys_user_sex" |
| | | :value="caseData.sex ? parseInt(caseData.sex) : ''" |
| | | /> |
| | | <dict-tag :options="dict.type.sys_user_sex" :value="caseData.sex" /> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="年龄"> |
| | | {{ caseData.age || "-" |
| | |
| | | <el-descriptions-item label="部门名称">{{ |
| | | caseData.deptName || "-" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="部门编号">{{ |
| | | caseData.deptNo || "-" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="上报医院">{{ |
| | | caseData.toHospital || "-" |
| | | }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-card> |
| | | |
| | |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="报告时间">{{ |
| | | formatDateTime(caseData.reporttime) |
| | | formatDateTime(caseData.createTime) |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="是否终止案例"> |
| | | {{ caseData.terminationCase === "1" ? "已终止" : "进行中" }} |
| | |
| | | </el-card> |
| | | |
| | | <!-- 附件信息模块 --> |
| | | <el-card class="detail-section" v-if="attachmentList.length > 0"> |
| | | <el-card |
| | | class="detail-section" |
| | | v-if="caseData.annexfilesList && caseData.annexfilesList.length > 0" |
| | | > |
| | | <div slot="header" class="section-header"> |
| | | <span class="section-title">附件信息</span> |
| | | </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 |
| | | <div class="detail-attachments"> |
| | | <div class="attachment-grid"> |
| | | <div |
| | | v-for="file in caseData.annexfilesList" |
| | | :key="file.id || file.fileName" |
| | | class="attachment-card" |
| | | > |
| | | <template v-if="isImageFile(file.fileName || file.path)"> |
| | | <!-- 图片使用 el-image 预览 --> |
| | | <el-image |
| | | class="image-attachment" |
| | | :src="getFileUrl(file)" |
| | | :preview-src-list="getImagePreviewList(file)" |
| | | fit="cover" |
| | | :style="{ width: '120px', height: '120px' }" |
| | | lazy |
| | | > |
| | | <div slot="error" class="image-error"> |
| | | <i class="el-icon-picture-outline"></i> |
| | | <span>加载失败</span> |
| | | </div> |
| | | <div slot="placeholder" class="image-loading"> |
| | | <i class="el-icon-loading"></i> |
| | | </div> |
| | | </el-image> |
| | | <div class="image-info"> |
| | | <div class="file-name" :title="file.fileName"> |
| | | {{ file.fileName }} |
| | | </div> |
| | | <div class="file-actions"> |
| | | <el-button |
| | | type="text" |
| | | size="mini" |
| | | type="success" |
| | | @click="handleDownload(scope.row)" |
| | | >下载</el-button |
| | | > |
| | | @click="handleDownload(file)" |
| | | icon="el-icon-download" |
| | | title="下载" |
| | | /> |
| | | <el-button |
| | | type="text" |
| | | size="mini" |
| | | @click="handlePreview(file)" |
| | | icon="el-icon-view" |
| | | title="预览" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <template v-else> |
| | | <!-- 非图片文件使用卡片样式 --> |
| | | <el-card shadow="hover" class="file-card"> |
| | | <div class="file-content"> |
| | | <i :class="getFileIcon(file.fileName)" class="file-icon"></i> |
| | | <div class="file-info"> |
| | | <div class="file-name" :title="file.fileName"> |
| | | {{ file.fileName }} |
| | | </div> |
| | | <div class="file-meta"> |
| | | <span class="file-type">{{ |
| | | getFileTypeText(file.fileName) |
| | | }}</span> |
| | | <span v-if="file.createTime" class="file-time"> |
| | | {{ formatDateTime(file.createTime) }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="file-actions"> |
| | | <el-button |
| | | type="text" |
| | | size="mini" |
| | | @click="handleDownload(file)" |
| | | > |
| | | 下载 |
| | | </el-button> |
| | | <el-button |
| | | v-if="canPreview(file.fileName)" |
| | | type="text" |
| | | size="mini" |
| | | @click="handlePreview(file)" |
| | | > |
| | | 预览 |
| | | </el-button> |
| | | </div> |
| | | </el-card> |
| | | </template> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 备注信息 --> |
| | | <el-card class="detail-section" v-if="caseData.remark"> |
| | | <div slot="header" class="section-header"> |
| | | <span class="section-title">备注信息</span> |
| | | </div> |
| | | <div class="remark-content"> |
| | | {{ caseData.remark }} |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 审批信息模块(状态为已同意或已驳回时显示) --> |
| | |
| | | {{ caseData.reportStatus === "3" ? "已同意" : "已驳回" }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="审批时间">{{ |
| | | formatDateTime(caseData.updateTime) |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="审批人">{{ |
| | | caseData.updateBy || "-" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="审批时间">{{ |
| | | formatDateTime(caseData.updateTime) |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="审批意见">{{ |
| | | caseData.remark || "无" |
| | | }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-card> |
| | | |
| | | <!-- 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" |
| | | <el-card |
| | | class="detail-section" |
| | | v-if=" |
| | | caseData.isTransport == '2' && |
| | | caseData.serviceTransport && |
| | | caseData.serviceTransport.length > 0 |
| | | " |
| | | > |
| | | <div class="pdf-preview-container" v-loading="pdfLoading"> |
| | | <!-- PDF控制工具栏 --> |
| | | <div class="pdf-toolbar"> |
| | | <el-button-group> |
| | | <div slot="header" class="section-header"> |
| | | <span class="section-title">转运信息</span> |
| | | <el-button |
| | | size="mini" |
| | | @click="changePage(currentPage - 1)" |
| | | :disabled="currentPage <= 1" |
| | | icon="el-icon-arrow-left" |
| | | v-if="caseData.reportStatus === '3'" |
| | | type="primary" |
| | | size="small" |
| | | icon="el-icon-truck" |
| | | @click="handleViewTransport" |
| | | > |
| | | 上一页 |
| | | 查看转运详情 |
| | | </el-button> |
| | | <el-button size="mini" disabled> |
| | | 第 {{ currentPage }} 页 / 共 {{ pageCount }} 页 |
| | | </el-button> |
| | | </div> |
| | | |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item |
| | | v-for="transport in caseData.serviceTransport" |
| | | :key="transport.id" |
| | | > |
| | | <!-- 转运单列表 --> |
| | | <div class="transport-info"> |
| | | <div class="transport-item"> |
| | | <strong>转运单号:</strong> {{ transport.reportId || "-" }} |
| | | </div> |
| | | <div class="transport-item"> |
| | | <strong>患者姓名:</strong> {{ transport.patName || "-" }} |
| | | </div> |
| | | <div class="transport-item"> |
| | | <strong>出发地点:</strong> |
| | | {{ transport.transportStartPlace || "-" }} |
| | | </div> |
| | | <div class="transport-item"> |
| | | <strong>出发时间:</strong> |
| | | {{ formatDateTime(transport.transportStartTime) }} |
| | | </div> |
| | | <div class="transport-item"> |
| | | <strong>转运状态:</strong> |
| | | <el-tag :type="getTransportStatusTag(transport)" size="small"> |
| | | {{ getTransportStatusText(transport) }} |
| | | </el-tag> |
| | | </div> |
| | | <div class="transport-item"> |
| | | <strong>负责协调员:</strong> {{ transport.contactPerson || "-" }} |
| | | </div> |
| | | <div class="transport-item" v-if="transport.remark"> |
| | | <strong>备注:</strong> {{ transport.remark }} |
| | | </div> |
| | | </div> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-card> |
| | | |
| | | <!-- 无转运信息但需要转运的提示 --> |
| | | <el-card |
| | | class="detail-section" |
| | | v-else-if="caseData.isTransport === '2' && caseData.reportStatus === '3'" |
| | | > |
| | | <div slot="header" class="section-header"> |
| | | <span class="section-title">转运信息</span> |
| | | <el-button |
| | | size="mini" |
| | | @click="changePage(currentPage + 1)" |
| | | :disabled="currentPage >= pageCount" |
| | | icon="el-icon-arrow-right" |
| | | type="primary" |
| | | size="small" |
| | | icon="el-icon-truck" |
| | | @click="handleCreateTransport" |
| | | > |
| | | 下一页 |
| | | </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> |
| | | |
| | | <!-- 图片预览弹窗 --> |
| | | <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="该文件格式不支持在线预览,请下载后查看" |
| | | title="该案例需要转运,但尚未创建转运单" |
| | | type="warning" |
| | | description="请点击上方按钮创建转运单" |
| | | 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> |
| | | </el-card> |
| | | <!-- 文件预览弹窗 --> |
| | | <FilePreviewDialog |
| | | :visible="previewVisible" |
| | | :file="currentPreviewFile" |
| | | @close="previewVisible = false" |
| | | @download="handleDownload" |
| | | /> |
| | | |
| | | <div class="detail-footer" v-if="showtitle"> |
| | | <el-button @click="handleClose">关闭</el-button> |
| | |
| | | |
| | | <script> |
| | | import pdf from "vue-pdf"; |
| | | import FilePreviewDialog from "@/components/FilePreviewDialog"; |
| | | |
| | | export default { |
| | | name: "CaseDetail", |
| | | components: { |
| | | pdf |
| | | pdf, |
| | | FilePreviewDialog |
| | | }, |
| | | props: { |
| | | caseData: { |
| | |
| | | } |
| | | }, |
| | | dicts: ["sys_user_sex", "sys_BloodType"], |
| | | filters: { |
| | | statusFilter(status) { |
| | | const statusMap = { |
| | | "0": "warning", |
| | | "1": "success", |
| | | "2": "danger" |
| | | }; |
| | | return statusMap[status]; |
| | | }, |
| | | statusTextFilter(status) { |
| | | const statusMap = { |
| | | "0": "待审批", |
| | | "1": "已通过", |
| | | "2": "已驳回" |
| | | }; |
| | | return statusMap[status]; |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | // 预览相关数据(保持原有代码) |
| | | pdfPreviewVisible: false, |
| | | imagePreviewVisible: false, |
| | | unsupportedPreviewVisible: false, |
| | | pdfLoading: false, |
| | | pdfUrl: "", |
| | | currentPage: 1, |
| | | pageCount: 0, |
| | | scale: 100, |
| | | pageRotate: 0, |
| | | previewTitle: "", |
| | | previewUrl: "", |
| | | currentFile: null, |
| | | // 预览相关 |
| | | previewVisible: false, |
| | | currentPreviewFile: null, |
| | | |
| | | // 附件列表 |
| | | attachmentList: [] |
| | | // 图片预览相关 |
| | | imagePreviewUrls: [] |
| | | }; |
| | | }, |
| | | watch: { |
| | | caseData: { |
| | | immediate: true, |
| | | handler(newVal) { |
| | | if (newVal && newVal.annexfilesList) { |
| | | this.loadAttachments(newVal.annexfilesList); |
| | | computed: { |
| | | // 收集所有图片URL用于预览 |
| | | allImageUrls() { |
| | | if ( |
| | | !this.caseData.annexfilesList || |
| | | !Array.isArray(this.caseData.annexfilesList) |
| | | ) { |
| | | return []; |
| | | } |
| | | } |
| | | return this.caseData.annexfilesList |
| | | .filter(file => this.isImageFile(file.fileName || file.path)) |
| | | .map(file => this.getFileUrl(file)) |
| | | .filter(url => url); |
| | | } |
| | | }, |
| | | methods: { |
| | |
| | | this.$emit("close"); |
| | | }, |
| | | |
| | | // 加载附件 |
| | | loadAttachments(annexfilesList) { |
| | | if (!annexfilesList || !Array.isArray(annexfilesList)) { |
| | | this.attachmentList = []; |
| | | return; |
| | | } |
| | | |
| | | this.attachmentList = annexfilesList.map((file, index) => ({ |
| | | id: index + 1, |
| | | fileName: file.fileName || `附件${index + 1}`, |
| | | fileType: this.getFileExtension(file.fileUrl || ""), |
| | | fileSize: file.fileSize || 0, |
| | | uploadTime: file.uploadTime || this.formatDateTime(new Date()), |
| | | fileUrl: file.fileUrl || "" |
| | | })); |
| | | }, |
| | | |
| | | // 获取文件扩展名 |
| | | getFileExtension(filename) { |
| | | return ( |
| | | filename |
| | | .split(".") |
| | | .pop() |
| | | ?.toLowerCase() || "unknown" |
| | | ); |
| | | }, |
| | | |
| | | // 格式化日期时间 |
| | | formatDateTime(dateString) { |
| | | if (!dateString) return "-"; |
| | | return dateString.replace("T", " ").substring(0, 19); |
| | | formatDateTime(dateTime) { |
| | | if (!dateTime) return "-"; |
| | | return dateTime.replace("T", " ").substring(0, 19); |
| | | }, |
| | | |
| | | // 格式化日期 |
| | |
| | | if (!dateString) return "-"; |
| | | return dateString.split("T")[0]; |
| | | }, |
| | | getTransportStatusTag(transport) { |
| | | if (!transport.transitStatus) return "info"; |
| | | switch (transport.transitStatus.toString()) { |
| | | case "1": |
| | | return "warning"; // 待转运 |
| | | case "2": |
| | | return "primary"; // 转运中 |
| | | case "3": |
| | | return "success"; // 转运完成 |
| | | case "4": |
| | | return "danger"; // 转运取消 |
| | | case "5": |
| | | return "info"; // 暂存 |
| | | default: |
| | | return "info"; |
| | | } |
| | | }, |
| | | |
| | | /** 获取转运状态文本 */ |
| | | getTransportStatusText(transport) { |
| | | if (!transport.transitStatus) return "未知"; |
| | | switch (transport.transitStatus.toString()) { |
| | | case "1": |
| | | return "待转运"; |
| | | case "2": |
| | | return "转运中"; |
| | | case "3": |
| | | return "转运完成"; |
| | | case "4": |
| | | return "转运取消"; |
| | | case "5": |
| | | return "暂存"; |
| | | default: |
| | | return "未知"; |
| | | } |
| | | }, |
| | | |
| | | /** 查看转运详情 */ |
| | | handleViewTransport() { |
| | | if ( |
| | | this.caseData.serviceTransport && |
| | | this.caseData.serviceTransport.length > 0 |
| | | ) { |
| | | const transport = this.caseData.serviceTransport[0]; |
| | | this.$router.push({ |
| | | path: "/business/transport/detail", |
| | | query: { |
| | | id: transport.id, |
| | | caseNo: this.caseData.caseNo |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | /** 创建转运单 */ |
| | | handleCreateTransport() { |
| | | this.$router.push({ |
| | | path: "/business/transport/create", |
| | | query: { |
| | | caseId: this.caseData.id, |
| | | caseNo: this.caseData.caseNo, |
| | | patName: this.caseData.name, |
| | | age: this.caseData.age, |
| | | sex: this.caseData.sex, |
| | | diagnosisname: this.caseData.diagnosisname, |
| | | treatmentHospitalName: this.caseData.treatmenthospitalname |
| | | } |
| | | }); |
| | | }, |
| | | // 获取完整户籍地址 |
| | | getFullRegisterAddress() { |
| | | const { |
| | |
| | | return typeMap[type] || type || "-"; |
| | | }, |
| | | |
| | | // 文件预览相关方法(保持原有代码) |
| | | // 文件处理相关方法 |
| | | isImageFile(fileName) { |
| | | if (!fileName) return false; |
| | | const imageExtensions = [ |
| | | "jpg", |
| | | "jpeg", |
| | | "png", |
| | | "gif", |
| | | "bmp", |
| | | "webp", |
| | | "svg" |
| | | ]; |
| | | const extension = fileName |
| | | .split(".") |
| | | .pop() |
| | | .toLowerCase(); |
| | | return imageExtensions.includes(extension); |
| | | }, |
| | | |
| | | getFileUrl(file) { |
| | | return file.path || file.fileUrl || ""; |
| | | }, |
| | | |
| | | getImagePreviewList(file) { |
| | | // 返回所有图片的URL列表,实现点击任意图片查看所有图片 |
| | | return this.allImageUrls; |
| | | }, |
| | | |
| | | getFileIcon(fileName) { |
| | | if (!fileName) return "el-icon-document"; |
| | | const ext = fileName |
| | | .split(".") |
| | | .pop() |
| | | .toLowerCase(); |
| | | const iconMap = { |
| | | pdf: "el-icon-document", |
| | | doc: "el-icon-document", |
| | | docx: "el-icon-document", |
| | | xls: "el-icon-document", |
| | | xlsx: "el-icon-document", |
| | | jpg: "el-icon-picture", |
| | | jpeg: "el-icon-picture", |
| | | png: "el-icon-picture", |
| | | gif: "el-icon-picture" |
| | | }; |
| | | return iconMap[ext] || "el-icon-document"; |
| | | }, |
| | | |
| | | getFileTypeText(fileName) { |
| | | if (!fileName) return "文件"; |
| | | const ext = fileName |
| | | .split(".") |
| | | .pop() |
| | | .toLowerCase(); |
| | | const typeMap = { |
| | | pdf: "PDF文档", |
| | | doc: "Word文档", |
| | | docx: "Word文档", |
| | | xls: "Excel表格", |
| | | xlsx: "Excel表格", |
| | | jpg: "图片", |
| | | jpeg: "图片", |
| | | png: "图片", |
| | | gif: "图片" |
| | | }; |
| | | return typeMap[ext] || "文件"; |
| | | }, |
| | | |
| | | canPreview(fileName) { |
| | | if (!fileName) return false; |
| | | const previewableExtensions = ["pdf", "jpg", "jpeg", "png", "gif"]; |
| | | const extension = fileName |
| | | .split(".") |
| | | .pop() |
| | | .toLowerCase(); |
| | | return previewableExtensions.includes(extension); |
| | | }, |
| | | |
| | | // 文件预览 |
| | | handlePreview(file) { |
| | | this.currentPreviewFile = { |
| | | fileName: file.fileName, |
| | | fileUrl: this.getFileUrl(file), |
| | | fileType: this.getFileType(file.fileName) |
| | | }; |
| | | this.previewVisible = true; |
| | | }, |
| | | |
| | | getFileType(fileName) { |
| | | if (!fileName) return "other"; |
| | | const extension = fileName |
| | | .split(".") |
| | | .pop() |
| | | .toLowerCase(); |
| | | const imageTypes = ["jpg", "jpeg", "png", "gif", "bmp", "webp"]; |
| | | const pdfTypes = ["pdf"]; |
| | | const officeTypes = ["doc", "docx", "xls", "xlsx"]; |
| | | |
| | | if (imageTypes.includes(extension)) return "image"; |
| | | if (pdfTypes.includes(extension)) return "pdf"; |
| | | if (officeTypes.includes(extension)) return "office"; |
| | | 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; |
| | | } |
| | | }, |
| | | |
| | | previewPdf(file) { |
| | | this.pdfPreviewVisible = true; |
| | | this.pdfLoading = true; |
| | | this.currentPage = 1; |
| | | this.scale = 100; |
| | | this.pageRotate = 0; |
| | | this.pdfUrl = file.fileUrl; |
| | | }, |
| | | |
| | | loadPdfHandler() { |
| | | this.pdfLoading = false; |
| | | this.currentPage = 1; |
| | | }, |
| | | |
| | | pdfErrorHandler(error) { |
| | | console.error("PDF加载失败:", error); |
| | | this.pdfLoading = false; |
| | | this.$message.error("PDF文件加载失败,请尝试下载后查看"); |
| | | this.pdfPreviewVisible = false; |
| | | }, |
| | | |
| | | changePage(newPage) { |
| | | if (newPage < 1 || newPage > this.pageCount) return; |
| | | this.currentPage = newPage; |
| | | }, |
| | | |
| | | zoomIn() { |
| | | if (this.scale >= 200) return; |
| | | this.scale += 10; |
| | | }, |
| | | |
| | | zoomOut() { |
| | | if (this.scale <= 50) return; |
| | | this.scale -= 10; |
| | | }, |
| | | |
| | | resetZoom() { |
| | | this.scale = 100; |
| | | }, |
| | | |
| | | previewImage(file) { |
| | | this.imagePreviewVisible = true; |
| | | }, |
| | | |
| | | previewUnsupported(file) { |
| | | this.unsupportedPreviewVisible = true; |
| | | }, |
| | | |
| | | handlePdfDialogClose() { |
| | | this.pdfUrl = ""; |
| | | this.currentPage = 1; |
| | | this.pageCount = 0; |
| | | }, |
| | | |
| | | // 文件下载 |
| | | handleDownload(file) { |
| | | const fileUrl = this.getFileUrl(file); |
| | | const fileName = file.fileName; |
| | | |
| | | if (fileUrl) { |
| | | const link = document.createElement("a"); |
| | | link.href = file.fileUrl; |
| | | link.download = file.fileName; |
| | | link.href = fileUrl; |
| | | link.download = fileName; |
| | | link.style.display = "none"; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | document.body.removeChild(link); |
| | | this.$message.success("开始下载文件"); |
| | | }, |
| | | |
| | | downloadPdf(file) { |
| | | this.handleDownload(file); |
| | | }, |
| | | |
| | | 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]; |
| | | } else { |
| | | this.$message.warning("文件路径不存在,无法下载"); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | |
| | | padding: 0 20px; |
| | | } |
| | | |
| | | /* PDF预览对话框样式 */ |
| | | .pdf-preview-dialog { |
| | | margin-top: 5vh !important; |
| | | .detail-section { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .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; |
| | | .section-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .zoom-controls { |
| | | margin: 0 15px; |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | |
| | | /* PDF视图区域样式 */ |
| | | .pdf-viewport { |
| | | flex: 1; |
| | | overflow: auto; |
| | | padding: 20px; |
| | | background: #f8f9fa; |
| | | /* 附件样式 */ |
| | | .detail-attachments { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .attachment-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); |
| | | gap: 16px; |
| | | } |
| | | |
| | | .attachment-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | |
| | | /* 图片附件样式 */ |
| | | .image-attachment { |
| | | border-radius: 4px; |
| | | border: 1px solid #ebeef5; |
| | | cursor: pointer; |
| | | transition: all 0.3s; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .image-attachment:hover { |
| | | box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .image-info { |
| | | text-align: center; |
| | | width: 100%; |
| | | } |
| | | |
| | | .image-info .file-name { |
| | | font-size: 12px; |
| | | color: #606266; |
| | | margin-bottom: 4px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | max-width: 120px; |
| | | } |
| | | |
| | | .image-info .file-actions { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: flex-start; |
| | | gap: 8px; |
| | | } |
| | | |
| | | /* 图片预览样式 */ |
| | | .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 { |
| | | .image-loading, |
| | | .image-error { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | justify-content: center; |
| | | align-items: center; |
| | | height: 100%; |
| | | color: #909399; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .zoom-controls { |
| | | margin: 10px 0; |
| | | .image-loading i, |
| | | .image-error i { |
| | | font-size: 20px; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .pdf-preview-dialog { |
| | | width: 95% !important; |
| | | /* 文件卡片样式 */ |
| | | .file-card { |
| | | width: 100%; |
| | | min-height: 60px; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .file-content { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 8px; |
| | | } |
| | | |
| | | .file-icon { |
| | | font-size: 24px; |
| | | margin-right: 12px; |
| | | color: #409eff; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .file-info { |
| | | flex: 1; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .file-name { |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | margin-bottom: 4px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .file-meta { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .file-actions { |
| | | text-align: center; |
| | | padding: 8px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | |
| | | /* 备注样式 */ |
| | | .remark-content { |
| | | padding: 12px; |
| | | line-height: 1.6; |
| | | color: #606266; |
| | | white-space: pre-line; |
| | | } |
| | | |
| | | .detail-footer { |
| | |
| | | background-color: #f5f7fa; |
| | | font-weight: bold; |
| | | } |
| | | /* 转运信息样式 */ |
| | | .transport-info { |
| | | padding: 10px; |
| | | } |
| | | |
| | | .transport-item { |
| | | margin-bottom: 8px; |
| | | line-height: 1.6; |
| | | } |
| | | |
| | | .transport-item strong { |
| | | display: inline-block; |
| | | width: 100px; |
| | | color: #606266; |
| | | } |
| | | </style> |