WXL
5 天以前 631c8f37b449b09d19345b76400a39abdb7800f6
api封装档案、上报、转运接入
已修改10个文件
已添加13个文件
2997 ■■■■ 文件已修改
src/api/businessApi/GetWitness.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/OrganUtilization.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/affirm.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/allocation.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/appear.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/assess.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/course.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/decide.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/ethicalReview.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/index.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/maintain.js 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/transfer.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FilePreviewDialog/index.vue 493 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/UploadAttachment/index.vue 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/getters.js 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/appear/caseDetail.vue 415 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/appear/index.vue 445 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/maintain/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/transfer/TransportEdit.vue 598 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/transfer/index.vue 391 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/transfer/transportDetail.vue 326 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/project/donatebaseinfo/index.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/businessApi/GetWitness.js
src/api/businessApi/OrganUtilization.js
src/api/businessApi/affirm.js
src/api/businessApi/allocation.js
src/api/businessApi/appear.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
import request from '@/utils/request'
// ä¸ŠæŠ¥æ¡ˆä¾‹æ–°å¢ž
export function donateAdd(data) {
  return request({
    url: '/project/donatebaseinforeport/add',
    method: 'post',
    data: data
  })
}
// ä¸ŠæŠ¥æ¡ˆä¾‹ä¿®æ”¹
export function donateEdit(data) {
  return request({
    url: '/project/donatebaseinforeport/edit',
    method: 'post',
    data: data
  })
}
// ä¸ŠæŠ¥æ¡ˆä¾‹åˆ—表
export function donateList(data) {
  return request({
    url: '/project/donatebaseinforeport/list',
    method: 'post',
    data: data
  })
}
// æ¡ˆä¾‹è¯¦æƒ…
export function donateInfo(id) {
  return request({
    url: '/project/donatebaseinforeport/getInfo/' + id,
    method: 'get'
  })
}
// åˆ é™¤
export function donateDel(id) {
  return request({
    url: '/project/donatebaseinforeport/remove/' + id,
    method: 'get'
  })
}
src/api/businessApi/assess.js
src/api/businessApi/course.js
src/api/businessApi/decide.js
src/api/businessApi/ethicalReview.js
src/api/businessApi/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
export * from "./affirm";
export * from "./allocation";
export * from "./appear";
export * from "./assess";
export * from "./course";
export * from "./ethicalReview";
export * from "./decide";
export * from "./GetWitness";
export * from "./maintain";
export * from "./OrganUtilization";
export * from "./transfer";
src/api/businessApi/maintain.js
src/api/businessApi/transfer.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
import request from '@/utils/request'
// ä¸ŠæŠ¥æ¡ˆä¾‹æ–°å¢ž
export function transportAdd(data) {
  return request({
    url: '/project/transport/add',
    method: 'post',
    data: data
  })
}
// ä¸ŠæŠ¥æ¡ˆä¾‹ä¿®æ”¹
export function transportEdit(data) {
  return request({
    url: '/project/transport/edit',
    method: 'post',
    data: data
  })
}
// ä¸ŠæŠ¥æ¡ˆä¾‹åˆ—表
export function transportList(data) {
  return request({
    url: '/project/transport/list',
    method: 'post',
    data: data
  })
}
// æ¡ˆä¾‹è¯¦æƒ…
export function transportInfo(id) {
  return request({
    url: '/project/transport/getInfo/' + id,
    method: 'get'
  })
}
// åˆ é™¤
export function transportDel(id) {
  return request({
    url: '/project/transport/remove/' + id,
    method: 'get'
  })
}
src/components/FilePreviewDialog/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,493 @@
<template>
  <el-dialog
    class="file-preview-dialog"
    :title="previewTitle"
    :visible.sync="previewVisible"
    width="80%"
    top="5vh"
    :close-on-click-modal="true"
    append-to-body
    @close="handleClose"
  >
    <!-- åŠ è½½çŠ¶æ€ -->
    <div v-if="loading" class="preview-loading">
      <i class="el-icon-loading" style="font-size: 40px; margin-bottom: 16px;"></i>
      <span>文件加载中...</span>
    </div>
    <!-- å›¾ç‰‡é¢„览 -->
    <div v-else-if="fileType === 'image'" class="preview-container">
      <div class="image-toolbar">
        <el-button-group>
          <el-button size="mini" @click="zoomImageIn" :disabled="imageScale >= 300">
            <i class="el-icon-zoom-in"></i> æ”¾å¤§
          </el-button>
          <el-button size="mini" disabled>{{ imageScale }}%</el-button>
          <el-button size="mini" @click="zoomImageOut" :disabled="imageScale <= 50">
            <i class="el-icon-zoom-out"></i> ç¼©å°
          </el-button>
          <el-button size="mini" @click="resetImageZoom">
            <i class="el-icon-refresh-left"></i> é‡ç½®
          </el-button>
        </el-button-group>
        <el-button size="mini" type="success" @click="handleDownload">
          <i class="el-icon-download"></i> ä¸‹è½½
        </el-button>
      </div>
      <div class="image-viewport">
        <img
          :src="fileUrl"
          alt="预览图片"
          class="preview-image"
          :style="{ transform: `scale(${imageScale / 100})` }"
          @load="handleImageLoad"
        />
      </div>
    </div>
    <!-- PDF预览 -->
    <div v-else-if="fileType === 'pdf'" class="preview-container pdf-preview">
      <div class="pdf-toolbar">
        <el-button-group>
          <el-button
            size="mini"
            @click="changePage(currentPage - 1)"
            :disabled="currentPage <= 1"
          >
            <i class="el-icon-arrow-left"></i> ä¸Šä¸€é¡µ
          </el-button>
          <el-button size="mini" disabled>
            ç¬¬ {{ currentPage }} é¡µ / å…± {{ pageCount }} é¡µ
          </el-button>
          <el-button
            size="mini"
            @click="changePage(currentPage + 1)"
            :disabled="currentPage >= pageCount"
          >
            <i class="el-icon-arrow-right"></i> ä¸‹ä¸€é¡µ
          </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="handleDownload"
        >
          <i class="el-icon-download"></i> ä¸‹è½½
        </el-button>
      </div>
      <div class="pdf-content" v-loading="pdfLoading">
        <pdf
          ref="pdf"
          :src="pdfUrl"
          :page="currentPage"
          @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>
    <!-- Office文档预览 -->
    <div v-else-if="fileType === 'office'" class="preview-container office-preview">
      <div class="office-toolbar">
        <el-alert
          title="Office文档预览提示"
          description="建议下载后使用本地Office软件查看以获得最佳体验"
          type="info"
          show-icon
          :closable="false"
        />
        <el-button size="mini" type="success" @click="handleDownload">
          <i class="el-icon-download"></i> ä¸‹è½½æ–‡æ¡£
        </el-button>
      </div>
      <div class="office-content">
        <iframe
          :src="`https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(fileUrl)}`"
          width="100%"
          height="600px"
          frameborder="0"
        ></iframe>
      </div>
    </div>
    <!-- ä¸æ”¯æŒé¢„览的文件类型 -->
    <div v-else class="preview-container unsupported-preview">
      <el-alert
        title="该文件格式不支持在线预览"
        :description="`文件类型: ${getFileExtension(fileName)}`"
        type="warning"
        show-icon
        :closable="false"
      />
      <div class="unsupported-actions">
        <el-button type="primary" @click="handleDownload">
          <i class="el-icon-download"></i> ä¸‹è½½æ–‡ä»¶
        </el-button>
        <el-button @click="handleClose">关闭</el-button>
      </div>
      <div class="file-info">
        <p><strong>文件名:</strong> {{ fileName }}</p>
        <p><strong>文件类型:</strong> {{ getFileExtension(fileName) }}</p>
      </div>
    </div>
  </el-dialog>
</template>
<script>
import pdf from "vue-pdf";
export default {
  name: "FilePreviewDialog",
  components: {
    pdf
  },
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    file: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      // é¢„览控制
      previewVisible: this.visible,
      // åŠ è½½çŠ¶æ€
      loading: false,
      pdfLoading: false,
      // æ–‡ä»¶ä¿¡æ¯
      fileUrl: "",
      fileName: "",
      fileType: "",
      // PDF相关
      currentPage: 1,
      pageCount: 0,
      scale: 100,
      pageRotate: 0,
      // å›¾ç‰‡ç›¸å…³
      imageScale: 100
    };
  },
  computed: {
    previewTitle() {
      return `文件预览 - ${this.fileName}`;
    },
    pdfUrl() {
      return this.fileUrl;
    }
  },
  watch: {
    visible(newVal) {
      this.previewVisible = newVal;
      if (newVal) {
        this.initPreview();
      }
    },
    previewVisible(newVal) {
      this.$emit('update:visible', newVal);
      if (!newVal) {
        this.handleClose();
      }
    }
  },
  methods: {
    /** åˆå§‹åŒ–预览 */
    initPreview() {
      if (!this.file) return;
      this.fileName = this.file.fileName || this.file.name || "未知文件";
      this.fileUrl = this.file.fileUrl || this.file.path || this.file.url;
      this.fileType = this.getFileType(this.fileName);
      this.loading = true;
      // é‡ç½®çŠ¶æ€
      this.currentPage = 1;
      this.scale = 100;
      this.imageScale = 100;
      this.pageCount = 0;
      // æ¨¡æ‹ŸåŠ è½½å»¶è¿Ÿ
      setTimeout(() => {
        this.loading = false;
        if (this.fileType === "pdf") {
          this.pdfLoading = true;
        }
      }, 300);
    },
    /** èŽ·å–æ–‡ä»¶ç±»åž‹ */
    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", "ppt", "pptx"];
      if (imageTypes.includes(extension)) return "image";
      if (pdfTypes.includes(extension)) return "pdf";
      if (officeTypes.includes(extension)) return "office";
      return "other";
    },
    /** èŽ·å–æ–‡ä»¶æ‰©å±•å */
    getFileExtension(filename) {
      return filename.split('.').pop().toLowerCase() || "未知";
    },
    /** PDF加载完成 */
    loadPdfHandler() {
      this.pdfLoading = false;
      this.currentPage = 1;
    },
    /** PDF加载错误 */
    pdfErrorHandler(error) {
      console.error("PDF加载失败:", error);
      this.pdfLoading = false;
      this.$message.error("PDF文件加载失败,请尝试下载后查看");
      this.previewVisible = false;
    },
    /** å›¾ç‰‡åŠ è½½å®Œæˆ */
    handleImageLoad() {
      this.loading = false;
    },
    /** æ”¹å˜PDF页码 */
    changePage(newPage) {
      if (newPage < 1 || newPage > this.pageCount) return;
      this.currentPage = newPage;
    },
    /** PDF放大 */
    zoomIn() {
      if (this.scale >= 200) {
        this.$message.info("已放大到最大比例");
        return;
      }
      this.scale += 10;
    },
    /** PDF缩小 */
    zoomOut() {
      if (this.scale <= 50) {
        this.$message.info("已缩小到最小比例");
        return;
      }
      this.scale -= 10;
    },
    /** PDF重置缩放 */
    resetZoom() {
      this.scale = 100;
    },
    /** å›¾ç‰‡æ”¾å¤§ */
    zoomImageIn() {
      if (this.imageScale >= 300) {
        this.$message.info("已放大到最大比例");
        return;
      }
      this.imageScale += 20;
    },
    /** å›¾ç‰‡ç¼©å° */
    zoomImageOut() {
      if (this.imageScale <= 50) {
        this.$message.info("已缩小到最小比例");
        return;
      }
      this.imageScale -= 20;
    },
    /** å›¾ç‰‡é‡ç½®ç¼©æ”¾ */
    resetImageZoom() {
      this.imageScale = 100;
    },
    /** ä¸‹è½½æ–‡ä»¶ */
    handleDownload() {
      if (!this.fileUrl) {
        this.$message.warning("文件路径不存在,无法下载");
        return;
      }
      const link = document.createElement("a");
      link.href = this.fileUrl;
      link.download = this.fileName;
      link.style.display = "none";
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      this.$message.success("开始下载文件");
    },
    /** å…³é—­å¯¹è¯æ¡† */
    handleClose() {
      this.previewVisible = false;
      this.$emit("close");
      // æ¸…理资源
      if (this.fileUrl && this.fileUrl.startsWith("blob:")) {
        URL.revokeObjectURL(this.fileUrl);
      }
    }
  }
};
</script>
<style scoped>
.file-preview-dialog {
  .preview-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 400px;
    color: #909399;
  }
  .preview-container {
    display: flex;
    flex-direction: column;
    height: 70vh;
  }
  /* å·¥å…·æ é€šç”¨æ ·å¼ */
  .image-toolbar,
  .pdf-toolbar,
  .office-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;
  }
  /* å›¾ç‰‡é¢„览样式 */
  .image-viewport {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: auto;
    padding: 20px;
    background: #f8f9fa;
  }
  .preview-image {
    max-width: 100%;
    max-height: 100%;
    transition: transform 0.3s ease;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  }
  /* PDF预览样式 */
  .pdf-content {
    flex: 1;
    overflow: auto;
    padding: 20px;
    background: #f8f9fa;
    display: flex;
    justify-content: center;
    align-items: flex-start;
  }
  /* Office预览样式 */
  .office-content {
    flex: 1;
    padding: 20px;
    background: #f8f9fa;
  }
  /* ä¸æ”¯æŒé¢„览的样式 */
  .unsupported-preview {
    padding: 40px 20px;
    text-align: center;
  }
  .unsupported-actions {
    margin: 30px 0;
  }
  .unsupported-actions .el-button {
    margin: 0 10px;
  }
  .file-info {
    text-align: left;
    max-width: 400px;
    margin: 0 auto;
    padding: 20px;
    background: #f5f7fa;
    border-radius: 4px;
  }
  .file-info p {
    margin: 8px 0;
  }
}
/* å¯¹è¯æ¡†æ ·å¼è°ƒæ•´ */
:deep(.el-dialog) {
  margin-top: 5vh !important;
}
:deep(.el-dialog__body) {
  padding: 0;
}
/* å“åº”式设计 */
@media (max-width: 768px) {
  .file-preview-dialog {
    :deep(.el-dialog) {
      width: 95% !important;
    }
    .preview-container {
      .image-toolbar,
      .pdf-toolbar,
      .office-toolbar {
        flex-direction: column;
        gap: 10px;
      }
    }
  }
}
</style>
src/components/UploadAttachment/index.vue
@@ -1,35 +1,172 @@
<template>
  <div class="upload-attachment">
    <el-upload
      action="#"
      ref="upload"
      :action="uploadAction"
      :headers="headers"
      :file-list="fileList"
      :auto-upload="false"
      :multiple="true"
      :limit="limit"
      :accept="accept"
      :on-exceed="handleExceed"
      :on-change="handleFileChange"
      :on-remove="handleFileRemove"
      multiple
      :on-success="handleUploadSuccess"
      :on-error="handleUploadError"
      :before-upload="beforeUpload"
    >
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">支持jpg、png、pdf、doc、docx等格式,单个文件不超过10MB</div>
      <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
      <el-button
        style="margin-left: 10px;"
        size="small"
        type="success"
        @click="submitUpload"
        :disabled="fileList.length === 0"
      >
        ä¸Šä¼ åˆ°æœåС噍
      </el-button>
      <div slot="tip" class="el-upload__tip">
        è¯·ä¸Šä¼  {{ accept }} æ ¼å¼çš„æ–‡ä»¶ï¼Œå•个文件不超过10MB,最多可上传{{ limit }}个文件
      </div>
    </el-upload>
  </div>
</template>
<script>
import { getToken } from "@/utils/auth";
export default {
  name: "UploadAttachment",
  props: {
    // æ–‡ä»¶åˆ—表
    fileList: {
      type: Array,
      default: () => []
    },
    // ä¸Šä¼ æ•°é‡é™åˆ¶
    limit: {
      type: Number,
      default: 10
    },
    // æŽ¥å—的文件类型
    accept: {
      type: String,
      default: ".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx"
    },
    // ä¸Šä¼ åœ°å€
    uploadUrl: {
      type: String,
      default: process.env.VUE_APP_BASE_API + "/common/upload"
    }
  },
  data() {
    return {
      uploadAction: process.env.VUE_APP_BASE_API + "/common/upload",
      headers: {
        Authorization: "Bearer " + getToken()
      }
    };
  },
  methods: {
    /** æ–‡ä»¶é€‰æ‹©å˜åŒ– */
    handleFileChange(file, fileList) {
      this.$emit('change', fileList);
    },
    /** æ–‡ä»¶ç§»é™¤ */
    handleFileRemove(file, fileList) {
      this.$emit('change', fileList);
      this.$emit('remove', file);
    },
    /** ä¸Šä¼ æˆåŠŸå¤„ç† */
    handleUploadSuccess(response, file, fileList) {
      if (response.code === 200) {
        file.url = response.data || response.url;
        this.$message.success('文件上传成功');
        this.$emit('upload-success', {
          file,
          fileList,
          response
        });
      } else {
        this.$message.error(response.msg || '文件上传失败');
      }
    },
    /** ä¸Šä¼ é”™è¯¯å¤„理 */
    handleUploadError(err, file, fileList) {
      console.error('上传失败:', err);
      this.$message.error('文件上传失败,请重试');
      this.$emit('upload-error', {
        file,
        fileList,
        error: err
      });
    },
    /** ä¸Šä¼ å‰æ ¡éªŒ */
    beforeUpload(file) {
      // æ£€æŸ¥æ–‡ä»¶ç±»åž‹
      const allowedTypes = this.accept.split(',').map(type => type.trim().toLowerCase());
      const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
      if (!allowedTypes.includes(fileExtension) && !allowedTypes.includes(fileExtension.substring(1))) {
        this.$message.error(`不支持的文件格式: ${fileExtension}`);
        return false;
      }
      // æ£€æŸ¥æ–‡ä»¶å¤§å° (10MB限制)
      const isLt10M = file.size / 1024 / 1024 < 10;
      if (!isLt10M) {
        this.$message.error('文件大小不能超过 10MB!');
        return false;
      }
      return true;
    },
    /** æ–‡ä»¶æ•°é‡è¶…出限制 */
    handleExceed(files, fileList) {
      this.$message.warning(`最多只能上传 ${this.limit} ä¸ªæ–‡ä»¶ï¼Œå½“前选择了 ${files.length} ä¸ªæ–‡ä»¶`);
    },
    /** æ‰‹åŠ¨æäº¤ä¸Šä¼  */
    submitUpload() {
      if (this.fileList.length === 0) {
        this.$message.warning('请先选择要上传的文件');
        return;
      }
      this.$refs.upload.submit();
    },
    /** æ¸…空文件列表 */
    clearFiles() {
      this.$refs.upload.clearFiles();
    },
    /** èŽ·å–å½“å‰æ–‡ä»¶åˆ—è¡¨ */
    getFileList() {
      return this.fileList;
    }
  }
};
</script>
<style scoped>
.upload-attachment {
  width: 100%;
}
::v-deep .el-upload {
  display: block;
}
::v-deep .el-upload__tip {
  margin-top: 8px;
  font-size: 12px;
  color: #909399;
}
</style>
src/store/getters.js
@@ -14,8 +14,44 @@
  rolesor: state => state.user.rolesor,
  permissions: state => state.user.permissions,
  permission_routes: state => state.permission.routes,
  topbarRouters:state => state.permission.topbarRouters,
  defaultRoutes:state => state.permission.defaultRoutes,
  sidebarRouters:state => state.permission.sidebarRouters,
}
export default getters
  topbarRouters: state => state.permission.topbarRouters,
  defaultRoutes: state => state.permission.defaultRoutes,
  sidebarRouters: state => state.permission.sidebarRouters,
  // ä¼˜å…ˆæ‰§è¡Œ
  bloodTypeOptions: state => [
    {
      value: 0,
      label: "语音优先",
      raw: {
        cssClass: "",
        listClass: ""
      }
    },
    {
      value: 1,
      label: "文字优先",
      raw: {
        cssClass: "",
        listClass: ""
      }
    },
    {
      value: 0,
      label: "语音优先",
      raw: {
        cssClass: "",
        listClass: ""
      }
    },
    {
      value: 1,
      label: "文字优先",
      raw: {
        cssClass: "",
        listClass: ""
      }
    }
  ]
};
export default getters;
src/views/business/appear/caseDetail.vue
@@ -6,33 +6,77 @@
        <span class="section-title">基本信息</span>
      </div>
      <el-descriptions :column="2" border>
        <el-descriptions-item label="捐献编号">{{
          caseData.donorNo
        <el-descriptions-item label="案例编号">{{
          caseData.caseNo || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="捐献者姓名">{{
          caseData.donorName
          caseData.name || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="性别">
          <dict-tag :options="genderOptions" :value="caseData.gender" />
          <dict-tag
            :options="dict.type.sys_user_sex"
            :value="caseData.sex ? parseInt(caseData.sex) : ''"
          />
        </el-descriptions-item>
        <el-descriptions-item label="年龄"
          >{{ caseData.age }}岁</el-descriptions-item
        >
        <el-descriptions-item label="年龄">
          {{ caseData.age || "-"
          }}{{
            caseData.ageunit ? `(${getAgeUnitText(caseData.ageunit)})` : ""
          }}
        </el-descriptions-item>
        <el-descriptions-item label="血型">
          <dict-tag :options="bloodTypeOptions" :value="caseData.bloodType" />
          <dict-tag
            :options="dict.type.sys_BloodType"
            :value="caseData.bloodType"
          />
        </el-descriptions-item>
        <el-descriptions-item label="Rh阴性">
          {{
            caseData.rhYin === "1" ? "是" : caseData.rhYin === "0" ? "否" : "-"
          }}
        </el-descriptions-item>
        <el-descriptions-item label="证件类型">
          {{ getIdCardTypeText(caseData.idcardtype) }}
        </el-descriptions-item>
        <el-descriptions-item label="证件号码">{{
          caseData.idCardNo
          caseData.idcardno || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="民族">{{
          caseData.nation
          caseData.nation || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="国籍">{{
          caseData.nationality || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="籍贯">{{
          caseData.nativeplace || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="学历">{{
          caseData.education || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="职业">{{
          caseData.occupation || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="出生日期">{{
          formatDate(caseData.birthday)
        }}</el-descriptions-item>
        <el-descriptions-item label="联系电话">{{
          caseData.phone
          caseData.phone || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="住址" :span="2">{{
          caseData.address
        }}</el-descriptions-item>
      </el-descriptions>
    </el-card>
    <!-- åœ°å€ä¿¡æ¯æ¨¡å— -->
    <el-card class="detail-section">
      <div slot="header" class="section-header">
        <span class="section-title">地址信息</span>
      </div>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="户籍地址">
          {{ getFullRegisterAddress() }}
        </el-descriptions-item>
        <el-descriptions-item label="现住地址">
          {{ getFullResidenceAddress() }}
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
@@ -42,24 +86,29 @@
        <span class="section-title">医疗信息</span>
      </div>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="疾病诊断">{{
          caseData.diagnosis
        <el-descriptions-item label="疾病诊断名称">{{
          caseData.diagnosisname || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="住院号">{{
          caseData.inpatientNo
        <el-descriptions-item label="病情概况">{{
          caseData.illnessoverview || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="所在科室">{{
          caseData.departmentName
        <el-descriptions-item label="病人状况">{{
          caseData.patientstate || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="主治医生">{{
          caseData.doctorName
        <el-descriptions-item label="GCS评分">{{
          caseData.gcsScore || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="传染病情况">{{
          caseData.infectiousDisease || "无"
          caseData.infectious || "无"
        }}</el-descriptions-item>
        <el-descriptions-item label="医疗记录">{{
          caseData.medicalRecord
        }}</el-descriptions-item>
        <el-descriptions-item
          label="传染病其他说明"
          v-if="caseData.infectiousOther"
          >{{ caseData.infectiousOther }}</el-descriptions-item
        >
        <el-descriptions-item label="是否需要转运">
          {{ caseData.isTransport === "2" ? "需要" : "不需要" }}
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
@@ -69,31 +118,60 @@
        <span class="section-title">医院信息</span>
      </div>
      <el-descriptions :column="2" border>
        <el-descriptions-item label="医院名称">{{
          caseData.hospitalName
        <el-descriptions-item label="治疗医院名称">{{
          caseData.treatmenthospitalname || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="医院级别">{{
          caseData.hospitalLevel
        <el-descriptions-item label="治疗科室名称">{{
          caseData.treatmentdeptname || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="联系人">{{
          caseData.contactPerson
        <el-descriptions-item label="住院号">{{
          caseData.inpatientno || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="联系电话">{{
          caseData.contactPhone
        }}</el-descriptions-item>
        <el-descriptions-item label="医院地址" :span="2">{{
          caseData.hospitalAddress
        <el-descriptions-item label="部门名称">{{
          caseData.deptName || "-"
        }}</el-descriptions-item>
      </el-descriptions>
    </el-card>
    <!-- é™„件信息模块 -->
    <!-- ä¸ŠæŠ¥ä¿¡æ¯æ¨¡å— -->
    <el-card class="detail-section">
      <div slot="header" class="section-header">
        <span class="section-title">上报信息</span>
      </div>
      <el-descriptions :column="2" border>
        <el-descriptions-item label="报告者姓名">{{
          caseData.infoName || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="报告者编号">{{
          caseData.infoNo || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="报告者联系电话">{{
          caseData.reporterphone || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="协调员姓名">{{
          caseData.coordinatorName || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="协调员编号">{{
          caseData.coordinatorNo || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="上报状态">
          <el-tag :type="getStatusType(caseData.reportStatus)">
            {{ getStatusText(caseData.reportStatus) }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="报告时间">{{
          formatDateTime(caseData.reporttime)
        }}</el-descriptions-item>
        <el-descriptions-item label="是否终止案例">
          {{ caseData.terminationCase === "1" ? "已终止" : "进行中" }}
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
    <!-- é™„件信息模块 -->
    <el-card class="detail-section" v-if="attachmentList.length > 0">
      <div slot="header" class="section-header">
        <span class="section-title">附件信息</span>
        <el-button type="text" icon="el-icon-upload" @click="handleUpload"
          >上传附件</el-button
        >
      </div>
      <el-table :data="attachmentList" style="width: 100%">
        <el-table-column label="文件名" width="300">
@@ -128,36 +206,33 @@
              @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-card class="detail-section" v-if="caseData.status !== '0'">
    <!-- å®¡æ‰¹ä¿¡æ¯æ¨¡å—(状态为已同意或已驳回时显示) -->
    <el-card
      class="detail-section"
      v-if="caseData.reportStatus === '3' || caseData.reportStatus === '4'"
    >
      <div slot="header" class="section-header">
        <span class="section-title">审批信息</span>
      </div>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="审批结果">
          <el-tag :type="caseData.status | statusFilter">
            {{ caseData.status | statusTextFilter }}
          <el-tag :type="caseData.reportStatus === '3' ? 'success' : 'danger'">
            {{ caseData.reportStatus === "3" ? "已同意" : "已驳回" }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="审批时间">{{
          caseData.approveTime
          formatDateTime(caseData.updateTime)
        }}</el-descriptions-item>
        <el-descriptions-item label="审批人">{{
          caseData.approverName
          caseData.updateBy || "-"
        }}</el-descriptions-item>
        <el-descriptions-item label="审批意见">{{
          caseData.approveOpinion
          caseData.remark || "无"
        }}</el-descriptions-item>
      </el-descriptions>
    </el-card>
@@ -302,6 +377,7 @@
      default: true
    }
  },
  dicts: ["sys_user_sex", "sys_BloodType"],
  filters: {
    statusFilter(status) {
      const statusMap = {
@@ -322,74 +398,159 @@
  },
  data() {
    return {
      activeTab: "basic",
      genderOptions: [
        { value: "0", label: "男" },
        { value: "1", label: "女" }
      ],
      bloodTypeOptions: [
        { value: "A", label: "A型" },
        { value: "B", label: "B型" },
        { value: "O", label: "O型" },
        { value: "AB", label: "AB型" }
      ],
      // é™„件相关数据
      attachmentList: [
        {
          id: 1,
          fileName: "捐献者身份证.jpg",
          fileType: "jpg",
          fileSize: 1024000,
          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: "docx",
          fileSize: 512000,
          uploadTime: "2024-12-19 14:15:00",
          fileUrl: "https://img95.699pic.com/photo/40019/3490.jpg_wh860.jpg"
        }
      ],
      // PDF预览相关数据
      // é¢„览相关数据(保持原有代码)
      pdfPreviewVisible: false,
      imagePreviewVisible: false,
      unsupportedPreviewVisible: false,
      pdfLoading: false,
      pdfUrl: "",
      currentPage: 1,
      pageCount: 0,
      scale: 100,
      pageRotate: 0,
      // å›¾ç‰‡é¢„览相关
      imagePreviewVisible: false,
      // ä¸æ”¯æŒé¢„览相关
      unsupportedPreviewVisible: false,
      // é€šç”¨é¢„览数据
      previewTitle: "",
      previewUrl: "",
      currentFile: null
      currentFile: null,
      // é™„件列表
      attachmentList: []
    };
  },
  watch: {
    caseData: {
      immediate: true,
      handler(newVal) {
        if (newVal && newVal.annexfilesList) {
          this.loadAttachments(newVal.annexfilesList);
        }
      }
    }
  },
  methods: {
    handleClose() {
      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);
    },
    // æ ¼å¼åŒ–日期
    formatDate(dateString) {
      if (!dateString) return "-";
      return dateString.split("T")[0];
    },
    // èŽ·å–å®Œæ•´æˆ·ç±åœ°å€
    getFullRegisterAddress() {
      const {
        registerprovincename,
        registercityname,
        registertownname,
        registercommunityname,
        registeraddress
      } = this.caseData;
      const addressParts = [
        registerprovincename,
        registercityname,
        registertownname,
        registercommunityname,
        registeraddress
      ];
      return addressParts.filter(part => part).join("") || "-";
    },
    // èŽ·å–å®Œæ•´çŽ°ä½åœ°å€
    getFullResidenceAddress() {
      const {
        residenceprovincename,
        residencecountyname,
        residencetownname,
        residencecommunityname,
        residenceaddress
      } = this.caseData;
      const addressParts = [
        residenceprovincename,
        residencecountyname,
        residencetownname,
        residencecommunityname,
        residenceaddress
      ];
      return addressParts.filter(part => part).join("") || "-";
    },
    // èŽ·å–çŠ¶æ€æ–‡æœ¬
    getStatusText(status) {
      const statusMap = {
        "1": "已上报",
        "2": "已阅读",
        "3": "已同意",
        "4": "已驳回"
      };
      return statusMap[status] || "未知状态";
    },
    // èŽ·å–çŠ¶æ€ç±»åž‹
    getStatusType(status) {
      const statusMap = {
        "1": "info",
        "2": "warning",
        "3": "success",
        "4": "danger"
      };
      return statusMap[status] || "info";
    },
    // èŽ·å–å¹´é¾„å•ä½æ–‡æœ¬
    getAgeUnitText(unit) {
      const unitMap = {
        year: "岁",
        month: "月",
        day: "天"
      };
      return unitMap[unit] || unit;
    },
    // èŽ·å–è¯ä»¶ç±»åž‹æ–‡æœ¬
    getIdCardTypeText(type) {
      const typeMap = {
        "1": "身份证",
        "2": "护照",
        "3": "军官证"
      };
      return typeMap[type] || type || "-";
    },
    // æ–‡ä»¶é¢„览相关方法(保持原有代码)
    getFileType(fileName) {
      const extension = fileName
        .split(".")
@@ -397,13 +558,11 @@
        .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}`;
@@ -423,7 +582,6 @@
      }
    },
    // PDF预览方法
    previewPdf(file) {
      this.pdfPreviewVisible = true;
      this.pdfLoading = true;
@@ -433,13 +591,11 @@
      this.pdfUrl = file.fileUrl;
    },
    // PDF加载完成回调
    loadPdfHandler() {
      this.pdfLoading = false;
      this.currentPage = 1;
    },
    // PDF加载错误处理
    pdfErrorHandler(error) {
      console.error("PDF加载失败:", error);
      this.pdfLoading = false;
@@ -447,26 +603,18 @@
      this.pdfPreviewVisible = false;
    },
    // ç¿»é¡µåŠŸèƒ½
    changePage(newPage) {
      if (newPage < 1 || newPage > this.pageCount) return;
      this.currentPage = newPage;
    },
    // ç¼©æ”¾åŠŸèƒ½
    zoomIn() {
      if (this.scale >= 200) {
        this.$message.info("已放大到最大比例");
        return;
      }
      if (this.scale >= 200) return;
      this.scale += 10;
    },
    zoomOut() {
      if (this.scale <= 50) {
        this.$message.info("已缩小到最小比例");
        return;
      }
      if (this.scale <= 50) return;
      this.scale -= 10;
    },
@@ -474,24 +622,20 @@
      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;
@@ -503,31 +647,10 @@
      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("上传功能待实现");
    },
    // æ ¼å¼åŒ–文件大小
    formatFileSize(bytes) {
      if (bytes === 0) return "0 B";
      const k = 1024;
src/views/business/appear/index.vue
@@ -8,33 +8,33 @@
        :inline="true"
        class="demo-form-inline"
      >
        <el-form-item label="捐献编号" prop="donorNo">
        <el-form-item label="案例编号" prop="caseNo">
          <el-input
            v-model="queryParams.donorNo"
            placeholder="请输入捐献编号"
            v-model="queryParams.caseNo"
            placeholder="请输入案例编号"
            clearable
            style="width: 200px"
          />
        </el-form-item>
        <el-form-item label="捐献者姓名" prop="donorName">
        <el-form-item label="捐献者姓名" prop="name">
          <el-input
            v-model="queryParams.donorName"
            v-model="queryParams.name"
            placeholder="请输入捐献者姓名"
            clearable
            style="width: 200px"
          />
        </el-form-item>
        <el-form-item label="案例状态" prop="status">
        <el-form-item label="案例状态" prop="reportStatus">
          <el-select
            v-model="queryParams.status"
            v-model="queryParams.reportStatus"
            placeholder="请选择状态"
            clearable
            style="width: 200px"
          >
            <el-option label="全部" value="" />
            <el-option label="待审批" value="0" />
            <el-option label="已通过" value="1" />
            <el-option label="已终止" value="2" />
            <el-option label="已阅读" value="2" />
            <el-option label="已同意" value="3" />
            <el-option label="已驳回" value="4" />
          </el-select>
        </el-form-item>
        <el-form-item>
@@ -48,11 +48,11 @@
    <!-- æ“ä½œæŒ‰é’®åŒºåŸŸ -->
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
      <!-- <el-col :span="1.5">
        <el-button type="primary" plain icon="el-icon-plus" @click="handleAdd"
          >新增案例</el-button
        >
      </el-col>
      </el-col> -->
      <el-col :span="1.5">
        <el-button
@@ -73,34 +73,38 @@
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" align="center" />
      <!-- <el-table-column label="序号" type="index" width="60" align="center"/>
      <el-table-column label="捐献编号" align="center" prop="donorNo" width="140"/> -->
      <el-table-column
        label="上报时间"
        align="center"
        prop="reportTime"
        prop="reporttime"
        width="160"
      />
      <el-table-column
        label="捐献者姓名"
        align="center"
        prop="donorName"
        prop="name"
        width="100"
      />
      <el-table-column label="性别" align="center" prop="gender" width="80">
      <el-table-column label="性别" align="center" prop="sex" width="80">
        <template slot-scope="scope">
          <dict-tag :options="genderOptions" :value="scope.row.gender" />
          <dict-tag
            :options="dict.type.sys_user_sex"
            :value="parseInt(scope.row.sex)"
          />
        </template>
      </el-table-column>
      <el-table-column label="年龄" align="center" prop="age" width="80" />
      <el-table-column label="血型" align="center" prop="bloodType" width="80">
        <template slot-scope="scope">
          <dict-tag :options="bloodTypeOptions" :value="scope.row.bloodType" />
          <dict-tag
            :options="dict.type.sys_BloodType"
            :value="scope.row.bloodtype"
          />
        </template>
      </el-table-column>
         <el-table-column
      <el-table-column
        label="GCS评分"
        align="center"
        prop="gscScore"
@@ -110,20 +114,25 @@
      <el-table-column
        label="疾病诊断"
        align="center"
        prop="diagnosis"
        prop="diagnosisname"
        min-width="200"
        show-overflow-tooltip
      />
      <el-table-column
        label="上报医院"
        label="治疗医院"
        align="center"
        prop="hospitalName"
        prop="treatmenthospitalname"
        width="150"
      />
      <el-table-column label="状态" align="center" prop="status" width="100">
      <el-table-column
        label="状态"
        align="center"
        prop="reportStatus"
        width="100"
      >
        <template slot-scope="scope">
          <el-tag :type="scope.row.status | statusFilter">
            {{ scope.row.status | statusTextFilter }}
          <el-tag :type="scope.row.reportStatus | statusFilter">
            {{ scope.row.reportStatus | statusTextFilter }}
          </el-tag>
        </template>
      </el-table-column>
@@ -147,7 +156,7 @@
            type="text"
            icon="el-icon-check"
            @click="handleApprove(scope.row)"
            v-if="scope.row.status === '0'"
            v-if="scope.row.reportStatus === '2'"
            >审批</el-button
          >
        </template>
@@ -175,7 +184,6 @@
    </el-dialog>
    <!-- å®¡æ‰¹å¼¹æ¡† -->
    <!-- å®¡æ‰¹å¼¹æ¡†ä¼˜åŒ– -->
    <el-dialog
      title="案例审批"
      :visible.sync="approveOpen"
@@ -205,15 +213,15 @@
          >
            <el-form-item label="审批结果" prop="approveResult">
              <el-radio-group v-model="approveForm.approveResult">
                <el-radio label="1">通过</el-radio>
                <el-radio label="2">终止</el-radio>
                <el-radio label="3">同意</el-radio>
                <el-radio label="4">驳回</el-radio>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="审批意见" prop="approveOpinion">
              <el-input
                type="textarea"
                v-model="approveForm.approveOpinion"
                placeholder="请输入详细的审批意见,包括通过或终止的理由"
                placeholder="请输入详细的审批意见,包括通过或驳回的理由"
                :rows="6"
                maxlength="500"
                show-word-limit
@@ -233,11 +241,17 @@
<script>
import CaseDetail from "./caseDetail";
import CaseDetailPreview from "./CaseDetailPreview";
import {
  donateList,
  donateInfo,
  donateDel,
  donateEdit
} from "@/api/businessApi/index";
export default {
  name: "CaseList",
  components: { CaseDetail, CaseDetailPreview },
  components: { CaseDetail },
  dicts: ["sys_user_sex", "sys_BloodType"],
  data() {
    return {
      // é®ç½©å±‚
@@ -276,14 +290,14 @@
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        donorNo: undefined,
        donorName: undefined,
        status: undefined
        caseNo: undefined,
        name: undefined,
        reportStatus: undefined
      },
      // å®¡æ‰¹è¡¨å•
      approveForm: {
        caseId: null,
        approveResult: "1",
        id: null,
        approveResult: "3",
        approveOpinion: ""
      },
      // å®¡æ‰¹è¡¨å•验证
@@ -298,21 +312,23 @@
    };
  },
  filters: {
    statusFilter(status) {
    statusFilter(reportStatus) {
      const statusMap = {
        "0": "warning", // å¾…审批
        "1": "success", // å·²é€šè¿‡
        "2": "danger" // å·²ç»ˆæ­¢
        "1": "info", // å·²ä¸ŠæŠ¥
        "2": "warning", // å·²é˜…读(待审批)
        "3": "success", // å·²åŒæ„
        "4": "danger" // å·²é©³å›ž
      };
      return statusMap[status];
      return statusMap[reportStatus] || "info";
    },
    statusTextFilter(status) {
    statusTextFilter(reportStatus) {
      const statusMap = {
        "0": "待审批",
        "1": "已通过",
        "2": "已终止"
        "1": "已上报",
        "2": "已阅读",
        "3": "已同意",
        "4": "已驳回"
      };
      return statusMap[status];
      return statusMap[reportStatus] || "未知状态";
    }
  },
  created() {
@@ -320,162 +336,255 @@
  },
  methods: {
    /** æŸ¥è¯¢æ¡ˆä¾‹åˆ—表 */
    getList() {
    async getList() {
      this.loading = true;
      // æ¨¡æ‹ŸAPI调用延迟
      setTimeout(() => {
        // æµ‹è¯•数据
        this.caseList = [
          {
            id: 1,
            donorNo: "DON20241219001",
            donorName: "张三",
            gender: "2",
            age: 38,
            bloodType: "A",
            gscScore:'1',
            diagnosis:
              "脑外伤导致脑死亡,经抢救无效宣布脑死亡。家属同意器官捐献。",
            hospitalName: "青岛大学附属医院",
            status: "0",
            reportTime: "2024-12-19 09:30:00",
            reporterName: "李医生",
            idCardNo: "370203198510123456",
            nation: "汉族",
            phone: "13800138000",
            address: "山东省青岛市市南区香港中路100号",
            inpatientNo: "ZY20241219001",
            departmentName: "神经外科",
            doctorName: "王主任",
            infectiousDisease: "无",
            medicalRecord:
              "患者因交通事故导致严重脑外伤,经抢救无效宣布脑死亡。",
            hospitalLevel: "三级甲等",
            contactPerson: "张护士",
            contactPhone: "13900139000",
            hospitalAddress: "山东省青岛市市南区江苏路1号"
          },
          {
            id: 2,
            donorNo: "DON20241218001",
            donorName: "李四",
            gender: "1",
            age: 45,
            bloodType: "O",
            gscScore:'3',
            diagnosis: "急性心肌梗死,心脏功能衰竭",
            hospitalName: "青岛市立医院",
            status: "1",
            reportTime: "2024-12-18 14:20:00",
            approveTime: "2024-12-18 16:30:00",
            reporterName: "刘医生",
            approverName: "审核专员A",
            approveOpinion: "资料齐全,符合捐献条件,同意通过。"
          },
          {
            id: 3,
            donorNo: "DON20241217001",
            donorName: "王五",
            gender: "2",
            age: 52,
            bloodType: "B",
            gscScore:'6',
            diagnosis: "颅内出血,脑干功能丧失",
            hospitalName: "青岛眼科医院",
            status: "2",
            reportTime: "2024-12-17 10:15:00",
            approveTime: "2024-12-17 14:20:00",
            reporterName: "陈医生",
            approverName: "审核专员B",
            approveOpinion: "家属同意书不完整,需补充材料后重新提交。"
          },
          {
            id: 4,
            donorNo: "DON20241216001",
            donorName: "赵六",
            gender: "1",
            age: 28,
            bloodType: "AB",
            gscScore:'10',
            diagnosis: "重型颅脑损伤,多器官功能衰竭",
            hospitalName: "青岛儿童医院",
            status: "0",
            reportTime: "2024-12-16 16:45:00",
            reporterName: "孙医生"
          }
        ];
      try {
        const response = await donateList(this.queryParams);
        this.caseList = response.rows || response.data || [];
        this.total = response.total || this.caseList.length;
      } catch (error) {
        console.error("获取案例列表失败:", error);
        this.$modal.msgError("获取案例列表失败");
        // æ¨¡æ‹Ÿæ•°æ®
        this.caseList = this.getMockData();
        this.total = this.caseList.length;
      } finally {
        this.loading = false;
      }, 500);
      }
    },
    /** æ¨¡æ‹Ÿæ•°æ® */
    getMockData() {
      return [
        {
          id: 1,
          caseNo: "DON20241219001",
          name: "张三",
          sex: "0",
          age: 38,
          bloodType: "A",
          gscScore: "1",
          diagnosisname:
            "脑外伤导致脑死亡,经抢救无效宣布脑死亡。家属同意器官捐献。",
          treatmenthospitalname: "青岛大学附属医院",
          reportStatus: "2",
          reporttime: "2024-12-19 09:30:00",
          reportername: "李医生",
          idcardno: "370203198510123456",
          nation: "汉族",
          phone: "13800138000",
          registeraddress: "山东省青岛市市南区香港中路100号",
          inpatientno: "ZY20241219001",
          treatmentdeptname: "神经外科",
          doctorname: "王主任",
          infectious: "无",
          illnessoverview:
            "患者因交通事故导致严重脑外伤,经抢救无效宣布脑死亡。",
          hospitalLevel: "三级甲等",
          contactperson: "张护士",
          contactphone: "13900139000",
          hospitalAddress: "山东省青岛市市南区江苏路1号"
        },
        {
          id: 2,
          caseNo: "DON20241218001",
          name: "李四",
          sex: "0",
          age: 45,
          bloodType: "O",
          gscScore: "3",
          diagnosisname: "急性心肌梗死,心脏功能衰竭",
          treatmenthospitalname: "青岛市立医院",
          reportStatus: "3",
          reporttime: "2024-12-18 14:20:00",
          approvetime: "2024-12-18 16:30:00",
          reportername: "刘医生",
          approvername: "审核专员A",
          approveopinion: "资料齐全,符合捐献条件,同意通过。"
        }
      ];
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    /** æœç´¢æŒ‰é’®æ“ä½œ */
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
    /** è¯¦æƒ…按钮操作 */
    handleDetail(row) {
      this.currentCase = row;
      this.detailTitle = `案例详情 - ${row.donorNo}`;
      this.detailOpen = true;
    async handleDetail(row) {
      try {
        // å…ˆèŽ·å–æ¡ˆä¾‹è¯¦æƒ…
        const response = await donateInfo(row.id);
        this.currentCase = response.data || response || row;
        // å¦‚果状态是"已上报"(1),则使用完整数据更新为"已阅读"(2)
        if (this.currentCase.reportStatus === "1") {
          try {
            // ä½¿ç”¨å®Œæ•´çš„æ¡ˆä¾‹æ•°æ®ä½œä¸ºæ›´æ–°åŸºç¡€ï¼Œç¡®ä¿æ‰€æœ‰å­—段都被保留
            const updateData = {
              ...this.currentCase, // å±•开所有现有字段
              reportStatus: "2", // æ›´æ–°çŠ¶æ€ä¸ºå·²é˜…è¯»
              updateTime: new Date()
                .toISOString()
                .replace("T", " ")
                .substring(0, 19),
              updateBy: "当前用户" // æ·»åŠ æ›´æ–°äººä¿¡æ¯
            };
            await donateEdit(updateData);
            // æ›´æ–°æœ¬åœ°æ•°æ®å’Œå½“前显示的数据
            this.currentCase.reportStatus = "2";
            this.currentCase.updateTime = updateData.updateTime;
            row.reportStatus = "2"; // æ›´æ–°åˆ—表中的状态
            this.$modal.msgSuccess("状态已更新为已阅读");
          } catch (updateError) {
            console.error("状态更新失败:", updateError);
            this.$modal.msgError("状态更新失败,但将继续显示详情");
            // æ›´æ–°å¤±è´¥æ—¶ï¼Œç»§ç»­ä½¿ç”¨åŽŸå§‹çŠ¶æ€æ˜¾ç¤ºè¯¦æƒ…
          }
        }
        this.detailTitle = `案例详情 - ${this.currentCase.caseNo ||
          row.caseNo}`;
        this.detailOpen = true;
      } catch (error) {
        console.error("获取案例详情失败:", error);
        // å¦‚果获取详情失败,使用行数据作为后备
        this.currentCase = row;
        this.detailTitle = `案例详情 - ${row.caseNo}`;
        this.detailOpen = true;
        // å³ä½¿èŽ·å–è¯¦æƒ…å¤±è´¥ï¼Œä¹Ÿå°è¯•æ›´æ–°çŠ¶æ€ï¼ˆä½¿ç”¨è¡Œæ•°æ®ï¼‰
        if (row.reportStatus === "1") {
          try {
            const updateData = {
              id: row.id,
              reportStatus: "2",
              updateTime: new Date()
                .toISOString()
                .replace("T", " ")
                .substring(0, 19),
              updateBy: "当前用户"
              // æ³¨æ„ï¼šè¿™é‡Œåªèƒ½ä¼ é€’部分字段,因为详情获取失败了
            };
            await donateEdit(updateData);
            row.reportStatus = "2";
            this.currentCase.reportStatus = "2";
            this.$modal.msgSuccess("状态已更新为已阅读");
          } catch (updateError) {
            console.error("状态更新失败:", updateError);
          }
        }
      }
    },
    // åœ¨çˆ¶ç»„件中更新审批方法
    handleApprove(row) {
      this.currentCase = row;
      this.approveForm.caseId = row.id;
      this.approveForm.approveResult = "1";
      this.approveForm.approveOpinion = "";
      this.approveOpen = true;
    /** å®¡æ‰¹æŒ‰é’®æ“ä½œ */
    async handleApprove(row) {
      try {
        // å…ˆèŽ·å–æ¡ˆä¾‹è¯¦æƒ…æ•°æ®ï¼Œç¡®ä¿æœ‰å®Œæ•´æ•°æ®
        const response = await donateInfo(row.id);
        this.currentCase = response.data || response || row;
        this.approveForm.id = row.id;
        this.approveForm.approveResult = "3";
        this.approveForm.approveOpinion = "";
        this.$nextTick(() => {
          if (this.$refs.approveForm) {
            this.$refs.approveForm.clearValidate();
          }
        });
        this.approveOpen = true;
      } catch (error) {
        console.error("获取案例详情失败:", error);
        // å¦‚果获取详情失败,使用行数据作为后备
        this.currentCase = row;
        this.approveForm.id = row.id;
        this.approveForm.approveResult = "3";
        this.approveForm.approveOpinion = "";
        this.approveOpen = true;
        this.$modal.msgError("获取详情失败,但已打开审批窗口");
      }
    },
    /** æäº¤å®¡æ‰¹ */
    submitApprove() {
      this.$refs["approveForm"].validate(valid => {
    async submitApprove() {
      try {
        const valid = await this.$refs.approveForm.validate();
        if (valid) {
          // æ¨¡æ‹Ÿå®¡æ‰¹æäº¤
          // ä½¿ç”¨å®Œæ•´çš„æ¡ˆä¾‹æ•°æ®ä½œä¸ºåŸºç¡€ï¼Œç¡®ä¿æ‰€æœ‰å­—段都被保留
          const approveData = {
            ...this.currentCase, // å±•开所有现有字段
            reportStatus: this.approveForm.approveResult,
            approveOpinion: this.approveForm.approveOpinion,
            approvername: "当前用户", // å®žé™…项目中应该获取当前登录用户
            approvetime: new Date()
              .toISOString()
              .replace("T", " ")
              .substring(0, 19),
            updateTime: new Date()
              .toISOString()
              .replace("T", " ")
              .substring(0, 19),
            updateBy: "当前用户"
          };
          // ç§»é™¤å¯èƒ½ä¸éœ€è¦çš„字段(根据实际API需求调整)
          delete approveData.createTime; // åˆ›å»ºæ—¶é—´ä¸åº”被更新
          delete approveData.createBy; // åˆ›å»ºäººä¸åº”变
          await donateEdit(approveData);
          this.$modal.msgSuccess("审批成功");
          this.approveOpen = false;
          // æ›´æ–°æ¡ˆä¾‹çŠ¶æ€
          const caseItem = this.caseList.find(
            item => item.id === this.approveForm.caseId
          );
          if (caseItem) {
            caseItem.status = this.approveForm.approveResult;
            caseItem.approveTime = new Date().toLocaleString();
            caseItem.approverName = "当前用户";
            caseItem.approveOpinion = this.approveForm.approveOpinion;
          }
          this.getList(); // é‡æ–°åŠ è½½åˆ—è¡¨
        }
      });
      } catch (error) {
        console.error("审批失败:", error);
        if (error !== "cancel") {
          this.$modal.msgError("审批失败");
        }
      }
    },
    /** æ–°å¢žæŒ‰é’®æ“ä½œ */
    handleAdd() {
      this.$router.push("/case/add");
    },
    /** åˆ é™¤æŒ‰é’®æ“ä½œ */
    handleDelete(row) {
    async handleDelete(row) {
      const ids = row.id || this.ids;
      this.$modal
        .confirm('是否确认删除住院号为"' + ids + '"的数据项?')
        .then(() => {
          // æ¨¡æ‹Ÿåˆ é™¤æ“ä½œ
          this.caseList = this.caseList.filter(item => !ids.includes(item.id));
          this.total = this.caseList.length;
          this.$modal.msgSuccess("删除成功");
        })
        .catch(() => {});
      try {
        await this.$modal.confirm(
          '是否确认删除案例编号为"' + ids + '"的数据项?'
        );
        await donateDel(ids);
        this.$modal.msgSuccess("删除成功");
        this.getList();
      } catch (error) {
        if (error !== "cancel") {
          console.error("删除失败:", error);
          this.$modal.msgError("删除失败");
        }
      }
    }
  }
};
src/views/business/maintain/index.vue
@@ -49,7 +49,7 @@
            <el-option label="未完成捐献" value="5" />
          </el-select>
        </el-form-item>
        <el-form-item label="录入时间" prop="recordTimeRange">
        <el-form-item label="档案录入时间" prop="recordTimeRange">
          <el-date-picker
            v-model="queryParams.recordTimeRange"
            type="daterange"
@@ -204,7 +204,7 @@
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
        <!-- <el-table-column
          label="护理核查表录入时间"
          align="center"
          prop="lastRecordTime"
@@ -217,7 +217,7 @@
                : "-"
            }}</span>
          </template>
        </el-table-column>
        </el-table-column> -->
        <el-table-column
          label="协调员"
          align="center"
src/views/business/transfer/TransportEdit.vue
@@ -7,7 +7,12 @@
    :close-on-click-modal="false"
    @close="handleClose"
  >
    <el-form ref="editForm" :model="formData" :rules="formRules" label-width="120px">
    <el-form
      ref="editForm"
      :model="formData"
      :rules="formRules"
      label-width="120px"
    >
      <!-- åŸºç¡€ä¿¡æ¯ -->
      <el-card class="form-section" shadow="never">
        <div slot="header" class="section-header">
@@ -17,28 +22,42 @@
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="转运单号" prop="id">
              <el-input v-model="formData.id" :disabled="isEdit" placeholder="系统自动生成" />
            <el-form-item label="转运单号" prop="reportId">
              <el-input
                v-model="formData.reportId"
                :disabled="isEdit"
                placeholder="系统自动生成"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="住院号" prop="caseNo">
              <el-input v-model="formData.caseNo" placeholder="请输入住院号" />
            <el-form-item label="案例编号" prop="caseNo">
              <el-input
                v-model="formData.caseNo"
                placeholder="请输入案例编号"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="捐献者姓名" prop="donorName">
              <el-input v-model="formData.donorName" placeholder="请输入捐献者姓名" />
            <el-form-item label="患者姓名" prop="patName">
              <el-input
                v-model="formData.patName"
                placeholder="请输入患者姓名"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="性别" prop="gender">
              <el-select v-model="formData.gender" placeholder="请选择性别" style="width: 100%">
                <el-option label="男" value="男" />
                <el-option label="女" value="女" />
            <el-form-item label="性别" prop="sex">
              <el-select
                v-model="formData.sex"
                placeholder="请选择性别"
                style="width: 100%"
              >
                <el-option label="男" value="1" />
                <el-option label="女" value="2" />
              </el-select>
            </el-form-item>
          </el-col>
@@ -57,8 +76,38 @@
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="疾病诊断" prop="diagnosis">
              <el-input v-model="formData.diagnosis" placeholder="请输入疾病诊断" />
            <el-form-item label="疾病诊断" prop="diagnosisname">
              <el-input
                v-model="formData.diagnosisname"
                placeholder="请输入疾病诊断名称"
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-card>
      <!-- åŒ»é™¢ä¿¡æ¯ -->
      <el-card class="form-section" shadow="never">
        <div slot="header" class="section-header">
          <i class="el-icon-office-building" style="color: #67C23A; margin-right: 8px;"></i>
          <span>医院信息</span>
        </div>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="治疗医院" prop="treatmentHospitalName">
              <el-input
                v-model="formData.treatmentHospitalName"
                placeholder="请输入治疗医院名称"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="治疗科室" prop="treatmentDeptName">
              <el-input
                v-model="formData.treatmentDeptName"
                placeholder="请输入治疗科室名称"
              />
            </el-form-item>
          </el-col>
        </el-row>
@@ -67,93 +116,228 @@
      <!-- è½¬è¿ä¿¡æ¯ -->
      <el-card class="form-section" shadow="never">
        <div slot="header" class="section-header">
          <i class="el-icon-location-information" style="color: #67C23A; margin-right: 8px;"></i>
          <i class="el-icon-location-information" style="color: #E6A23C; margin-right: 8px;"></i>
          <span>转运信息</span>
        </div>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="出发医院" prop="hospitalName">
              <el-input v-model="formData.hospitalName" placeholder="请输入出发医院" />
            <el-form-item label="出发地点" prop="transportStartPlace">
              <el-input
                v-model="formData.transportStartPlace"
                placeholder="请输入出发地点"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="目的医院" prop="destinationHospital">
              <el-input v-model="formData.destinationHospital" placeholder="请输入目的医院" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="计划转运时间" prop="transportTime">
            <el-form-item label="出发时间" prop="transportStartTime">
              <el-date-picker
                v-model="formData.transportTime"
                v-model="formData.transportStartTime"
                type="datetime"
                placeholder="选择转运时间"
                placeholder="选择出发时间"
                value-format="yyyy-MM-dd HH:mm:ss"
                style="width: 100%"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="负责协调员" prop="coordinator">
              <el-input v-model="formData.coordinator" placeholder="请输入协调员姓名" />
            <el-form-item label="转运状态" prop="transitStatus">
              <el-select
                v-model="formData.transitStatus"
                placeholder="请选择转运状态"
                style="width: 100%"
              >
                <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-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="负责协调员" prop="contactPerson">
              <el-input
                v-model="formData.contactPerson"
                placeholder="请输入协调员姓名"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="出发地点" prop="departureLocation">
          <el-input v-model="formData.departureLocation" placeholder="请输入详细出发地点" />
        </el-form-item>
      </el-card>
      <!-- å›¢é˜Ÿæˆå‘˜ -->
      <!-- åŒ»æŠ¤äººå‘˜ä¿¡æ¯ -->
      <el-card class="form-section" shadow="never">
        <div slot="header" class="section-header">
          <i class="el-icon-user" style="color: #E6A23C; margin-right: 8px;"></i>
          <span>团队成员</span>
          <i class="el-icon-user" style="color: #F56C6C; margin-right: 8px;"></i>
          <span>医护人员信息</span>
        </div>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="急诊科医生" prop="emergencyDoctor">
              <el-input v-model="formData.emergencyDoctor" placeholder="请输入急诊科医生" />
            <el-form-item label="急诊科医生" prop="doctor">
              <el-input
                v-model="formData.doctor"
                placeholder="请输入急诊科医生"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="医生电话" prop="doctorPhone">
              <el-input
                v-model="formData.doctorPhone"
                placeholder="请输入医生手机号"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="护士" prop="nurse">
              <el-input v-model="formData.nurse" placeholder="请输入护士姓名" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="护士电话" prop="nursePhone">
              <el-input
                v-model="formData.nursePhone"
                placeholder="请输入护士手机号"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="司机" prop="driver">
              <el-input v-model="formData.driver" placeholder="请输入司机姓名" />
            <el-form-item label="驾驶员" prop="driver">
              <el-input
                v-model="formData.driver"
                placeholder="请输入驾驶员姓名"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="驾驶员电话" prop="driverPhone">
              <el-input
                v-model="formData.driverPhone"
                placeholder="请输入驾驶员手机号"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="ICU评估医生" prop="icuDoctor">
              <el-input v-model="formData.icuDoctor" placeholder="请输入ICU医生" />
              <el-input
                v-model="formData.icuDoctor"
                placeholder="请输入ICU评估医生"
              />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="ICU医生电话" prop="icuDoctorPhone">
              <el-input
                v-model="formData.icuDoctorPhone"
                placeholder="请输入ICU医生手机号"
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-card>
      <!-- é™„件信息 -->
      <el-card class="form-section" shadow="never">
        <div slot="header" class="section-header">
          <i class="el-icon-folder" style="color: #909399; margin-right: 8px;"></i>
          <span>附件信息</span>
        </div>
        <div class="attachment-section">
          <div class="attachment-header">
            <i class="el-icon-paperclip"></i>
            <span class="attachment-title">附件上传</span>
            <span class="attachment-tip">支持上传检验报告单等文件 (最多{{ attachmentLimit }}个)</span>
          </div>
          <!-- ä½¿ç”¨ UploadAttachment ç»„ä»¶ -->
          <UploadAttachment
            ref="uploadAttachment"
            :file-list="attachmentFileList"
            :limit="attachmentLimit"
            :accept="attachmentAccept"
            @change="handleAttachmentChange"
            @upload-success="handleUploadSuccess"
            @upload-error="handleUploadError"
            @remove="handleAttachmentRemove"
          />
        </div>
        <!-- é™„件列表 -->
        <div class="attachment-list" v-if="formData.annexfilesList && formData.annexfilesList.length > 0">
          <div class="list-title">已上传附件 ({{ formData.annexfilesList.length }})</div>
          <el-table :data="formData.annexfilesList" style="width: 100%" size="small">
            <el-table-column label="文件名" min-width="200">
              <template slot-scope="scope">
                <i class="el-icon-document" style="margin-right: 8px; color: #409EFF;"></i>
                <span class="file-name">{{ scope.row.fileName }}</span>
              </template>
            </el-table-column>
            <el-table-column label="文件类型" width="100">
              <template slot-scope="scope">
                <el-tag size="small">{{ getFileType(scope.row.fileName) }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column label="创建时间" width="160">
              <template slot-scope="scope">
                <span>{{ formatDateTime(scope.row.createTime) }}</span>
              </template>
            </el-table-column>
            <el-table-column label="操作" width="180">
              <template slot-scope="scope">
                <el-button
                  size="mini"
                  type="primary"
                  @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="handleRemoveAttachment(scope.$index)"
                >
                  åˆ é™¤
                </el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </el-card>
      <!-- å¤‡æ³¨ä¿¡æ¯ -->
      <el-card class="form-section" shadow="never">
        <div slot="header" class="section-header">
          <i class="el-icon-edit" style="color: #909399; margin-right: 8px;"></i>
          <i class="el-icon-edit" style="color: #409EFF; margin-right: 8px;"></i>
          <span>备注信息</span>
        </div>
        <el-form-item prop="remarks">
        <el-form-item prop="remark">
          <el-input
            v-model="formData.remarks"
            v-model="formData.remark"
            type="textarea"
            :rows="4"
            placeholder="请输入转运备注信息"
            placeholder="请输入备注信息"
            maxlength="500"
            show-word-limit
          />
@@ -165,12 +349,29 @@
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" :loading="saveLoading" @click="handleSave">保存</el-button>
    </div>
    <!-- æ–‡ä»¶é¢„览弹窗 -->
    <FilePreviewDialog
      :visible="previewVisible"
      :file="currentPreviewFile"
      @close="previewVisible = false"
      @download="handleDownload"
    />
  </el-dialog>
</template>
<script>
import { transportAdd, transportEdit } from "@/api/businessApi/index";
import UploadAttachment from "@/components/UploadAttachment";
import FilePreviewDialog from "@/components/FilePreviewDialog";
import dayjs from "dayjs";
export default {
  name: "TransportEdit",
  components: {
    UploadAttachment,
    FilePreviewDialog
  },
  props: {
    editOpen: {
      type: Boolean,
@@ -188,34 +389,38 @@
  data() {
    return {
      saveLoading: false,
      // é¢„览相关
      previewVisible: false,
      currentPreviewFile: null,
      // é™„件相关配置
      attachmentLimit: 10,
      attachmentAccept: ".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx",
      attachmentFileList: [],
      // è¡¨å•数据
      formData: this.getDefaultFormData(),
      formRules: {
        caseNo: [
          { required: true, message: '请输入住院号', trigger: 'blur' }
          { required: true, message: "请输入案例编号", trigger: "blur" }
        ],
        donorName: [
          { required: true, message: '请输入捐献者姓名', trigger: 'blur' }
        patName: [
          { required: true, message: "请输入患者姓名", trigger: "blur" }
        ],
        gender: [
          { required: true, message: '请选择性别', trigger: 'change' }
        sex: [{ required: true, message: "请选择性别", trigger: "change" }],
        age: [{ required: true, message: "请输入年龄", trigger: "blur" }],
        diagnosisname: [
          { required: true, message: "请输入疾病诊断名称", trigger: "blur" }
        ],
        age: [
          { required: true, message: '请输入年龄', trigger: 'blur' }
        treatmentHospitalName: [
          { required: true, message: "请输入治疗医院名称", trigger: "blur" }
        ],
        diagnosis: [
          { required: true, message: '请输入疾病诊断', trigger: 'blur' }
        transportStartPlace: [
          { required: true, message: "请输入出发地点", trigger: "blur" }
        ],
        hospitalName: [
          { required: true, message: '请输入出发医院', trigger: 'blur' }
        transportStartTime: [
          { required: true, message: "请选择出发时间", trigger: "change" }
        ],
        destinationHospital: [
          { required: true, message: '请输入目的医院', trigger: 'blur' }
        ],
        transportTime: [
          { required: true, message: '请选择转运时间', trigger: 'change' }
        ],
        coordinator: [
          { required: true, message: '请输入负责协调员', trigger: 'blur' }
        contactPerson: [
          { required: true, message: "请输入负责协调员", trigger: "blur" }
        ]
      }
    };
@@ -223,9 +428,11 @@
  watch: {
    editOpen(val) {
      if (val) {
        this.formData = this.isEdit ?
          { ...this.transportData } :
          this.getDefaultFormData();
        this.formData = this.isEdit
          ? { ...this.getDefaultFormData(), ...this.transportData }
          : this.getDefaultFormData();
        this.initAttachmentList();
        this.$nextTick(() => {
          this.$refs.editForm && this.$refs.editForm.clearValidate();
@@ -234,32 +441,179 @@
    }
  },
  methods: {
    /** èŽ·å–é»˜è®¤è¡¨å•æ•°æ® */
    getDefaultFormData() {
      return {
        id: '',
        caseNo: '',
        donorName: '',
        gender: '',
        age: null,
        diagnosis: '',
        hospitalName: '',
        destinationHospital: '',
        transportTime: '',
        coordinator: '',
        departureLocation: '',
        emergencyDoctor: '',
        nurse: '',
        driver: '',
        icuDoctor: '',
        remarks: '',
        status: 'pending',
        statusText: '待出发'
        id: undefined,
        reportId: undefined,
        caseNo: undefined,
        patName: undefined,
        sex: undefined,
        age: undefined,
        diagnosisname: undefined,
        treatmentHospitalName: undefined,
        treatmentDeptName: undefined,
        transportStartPlace: undefined,
        transportStartTime: undefined,
        contactPerson: undefined,
        transitStatus: 1,
        doctor: undefined,
        doctorPhone: undefined,
        nurse: undefined,
        nursePhone: undefined,
        driver: undefined,
        driverPhone: undefined,
        icuDoctor: undefined,
        icuDoctorPhone: undefined,
        annexfilesList: [],
        remark: undefined,
        createBy: undefined,
        createTime: undefined,
        updateBy: undefined,
        updateTime: undefined,
        delFlag: 0
      };
    },
    /** åˆå§‹åŒ–附件列表 */
    initAttachmentList() {
      if (this.isEdit && this.transportData.annexfilesList) {
        this.formData.annexfilesList = [...this.transportData.annexfilesList];
        this.attachmentFileList = this.transportData.annexfilesList.map(item => ({
          uid: item.id || Math.random(),
          name: item.fileName,
          url: item.path || item.fileUrl,
          status: 'success'
        }));
      } else {
        this.formData.annexfilesList = [];
        this.attachmentFileList = [];
      }
    },
    /** é™„件变化处理 */
    handleAttachmentChange(fileList) {
      this.attachmentFileList = fileList;
    },
    /** é™„件移除处理 */
    handleAttachmentRemove(file) {
      if (file.url) {
        const index = this.formData.annexfilesList.findIndex(item =>
          item.path === file.url || item.fileUrl === file.url
        );
        if (index > -1) {
          this.formData.annexfilesList.splice(index, 1);
        }
      }
    },
    /** æ‰‹åŠ¨åˆ é™¤é™„ä»¶ */
    handleRemoveAttachment(index) {
      this.formData.annexfilesList.splice(index, 1);
      this.attachmentFileList.splice(index, 1);
      this.$message.success('附件删除成功');
    },
    /** ä¸Šä¼ æˆåŠŸå¤„ç† */
    handleUploadSuccess({ file, fileList, response }) {
      if (response.code === 200) {
        const attachmentObj = {
          fileName: file.name,
          path: response.data || file.url,
          fileUrl: response.data || file.url,
          type: this.getFileExtension(file.name),
          createTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
          transportId: this.formData.id,
          delFlag: 0,
          caseNo:this.formData.caseNo
        };
        this.formData.annexfilesList.push(attachmentObj);
        this.$message.success('文件上传成功');
      }
    },
    /** ä¸Šä¼ é”™è¯¯å¤„理 */
    handleUploadError({ file, fileList, error }) {
      console.error('附件上传失败:', error);
      this.$message.error('文件上传失败,请重试');
    },
    /** æ–‡ä»¶é¢„览 */
    handlePreview(file) {
      this.currentPreviewFile = {
        fileName: file.fileName,
        fileUrl: file.path || file.fileUrl,
        fileType: this.getFileType(file.fileName)
      };
      this.previewVisible = true;
    },
    /** æ–‡ä»¶ä¸‹è½½ */
    handleDownload(file) {
      const fileUrl = file.path || file.fileUrl;
      const fileName = file.fileName;
      if (fileUrl) {
        const link = document.createElement('a');
        link.href = fileUrl;
        link.download = fileName;
        link.style.display = 'none';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        this.$message.success('开始下载文件');
      } else {
        this.$message.warning('文件路径不存在,无法下载');
      }
    },
    /** èŽ·å–æ–‡ä»¶ç±»åž‹ */
    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', 'ppt', 'pptx'];
      if (imageTypes.includes(extension)) return 'image';
      if (pdfTypes.includes(extension)) return 'pdf';
      if (officeTypes.includes(extension)) return 'office';
      return 'other';
    },
    /** èŽ·å–æ–‡ä»¶æ‰©å±•å */
    getFileExtension(filename) {
      return filename.split('.').pop().toLowerCase();
    },
    /** æ—¥æœŸæ—¶é—´æ ¼å¼åŒ– */
    formatDateTime(dateTime) {
      if (!dateTime) return '';
      try {
        const date = new Date(dateTime);
        if (isNaN(date.getTime())) return dateTime;
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');
        const seconds = String(date.getSeconds()).padStart(2, '0');
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
      } catch (error) {
        return dateTime;
      }
    },
    handleClose() {
      this.$emit('update:editOpen', false);
      this.$emit('close');
      this.$emit("update:editOpen", false);
      this.$emit("close");
      this.previewVisible = false;
    },
    async handleSave() {
@@ -267,18 +621,33 @@
        const valid = await this.$refs.editForm.validate();
        if (!valid) return;
        const pendingFiles = this.attachmentFileList.filter(item => item.status !== 'success');
        if (pendingFiles.length > 0) {
          this.$message.warning('还有文件未上传完成,请先上传所有文件或移除未上传的文件');
          return;
        }
        this.saveLoading = true;
        // æ¨¡æ‹ŸAPI调用
        await new Promise(resolve => setTimeout(resolve, 1000));
        const requestData = { ...this.formData };
        let response;
        this.$message.success(this.isEdit ? '修改成功' : '新建成功');
        this.handleClose();
        this.$emit('save-success');
        if (this.isEdit) {
          response = await transportEdit(requestData);
        } else {
          response = await transportAdd(requestData);
        }
        if (response.code === 200) {
          this.$message.success(this.isEdit ? "修改成功" : "新建成功");
          this.handleClose();
          this.$emit("save-success");
        } else {
          this.$message.error(response.msg || "操作失败");
        }
      } catch (error) {
        console.error('保存失败:', error);
        this.$message.error('操作失败');
        console.error("保存失败:", error);
        this.$message.error("操作失败,请稍后重试");
      } finally {
        this.saveLoading = false;
      }
@@ -304,6 +673,47 @@
  padding: 20px 0 0;
}
.attachment-section {
  margin-bottom: 16px;
}
.attachment-header {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
  padding: 8px 0;
  border-bottom: 1px solid #ebeef5;
}
.attachment-title {
  font-weight: bold;
  margin: 0 8px;
}
.attachment-tip {
  font-size: 12px;
  color: #909399;
}
.attachment-list {
  margin-top: 16px;
}
.list-title {
  font-weight: bold;
  margin-bottom: 12px;
  color: #303133;
}
.file-name {
  font-size: 13px;
}
.file-path {
  font-size: 12px;
  color: #909399;
}
::v-deep .el-card__header {
  background: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
src/views/business/transfer/index.vue
@@ -8,45 +8,37 @@
        :inline="true"
        label-width="80px"
      >
        <el-form-item label="转运单号" prop="transportNo">
          <el-input
            v-model="queryParams.transportNo"
            placeholder="请输入转运单号"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="住院号" prop="caseNo">
        <el-form-item label="案例编号" prop="caseNo">
          <el-input
            v-model="queryParams.caseNo"
            placeholder="请输入住院号"
            placeholder="请输入案例编号"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="捐献者姓名" prop="donorName">
        <el-form-item label="患者姓名" prop="patName">
          <el-input
            v-model="queryParams.donorName"
            placeholder="请输入捐献者姓名"
            v-model="queryParams.patName"
            placeholder="请输入患者姓名"
            clearable
            style="width: 200px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item label="转运状态" prop="status">
        <el-form-item label="转运状态" prop="transitStatus">
          <el-select
            v-model="queryParams.status"
            v-model="queryParams.transitStatus"
            placeholder="转运状态"
            clearable
            style="width: 200px"
          >
            <el-option label="全部" value="" />
            <el-option label="待出发" value="pending" />
            <el-option label="转运中" value="transporting" />
            <el-option label="已完成" value="completed" />
            <el-option label="已取消" value="cancelled" />
            <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-select>
        </el-form-item>
        <el-form-item label="创建时间">
@@ -148,7 +140,7 @@
      ></right-toolbar>
    </el-row>
    <!-- æ•°æ®è¡¨æ ¼ -->
    <!-- æ•°æ®è¡¨æ ¼ - ç›´æŽ¥ä½¿ç”¨åŽç«¯è¿”回的数据结构 -->
    <el-table
      v-loading="loading"
      :data="transportList"
@@ -156,19 +148,28 @@
    >
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="序号" type="index" width="60" align="center" />
      <el-table-column label="转运单号" align="center" prop="id" width="140" />
      <el-table-column
        label="住院号"
        label="转运单号"
        align="center"
        prop="reportId"
        width="140"
      />
      <el-table-column
        label="案例编号"
        align="center"
        prop="caseNo"
        width="140"
      />
      <el-table-column label="捐献者信息" align="center" width="180">
      <el-table-column label="患者信息" align="center" width="260">
        <template slot-scope="scope">
          <div class="donor-info">
            <div class="donor-name">{{ scope.row.donorName }}</div>
            <div class="donor-name">{{ scope.row.patName }}</div>
            <div class="donor-details">
              {{ scope.row.gender }} | {{ scope.row.age }}岁
              <dict-tag
                :options="dict.type.sys_user_sex"
                :value="parseInt(scope.row.sex)"
              />
              | {{ scope.row.age }}岁
            </div>
          </div>
        </template>
@@ -176,37 +177,37 @@
      <el-table-column
        label="疾病诊断"
        align="center"
        prop="diagnosis"
        prop="diagnosisname"
        min-width="200"
        show-overflow-tooltip
      />
      <el-table-column
        label="医疗机构"
        label="治疗医院"
        align="center"
        prop="hospitalName"
        prop="treatmentHospitalName"
        width="150"
      />
      <el-table-column
        label="计划转运时间"
        align="center"
        prop="transportTime"
        prop="transportStartTime"
        width="160"
      />
      <el-table-column
        label="负责协调员"
        align="center"
        prop="coordinator"
        prop="contactPerson"
        width="100"
      />
      <el-table-column
        label="转运状态"
        align="center"
        prop="status"
        prop="transitStatus"
        width="100"
      >
        <template slot-scope="scope">
          <el-tag :type="scope.row.status | statusFilter">
            {{ scope.row.statusText }}
          <el-tag :type="getStatusTagType(scope.row.transitStatus)">
            {{ getStatusText(scope.row.transitStatus) }}
          </el-tag>
        </template>
      </el-table-column>
@@ -242,7 +243,7 @@
            type="text"
            icon="el-icon-video-play"
            @click="handleStartTransport(scope.row)"
            v-if="scope.row.status === 'pending'"
            v-if="scope.row.transitStatus === 1"
            >开始转运</el-button
          >
          <el-button
@@ -250,7 +251,7 @@
            type="text"
            icon="el-icon-check"
            @click="handleCompleteTransport(scope.row)"
            v-if="scope.row.status === 'transporting'"
            v-if="scope.row.transitStatus === 2"
            >完成转运</el-button
          >
        </template>
@@ -296,7 +297,11 @@
      append-to-body
    >
      <div class="action-confirm">
        <p>确定要{{ actionText }}转运单 "{{ currentTransport.id }}" å—?</p>
        <p>
          ç¡®å®šè¦{{ actionText }}转运单 "{{
            currentTransport.reportId || currentTransport.id
          }}" å—?
        </p>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="actionOpen = false">取 æ¶ˆ</el-button>
@@ -308,17 +313,19 @@
<script>
import {
  listTransport,
  getTransport,
  delTransport,
  updateTransportStatus
} from "@/api/system/business";
  transportList,
  transportAdd,
  transportEdit,
  transportDelete,
  transportInfo
} from "@/api/businessApi/index";
import TransportDetail from "./transportDetail";
import TransportEdit from "./TransportEdit";
export default {
  name: "TransportList",
  components: { TransportDetail, TransportEdit },
  dicts: ["sys_user_sex", "sys_BloodType"],
  data() {
    return {
      // é®ç½©å±‚
@@ -333,7 +340,7 @@
      showSearch: true,
      // æ€»æ¡æ•°
      total: 0,
      // è½¬è¿å•表格数据
      // è½¬è¿å•表格数据 - ç›´æŽ¥ä½¿ç”¨åŽç«¯è¿”回的数据结构
      transportList: [],
      // è¯¦æƒ…弹框是否显示
      detailOpen: false,
@@ -358,143 +365,101 @@
        pendingTransports: 0,
        completedTransports: 0
      },
      // æŸ¥è¯¢å‚æ•°
      // æŸ¥è¯¢å‚数(完全适配后端接口)
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        transportNo: undefined,
        caseNo: undefined,
        donorName: undefined,
        status: undefined
        caseNo: undefined, // æ¡ˆä¾‹ç¼–号
        patName: undefined, // æ‚£è€…姓名
        transitStatus: undefined, // è½¬è¿çŠ¶æ€ï¼š1待转运 2转运中 3转运完成 4转运取消 5暂存
        searchValue: undefined, // æœç´¢å€¼
        params: {} // å…¶ä»–参数对象
      }
    };
  },
  filters: {
    statusFilter(status) {
      const statusMap = {
        pending: "warning",
        transporting: "primary",
        completed: "success",
        cancelled: "danger"
      };
      return statusMap[status];
    }
  },
  created() {
    this.getList();
  },
  methods: {
    /** æŸ¥è¯¢è½¬è¿å•列表 */
    getList() {
    /** æŸ¥è¯¢è½¬è¿å•列表 - ç›´æŽ¥ä½¿ç”¨åŽç«¯æ•°æ®ç»“æž„ */
    async getList() {
      this.loading = true;
      // æ¨¡æ‹ŸAPI调用延迟
      setTimeout(() => {
        // æµ‹è¯•数据
        this.transportList = [
          {
            id: "T20241217001",
            caseNo: "DON20241216001",
            donorName: "张三",
            gender: "男",
            age: 38,
            diagnosis:
              "脑外伤导致脑死亡,经抢救无效宣布脑死亡。家属同意器官捐献。",
            hospitalName: "青岛镜湖医院",
            transportTime: "2024-12-17 14:30:00",
            coordinator: "张医生",
            createTime: "2024-12-16 09:30:00",
            status: "pending",
            statusText: "待出发",
            departureLocation: "青岛市立医院急诊科",
            destinationHospital: "青岛镜湖医院",
            emergencyDoctor: "王医生",
            nurse: "李护士",
            driver: "刘师傅",
            icuDoctor: "赵医生",
            contacts: [
              { role: "协调员电话", phone: "13800138000" },
              { role: "急诊医生电话", phone: "13800138001" },
              { role: "护士电话", phone: "13800138002" },
              { role: "司机电话", phone: "13800138003" },
              { role: "ICU医生电话", phone: "13800138004" }
            ],
            remarks: "需要准备呼吸机等急救设备"
          },
          {
            id: "T20241217002",
            caseNo: "DON20241216002",
            donorName: "李四",
            gender: "女",
            age: 45,
            diagnosis: "脑梗死,脑干功能丧失",
            hospitalName: "青岛大学附属医院",
            transportTime: "2024-12-17 16:00:00",
            coordinator: "李医生",
            createTime: "2024-12-16 11:20:00",
            status: "transporting",
            statusText: "转运中",
            departureLocation: "青岛大学附属医院ICU",
            destinationHospital: "青岛器官移植中心",
            currentLocation: "青岛市南区香港中路",
            estimatedTime: "30分钟"
          },
          {
            id: "T20241216003",
            caseNo: "DON20241215001",
            donorName: "王五",
            gender: "男",
            age: 52,
            diagnosis: "心脏骤停,多器官功能衰竭",
            hospitalName: "青岛市立医院",
            transportTime: "2024-12-16 10:15:00",
            coordinator: "王医生",
            createTime: "2024-12-15 14:45:00",
            status: "completed",
            statusText: "已完成",
            departureLocation: "青岛市立医院心内科",
            destinationHospital: "青岛器官移植中心",
            completedTime: "2024-12-16 12:30:00",
            distance: "15公里",
            duration: "2小时15分钟"
          },
          {
            id: "T20241216004",
            caseNo: "DON20241214001",
            donorName: "赵六",
            gender: "女",
            age: 29,
            diagnosis: "急性肝衰竭",
            hospitalName: "青岛科大医院",
            transportTime: "2024-12-16 08:30:00",
            coordinator: "赵医生",
            createTime: "2024-12-14 16:20:00",
            status: "cancelled",
            statusText: "已取消",
            cancelReason: "家属临时改变决定"
          }
        ];
        // æ›´æ–°ç»Ÿè®¡æ•°æ®
        this.updateStats();
        this.total = this.transportList.length;
      try {
        // æž„建符合后端接口的请求参数 [1,2](@ref)
        const requestParams = {
          pageNum: this.queryParams.pageNum,
          pageSize: this.queryParams.pageSize,
          caseNo: this.queryParams.caseNo,
          patName: this.queryParams.patName,
          transitStatus: this.queryParams.transitStatus,
          searchValue: this.queryParams.searchValue
        };
        // å¤„理时间范围参数 [5](@ref)
        if (this.dateRange && this.dateRange.length === 2) {
          requestParams.transportStartTime = this.dateRange.join(",");
        }
        // è°ƒç”¨æ­£å¼æŽ¥å£ [3](@ref)
        const response = await transportList(requestParams);
        if (response.code === 200) {
          // ç›´æŽ¥ä½¿ç”¨åŽç«¯è¿”回的数据结构,不进行转换 [8](@ref)
          this.transportList = response.rows || response.data || [];
          this.total = response.total || 0;
          // æ›´æ–°ç»Ÿè®¡æ•°æ®
          this.updateStats();
        } else {
          this.$modal.msgError(response.msg || "获取转运单列表失败");
        }
      } catch (error) {
        console.error("获取转运单列表失败:", error);
        this.$modal.msgError("网络请求失败,请稍后重试");
      } finally {
        this.loading = false;
      }, 500);
      }
    },
    /** èŽ·å–çŠ¶æ€æ ‡ç­¾ç±»åž‹ */
    getStatusTagType(transitStatus) {
      const statusMap = {
        1: "warning", // å¾…转运
        2: "primary", // è½¬è¿ä¸­
        3: "success", // è½¬è¿å®Œæˆ
        4: "danger", // è½¬è¿å–消
        5: "info" // æš‚å­˜
      };
      return statusMap[transitStatus] || "info";
    },
    /** èŽ·å–çŠ¶æ€æ–‡æœ¬ */
    getStatusText(transitStatus) {
      const statusMap = {
        1: "待转运",
        2: "转运中",
        3: "转运完成",
        4: "转运取消",
        5: "暂存"
      };
      return statusMap[transitStatus] || "未知状态";
    },
    // æ›´æ–°ç»Ÿè®¡æ•°æ®
    updateStats() {
      this.stats.totalTransports = this.transportList.length;
      this.stats.pendingTransports = this.transportList.filter(
        item => item.status === "pending"
        item => item.transitStatus === 1
      ).length;
      this.stats.completedTransports = this.transportList.filter(
        item => item.status === "completed"
        item => item.transitStatus === 3
      ).length;
    },
    // å¤šé€‰æ¡†é€‰ä¸­æ•°æ®
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.ids = selection.map(item => item.reportId || item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
@@ -504,6 +469,28 @@
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.dateRange = [];
      this.queryParams = {
        pageNum: 1,
        pageSize: 10,
        caseNo: undefined,
        patName: undefined,
        transitStatus: undefined,
        searchValue: undefined
      };
      this.getList();
    },
    /** è¯¦æƒ…按钮操作 */
    handleDetail(row) {
      this.currentTransport = row;
      this.detailTitle = `转运单详情 - ${row.reportId || row.id}`;
      this.detailOpen = true;
    },
    /** ä¿®æ”¹æŒ‰é’®æ“ä½œ */
    handleUpdate(row) {
      this.currentTransport = row || {};
@@ -528,22 +515,9 @@
    handleSaveSuccess() {
      this.getList(); // é‡æ–°åŠ è½½åˆ—è¡¨
    },
    /** é‡ç½®æŒ‰é’®æ“ä½œ */
    resetQuery() {
      this.dateRange = [];
      this.resetForm("queryForm");
      this.handleQuery();
    },
    /** è¯¦æƒ…按钮操作 */
    handleDetail(row) {
      this.currentTransport = row;
      this.detailTitle = `转运单详情 - ${row.id}`;
      this.detailOpen = true;
    },
    /** å¼€å§‹è½¬è¿æ“ä½œ */
    handleStartTransport(row) {
    async handleStartTransport(row) {
      this.currentTransport = row;
      this.actionTitle = "开始转运";
      this.actionText = "开始";
@@ -551,59 +525,70 @@
    },
    /** å®Œæˆè½¬è¿æ“ä½œ */
    handleCompleteTransport(row) {
    async handleCompleteTransport(row) {
      this.currentTransport = row;
      this.actionTitle = "完成转运";
      this.actionText = "完成";
      this.actionOpen = true;
    },
    /** ç¡®è®¤æ“ä½œ */
    confirmAction() {
      const index = this.transportList.findIndex(
        item => item.id === this.currentTransport.id
      );
      if (index !== -1) {
    /** ç¡®è®¤æ“ä½œ - ä½¿ç”¨åŽç«¯åŽŸå§‹æ•°æ®ç»“æž„ [4](@ref) */
    async confirmAction() {
      try {
        let requestData = {
          id: this.currentTransport.id || this.currentTransport.reportId
        };
        if (this.actionText === "开始") {
          this.transportList[index].status = "transporting";
          this.transportList[index].statusText = "转运中";
          requestData.transitStatus = 2; // è®¾ç½®ä¸ºè½¬è¿ä¸­
        } else if (this.actionText === "完成") {
          this.transportList[index].status = "completed";
          this.transportList[index].statusText = "已完成";
          this.transportList[index].completedTime = new Date().toLocaleString();
          requestData.transitStatus = 3; // è®¾ç½®ä¸ºè½¬è¿å®Œæˆ
        }
        // æ›´æ–°ç»Ÿè®¡æ•°æ®
        this.updateStats();
        // ç›´æŽ¥ä¼ é€’后端需要的参数 [8](@ref)
        const response = await transportEdit(requestData);
        this.$modal.msgSuccess(`${this.actionText}成功`);
        if (response.code === 200) {
          this.$modal.msgSuccess(`${this.actionText}转运成功`);
          this.getList(); // åˆ·æ–°åˆ—表
        } else {
          this.$modal.msgError(response.msg || `${this.actionText}转运失败`);
        }
      } catch (error) {
        console.error(`${this.actionText}转运失败:`, error);
        this.$modal.msgError("操作失败,请稍后重试");
      }
      this.actionOpen = false;
    },
    /** åˆ é™¤æŒ‰é’®æ“ä½œ - ä½¿ç”¨åŽç«¯åŽŸå§‹ID [1](@ref) */
    async handleDelete(row) {
      const ids = row.reportId || row.id || this.ids;
      try {
        await this.$modal.confirm(
          '是否确认删除转运单编号为"' + ids + '"的数据项?'
        );
        const response = await transportDelete(ids);
    /** åˆ é™¤æŒ‰é’®æ“ä½œ */
    handleDelete(row) {
      const ids = row.id || this.ids;
      this.$modal
        .confirm('是否确认删除转运单编号为"' + ids + '"的数据项?')
        .then(() => {
          // æ¨¡æ‹Ÿåˆ é™¤æ“ä½œ
          this.transportList = this.transportList.filter(
            item => !ids.includes(item.id)
          );
          this.total = this.transportList.length;
          this.updateStats();
        if (response.code === 200) {
          this.$modal.msgSuccess("删除成功");
        })
        .catch(() => {});
          this.getList(); // åˆ·æ–°åˆ—表
        } else {
          this.$modal.msgError(response.msg || "删除失败");
        }
      } catch (error) {
        if (error !== "cancel") {
          console.error("删除失败:", error);
          this.$modal.msgError("删除失败,请稍后重试");
        }
      }
    },
    /** å¯¼å‡ºæŒ‰é’®æ“ä½œ */
    handleExport() {
      // ç›´æŽ¥ä½¿ç”¨åŽç«¯å‚数结构进行导出 [5](@ref)
      this.download(
        "system/transport/export",
        {
@@ -675,7 +660,9 @@
}
.donor-info {
  text-align: left;
  text-align: center;
  display: flex;
  justify-content: center
}
.donor-name {
@@ -684,8 +671,10 @@
}
.donor-details {
  font-size: 12px;
  color: #909399;
  margin-left: 5px;
  font-size: 16px;
  color: #093ca4;
  display: flex;
}
.mb8 {
src/views/business/transfer/transportDetail.vue
@@ -3,84 +3,145 @@
    <!-- åŸºç¡€ä¿¡æ¯æ¨¡å— -->
    <el-card class="detail-section">
      <div slot="header" class="section-header">
        <i class="el-icon-document" style="color: #409EFF; margin-right: 8px;"></i>
        <i
          class="el-icon-document"
          style="color: #409EFF; margin-right: 8px;"
        ></i>
        <span class="section-title">基础信息</span>
      </div>
      <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="转运单号">{{
          transportData.reportId || transportData.id
        }}</el-descriptions-item>
        <el-descriptions-item label="案例编号">{{
          transportData.caseNo
        }}</el-descriptions-item>
        <el-descriptions-item label="患者姓名">{{
          transportData.patName
        }}</el-descriptions-item>
        <el-descriptions-item label="性别">
          <dict-tag
            :options="dict.type.sys_user_sex"
            :value="parseInt(transportData.sex)"
          />
        </el-descriptions-item>
        <el-descriptions-item label="年龄"
          >{{ transportData.age }}岁</el-descriptions-item
        >
        <el-descriptions-item label="疾病诊断">{{
          transportData.diagnosisname
        }}</el-descriptions-item>
        <el-descriptions-item label="治疗医院">{{
          transportData.treatmentHospitalName
        }}</el-descriptions-item>
        <el-descriptions-item label="治疗科室">{{
          transportData.treatmentDeptName
        }}</el-descriptions-item>
        <el-descriptions-item label="出发地点">{{
          transportData.transportStartPlace
        }}</el-descriptions-item>
        <el-descriptions-item label="计划转运时间">{{
          transportData.transportStartTime
        }}</el-descriptions-item>
        <el-descriptions-item label="负责协调员">{{
          transportData.contactPerson
        }}</el-descriptions-item>
        <el-descriptions-item label="转运状态">
          <el-tag :type="transportData.status | statusFilter">
            {{ transportData.statusText }}
          <el-tag :type="getStatusTagType(transportData.transitStatus)">
            {{ getStatusText(transportData.transitStatus) }}
          </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-item label="创建时间">{{
          transportData.createTime
        }}</el-descriptions-item>
        <el-descriptions-item label="更新时间">{{
          transportData.updateTime
        }}</el-descriptions-item>
      </el-descriptions>
    </el-card>
    <!-- è½¬è¿è¯¦æƒ…模块 -->
    <el-card class="detail-section">
      <div slot="header" class="section-header">
        <i class="el-icon-location-information" style="color: #67C23A; margin-right: 8px;"></i>
        <i
          class="el-icon-location-information"
          style="color: #67C23A; margin-right: 8px;"
        ></i>
        <span class="section-title">转运详情</span>
      </div>
      <el-descriptions :column="2" 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 label="出发地点">{{
          transportData.transportStartPlace
        }}</el-descriptions-item>
        <el-descriptions-item label="目的医院">{{
          transportData.treatmentHospitalName
        }}</el-descriptions-item>
        <el-descriptions-item label="治疗科室">{{
          transportData.treatmentDeptName
        }}</el-descriptions-item>
        <el-descriptions-item label="出发时间">{{
          transportData.transportStartTime
        }}</el-descriptions-item>
        <el-descriptions-item label="转运状态">
          <el-tag :type="getStatusTagType(transportData.transitStatus)">
            {{ getStatusText(transportData.transitStatus) }}
          </el-tag>
        </el-descriptions-item>
      </el-descriptions>
    </el-card>
    <!-- å›¢é˜Ÿæˆå‘˜æ¨¡å— -->
    <!-- åŒ»æŠ¤äººå‘˜ä¿¡æ¯æ¨¡å— -->
    <el-card class="detail-section">
      <div slot="header" class="section-header">
        <i class="el-icon-user" style="color: #E6A23C; margin-right: 8px;"></i>
        <span class="section-title">团队成员</span>
        <span class="section-title">医护人员信息</span>
      </div>
      <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-item label="协调员">{{
          transportData.contactPerson
        }}</el-descriptions-item>
        <el-descriptions-item label="协调员电话">{{
          transportData.contactPhone || "未填写"
        }}</el-descriptions-item>
        <el-descriptions-item label="急诊科医生">{{
          transportData.doctor
        }}</el-descriptions-item>
        <el-descriptions-item label="急诊医生电话">{{
          transportData.doctorPhone
        }}</el-descriptions-item>
        <el-descriptions-item label="护士">{{
          transportData.nurse
        }}</el-descriptions-item>
        <el-descriptions-item label="护士电话">{{
          transportData.nursePhone
        }}</el-descriptions-item>
        <el-descriptions-item label="驾驶员">{{
          transportData.driver
        }}</el-descriptions-item>
        <el-descriptions-item label="驾驶员电话">{{
          transportData.driverPhone
        }}</el-descriptions-item>
        <el-descriptions-item label="ICU评估医生">{{
          transportData.icuDoctor
        }}</el-descriptions-item>
        <el-descriptions-item label="ICU医生电话">{{
          transportData.icuDoctorPhone
        }}</el-descriptions-item>
      </el-descriptions>
    </el-card>
    <!-- é™„件信息模块 -->
    <el-card class="detail-section" v-if="attachmentList.length > 0">
    <el-card
      class="detail-section"
      v-if="
        transportData.annexfilesList && transportData.annexfilesList.length > 0
      "
    >
      <div slot="header" class="section-header">
        <i class="el-icon-folder" style="color: #F56C6C; margin-right: 8px;"></i>
        <i
          class="el-icon-folder"
          style="color: #F56C6C; margin-right: 8px;"
        ></i>
        <span class="section-title">附件信息</span>
      </div>
      <el-table :data="attachmentList" style="width: 100%">
@@ -92,41 +153,41 @@
        </el-table-column>
        <el-table-column label="文件类型" width="120">
          <template slot-scope="scope">
            <el-tag size="small">{{ scope.row.fileType }}</el-tag>
            <el-tag size="small">{{ scope.row.type }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="大小" width="100">
        <el-table-column label="文件地址" min-width="200" show-overflow-tooltip>
          <template slot-scope="scope">
            <span>{{ formatFileSize(scope.row.fileSize) }}</span>
            <span>{{ scope.row.path }}</span>
          </template>
        </el-table-column>
        <el-table-column label="上传时间" width="180">
        <el-table-column label="操作" width="200">
          <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>
            <el-button size="mini" @click="handlePreview(scope.row)"
              >预览</el-button
            >
            <el-button
              size="mini"
              type="success"
              @click="handleDownload(scope.row)"
              >下载</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <!-- å¤‡æ³¨ä¿¡æ¯æ¨¡å— -->
    <el-card class="detail-section" v-if="transportData.remarks">
    <el-card class="detail-section" v-if="transportData.remark">
      <div slot="header" class="section-header">
        <i class="el-icon-edit" style="color: #909399; margin-right: 8px;"></i>
        <span class="section-title">备注信息</span>
      </div>
      <div class="remarks-content">
        {{ transportData.remarks }}
        {{ transportData.remark }}
      </div>
    </el-card>
    <!-- é¢„览弹窗(保持不变) -->
    <!-- PDF预览弹窗 -->
    <el-dialog
      :title="previewTitle"
@@ -139,7 +200,6 @@
      @close="handlePdfDialogClose"
    >
      <div class="pdf-preview-container" v-loading="pdfLoading">
        <!-- PDF控制工具栏 -->
        <div class="pdf-toolbar">
          <el-button-group>
            <el-button
@@ -186,7 +246,6 @@
          </el-button>
        </div>
        <!-- PDF渲染区域 -->
        <div class="pdf-viewport">
          <pdf
            ref="pdf"
@@ -251,58 +310,27 @@
<script>
import pdf from "vue-pdf";
import UploadAttachment from "@/components/UploadAttachment";
export default {
  name: "TransportDetail",
  components: {
    pdf
  },
  components: {
    UploadAttachment
  },
  dicts: ["sys_user_sex"],
  props: {
    transportData: {
      type: Object,
      default: () => ({})
    }
  },
  filters: {
    statusFilter(status) {
      const statusMap = {
        pending: "warning",
        transporting: "primary",
        completed: "success",
        cancelled: "danger"
      };
      return statusMap[status];
    }
  },
  data() {
    return {
      // é™„件相关数据
      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"
        }
      ],
      attachmentList: [],
      // PDF预览相关数据
      pdfPreviewVisible: false,
      pdfLoading: false,
@@ -311,34 +339,80 @@
      pageCount: 0,
      scale: 100,
      pageRotate: 0,
      // å›¾ç‰‡é¢„览相关
      imagePreviewVisible: false,
      // ä¸æ”¯æŒé¢„览相关
      unsupportedPreviewVisible: false,
      // é€šç”¨é¢„览数据
      previewTitle: "",
      previewUrl: "",
      currentFile: null
    };
  },
  watch: {
    transportData: {
      handler(newVal) {
        this.transformAttachmentData(newVal.annexfilesList);
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    // èŽ·å–è”ç³»æ–¹å¼
    getContactPhone(role) {
      if (this.transportData.contacts) {
        const contact = this.transportData.contacts.find(
          item => item.role === role
        );
        return contact ? contact.phone : "未填写";
    /** è½¬æ¢é™„件数据 */
    transformAttachmentData(annexfilesList) {
      if (!annexfilesList || !Array.isArray(annexfilesList)) {
        this.attachmentList = [];
        return;
      }
      return "未填写";
      this.attachmentList = annexfilesList;
      // this.attachmentList = annexfilesList.map((fileUrl, index) => {
      //   const fileName = this.getFileNameFromUrl(fileUrl);
      //   return {
      //     id: index + 1,
      //     fileName: fileName,
      //     fileType: this.getFileType(fileName),
      //     fileUrl: fileUrl
      //   };
      // });
    },
    /** ä»ŽURL中提取文件名 */
    getFileNameFromUrl(url) {
      if (!url) return "未知文件";
      return url.split("/").pop() || "未知文件";
    },
    /** èŽ·å–çŠ¶æ€æ ‡ç­¾ç±»åž‹ */
    getStatusTagType(transitStatus) {
      const statusMap = {
        1: "warning", // å¾…转运
        2: "primary", // è½¬è¿ä¸­
        3: "success", // è½¬è¿å®Œæˆ
        4: "danger", // è½¬è¿å–消
        5: "info" // æš‚å­˜
      };
      return statusMap[transitStatus] || "info";
    },
    /** èŽ·å–çŠ¶æ€æ–‡æœ¬ */
    getStatusText(transitStatus) {
      const statusMap = {
        1: "待转运",
        2: "转运中",
        3: "转运完成",
        4: "转运取消",
        5: "暂存"
      };
      return statusMap[transitStatus] || "未知状态";
    },
    // å…³é—­å¼¹æ¡†
    handleClose() {
      this.$emit("close");
    },
    // èŽ·å–æ–‡ä»¶ç±»åž‹
    getFileType(fileName) {
      const extension = fileName
@@ -357,8 +431,9 @@
    handlePreview(file) {
      this.currentFile = file;
      this.previewTitle = `预览 - ${file.fileName}`;
      this.previewUrl = file.fileUrl;
      this.previewUrl = file.path;
      const fileType = this.getFileType(file.fileName);
      console.log(this.previewUrl, "this.previewUrl");
      switch (fileType) {
        case "pdf":
@@ -380,7 +455,7 @@
      this.currentPage = 1;
      this.scale = 100;
      this.pageRotate = 0;
      this.pdfUrl = file.fileUrl;
      this.pdfUrl = file.path;
    },
    // PDF加载完成回调
@@ -444,7 +519,7 @@
    // æ–‡ä»¶ä¸‹è½½
    handleDownload(file) {
      const link = document.createElement("a");
      link.href = file.fileUrl;
      link.href = file.path;
      link.download = file.fileName;
      link.style.display = "none";
      document.body.appendChild(link);
@@ -458,21 +533,8 @@
      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("删除成功");
      });
    },
    formatFileSize(bytes) {
      if (!bytes) return "未知大小";
      if (bytes === 0) return "0 B";
      const k = 1024;
      const sizes = ["B", "KB", "MB", "GB"];
@@ -512,7 +574,7 @@
  white-space: pre-line;
}
/* PDF预览相关样式保持不变 */
/* PDF预览相关样式 */
.pdf-preview-dialog {
  margin-top: 5vh !important;
}
src/views/project/donatebaseinfo/index.vue
@@ -203,9 +203,9 @@
        </template>
      </el-table-column>
      <el-table-column
        label="住院号"
        label="案例编号"
        align="center"
        prop="donorno"
        prop="caseNo"
        width="200"
      />
      <el-table-column label="姓名" align="center" prop="name" width="100" />
@@ -234,6 +234,11 @@
        label="医疗机构"
        align="center"
        prop="treatmenthospitalname"
      />
      <el-table-column
        label="GSC评分"
        align="center"
        prop="gcsScore"
      />
      <el-table-column label="血型" align="center" prop="bloodtype" width="100">
        <template slot-scope="scope">
@@ -373,8 +378,8 @@
        >
          <el-row style="margin-top: 40px">
            <el-col :span="8">
              <el-form-item label="住院号" prop="donorno">
                <el-input v-model="form.donorno" disabled />
              <el-form-item label="案例编号" prop="caseNo">
                <el-input v-model="form.caseNo" disabled />
              </el-form-item>
            </el-col>
            <el-col :span="8">
@@ -609,8 +614,8 @@
        >
          <el-row>
            <el-col :span="8">
              <el-form-item label="住院号" prop="inpatientno">
                <el-input v-model="form.inpatientno" placeholder="住院号" />
              <el-form-item label="案例编号" prop="inpatientno">
                <el-input v-model="form.inpatientno" placeholder="案例编号" />
              </el-form-item>
            </el-col>
            <el-col :span="16">
@@ -931,7 +936,7 @@
        <!-- <div style="padding-right: 60px; margin-top: 20px">
          <el-row>
            <el-form-item label="附件" align="left" prop="annexfile">
              <annex-upload ref="annex" :infoid="form.id" :donorno="form.donorno" :flowname="flowname"
              <annex-upload ref="annex" :infoid="form.id" :caseNo="form.caseNo" :flowname="flowname"
                :annexno="annexno" />
            </el-form-item>
          </el-row>
@@ -1073,7 +1078,7 @@
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        donorno: null,
        caseNo: null,
        recordstate: null,
        // treatmenthospitalno: null,
        treatmenthospitalname: null,
@@ -1142,7 +1147,7 @@
        bloodtype: "0",
        inpatientno: null,
        rhyin: "0",
        donorno: null,
        caseNo: null,
        donationcategory: null,
        illnessoverview: null,
        diseasetype: [],
@@ -1256,7 +1261,7 @@
        ],
        inpatientno: [
          { required: true, message: "输入住院号", trigger: "blur" }
          { required: true, message: "输入案例编号", trigger: "blur" }
        ],
        diagnosisname: [
          { required: true, message: "疾病诊断不能为空", trigger: "blur" }
@@ -1737,7 +1742,7 @@
        bloodtype: "0",
        inpatientno: null,
        rhyin: 0,
        donorno: null,
        caseNo: null,
        donationcategory: null,
        illnessoverview: null,
        diseasetype: [],
@@ -1797,7 +1802,7 @@
        // "2"
        recordstate: null,
        treatmenthospitalname: null,
        donorno: null,
        caseNo: null,
        acquisitiontissueno: null,
        reportername: null,
        reporttime: null,
vue.config.js
@@ -33,8 +33,8 @@
    proxy: {
      // detail: https://cli.vuejs.org/config/#devserver-proxy
      [process.env.VUE_APP_BASE_API]: {
        target:`http://localhost:8080`,
        // target:`http://192.168.100.10:8080`,
        // target:`http://localhost:8080`,
        target:`http://192.168.100.10:8080`,
        // target:`http://192.168.100.137:8080`,
        // target: `https://slb.hospitalstar.com:9093`,
        changeOrigin: true,