WXL
2026-03-13 45680b99ccdfb0d323088c57c237e0bc714a8e0b
src/views/business/maintain/maintainInfo.vue
@@ -53,11 +53,6 @@
          <el-col :span="8">
            <el-form-item label="患者状态" prop="recordstate">
              <el-select v-model="form.recordstate" style="width: 100%">
                <!-- <el-option label="DCD" value="1" />
                <el-option label="DBD" value="2" />
                <el-option label="DBCD" value="3" />
                <el-option label="已完成捐献" value="4" />
                <el-option label="未完成捐献" value="5" /> -->
                <el-option
                  v-for="dict in dict.type.sys_DonationCategory || []"
                  :key="dict.value"
@@ -66,20 +61,6 @@
                ></el-option>
              </el-select>
            </el-form-item>
            <!-- <el-form-item
              align="left"
              label="患者捐献状态"
              prop="donationcategory"
            >
              <el-radio-group v-model="form.recordstate">
                <el-radio
                  v-for="dict in dict.type.sys_DonationCategory || []"
                  :key="dict.value"
                  :label="dict.value"
                  >{{ dict.label }}</el-radio
                >
              </el-radio-group>
            </el-form-item> -->
          </el-col>
          <el-col :span="8">
            <el-form-item
@@ -127,10 +108,6 @@
          <el-col :span="8">
            <el-form-item label="血型" prop="bloodtype">
              <el-select v-model="form.bloodtype" style="width: 100%">
                <!-- <el-option label="A型" value="A" />
                <el-option label="B型" value="B" />
                <el-option label="O型" value="O" />
                <el-option label="AB型" value="AB" /> -->
                <el-option
                  v-for="dict in dict.type.sys_BloodType"
                  :key="dict.value"
@@ -423,9 +400,16 @@
        </el-row>
        <el-form-item label="附件">
          <upload-attachment
            :file-list="cultureForm.attachments"
          <UploadAttachment
            ref="cultureUploadAttachment"
            :file-list="cultureFileList"
            :limit="10"
            :accept="attachmentAccept"
            :multiple="true"
            @change="handleCultureAttachmentChange"
            @upload-success="handleCultureUploadSuccess"
            @upload-error="handleCultureUploadError"
            @remove="handleCultureAttachmentRemove"
          />
        </el-form-item>
      </el-form>
@@ -486,9 +470,16 @@
        </el-form-item>
        <el-form-item label="附件">
          <upload-attachment
            :file-list="recordForm.attachments"
          <UploadAttachment
            ref="recordUploadAttachment"
            :file-list="recordFileList"
            :limit="10"
            :accept="attachmentAccept"
            :multiple="true"
            @change="handleRecordAttachmentChange"
            @upload-success="handleRecordUploadSuccess"
            @upload-error="handleRecordUploadError"
            @remove="handleRecordAttachmentRemove"
          />
        </el-form-item>
      </el-form>
@@ -505,11 +496,67 @@
    </el-dialog>
    <!-- 附件预览对话框 -->
    <attachment-preview
      :visible="attachmentPreviewVisible"
      :file-list="currentAttachmentList"
    <el-dialog
      :title="attachmentPreviewTitle"
      @close="attachmentPreviewVisible = false"
      :visible.sync="attachmentPreviewVisible"
      width="900px"
      @close="handleAttachmentPreviewClose"
    >
      <el-table :data="currentAttachmentList" style="width: 100%" size="small">
        <el-table-column label="文件名" min-width="200">
          <template slot-scope="scope">
            <i
              class="el-icon-document"
              :style="{ color: getFileIconColor(scope.row.fileName) }"
            ></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 :type="getFileTagType(scope.row.fileName)" size="small">
              {{ getFileTypeText(scope.row.fileName) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="上传时间" width="160">
          <template slot-scope="scope">
            <span>{{ formatDateTime(scope.row.uploadTime) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="文件大小" width="100">
          <template slot-scope="scope">
            <span>{{ formatFileSize(scope.row.fileSize) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150" fixed="right">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="primary"
              @click="handlePreviewAttachment(scope.row)"
              :disabled="!isPreviewable(scope.row.fileName)"
            >
              预览
            </el-button>
            <el-button
              size="mini"
              type="success"
              @click="handleDownloadAttachment(scope.row)"
            >
              下载
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- 文件预览弹窗 -->
    <FilePreviewDialog
      :visible="filePreviewVisible"
      :file="currentPreviewFile"
      @close="filePreviewVisible = false"
      @download="handleDownloadAttachment"
    />
  </div>
</template>
@@ -518,17 +565,18 @@
import { maintainList, maintainedit, maintainAdd } from "@/api/businessApi";
import Pagination from "@/components/Pagination";
import UploadAttachment from "@/components/UploadAttachment";
import AttachmentPreview from "@/components/AttachmentPreview";
import FilePreviewDialog from "@/components/FilePreviewDialog";
import LiverKidneyPanel from "./components/LiverKidneyPanel.vue";
import BloodRoutinePanel from "./components/BloodRoutinePanel.vue";
import UrineRoutinePanel from "./components/UrineRoutinePanel.vue";
import dayjs from "dayjs";
export default {
  name: "MaintenanceDetail",
  components: {
    Pagination,
    UploadAttachment,
    AttachmentPreview,
    FilePreviewDialog,
    LiverKidneyPanel,
    BloodRoutinePanel,
    UrineRoutinePanel
@@ -565,9 +613,8 @@
        incompleteReason: ""
      },
      activeTab: "culture",
      liverKidneyData: {}, // 从 maintainList 接口获取的数据
      bloodRoutineData: {}, // 从 maintainList 接口获取的数据
      liverKidneyData: {}, // 从 maintainList 接口获取的数据
      extracontentinfo: {},
      // 培养结果相关数据
      cultureList: [],
      cultureLoading: false,
@@ -581,6 +628,7 @@
        result: "阴性",
        attachments: []
      },
      cultureFileList: [],
      cultureRules: {
        cultureType: [
          { required: true, message: "请选择培养类型", trigger: "change" }
@@ -614,6 +662,7 @@
        checkRecord: "",
        attachments: []
      },
      recordFileList: [],
      recordRules: {
        recordTime: [
          { required: true, message: "请选择核查时间", trigger: "change" }
@@ -630,6 +679,14 @@
      attachmentPreviewVisible: false,
      currentAttachmentList: [],
      attachmentPreviewTitle: "",
      // 文件预览相关
      filePreviewVisible: false,
      currentPreviewFile: null,
      // 附件相关配置
      attachmentLimit: 10,
      attachmentAccept: ".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt",
      // 评估数据存储
      assessmentData: {
@@ -650,7 +707,7 @@
    }
  },
  methods: {
    // 加载维护数据[1,3](@ref)
    // 加载维护数据
    async loadMaintenanceData() {
      try {
        this.cultureLoading = true;
@@ -660,7 +717,7 @@
        const queryParams = {};
        if (id) {
          queryParams.id = id;
          queryParams.infoid = infoid;
          this.currentMaintenanceId = id;
          this.isEditMode = true;
        } else if (infoid) {
@@ -672,22 +729,26 @@
          return;
        }
        queryParams.infoid = infoid;
        const response = await maintainList(queryParams);
        if (response.code === 200) {
          let maintenanceData = response.data[0];
          // 处理数组响应
          if (Array.isArray(maintenanceData)) {
            maintenanceData = maintenanceData[0] || {};
          }
          if (maintenanceData.extracontent) {
            this.extracontentinfo = JSON.parse(maintenanceData.extracontent);
            if (this.extracontentinfo.specialMedicalHistory) {
              this.form.specialMedicalHistory = this.extracontentinfo.specialMedicalHistory;
            }
          }
          // 解析itemDesc字段中的JSON数据[6,8](@ref)
          if (maintenanceData.itemDesc) {
            try {
              const itemDescData = JSON.parse(maintenanceData.itemDesc);
              const itemDescData = maintenanceData.itemDesc;
              this.assessmentData = { ...this.assessmentData, ...itemDescData };
              // 填充各个模块的数据
              if (itemDescData.cultureResults) {
                this.cultureList = itemDescData.cultureResults;
              }
@@ -708,7 +769,6 @@
            }
          }
          // 填充基础表单数据
          this.form = { ...this.form, ...maintenanceData };
          this.$message.success("数据加载成功");
        } else {
@@ -723,36 +783,35 @@
      }
    },
    // 保存所有数据[1,2](@ref)
    // 保存所有数据
    async handleSave() {
      try {
        // 构建保存数据
        const saveData = {
          ...this.form,
          itemDesc: JSON.stringify({
          itemDesc: {
            liverKidney: this.assessmentData.liverKidney,
            bloodRoutine: this.assessmentData.bloodRoutine,
            urineRoutine: this.assessmentData.urineRoutine,
            cultureResults: this.cultureList,
            nursingRecords: this.recordList
          })
          }
        };
        this.extracontentinfo.specialMedicalHistory = this.form.specialMedicalHistory;
        let response;
        if (this.isEditMode && this.currentMaintenanceId) {
          // 编辑模式,调用maintainedit接口[1](@ref)
          saveData.id = this.currentMaintenanceId;
          response = await maintainedit(saveData);
        } else {
          // 新增模式,调用maintainAdd接口[2](@ref)
          response = await maintainAdd(saveData);
        }
        if (response.code === 200) {
          this.$message.success("保存成功");
          this.isEdit = false;
          // 如果是新增保存,更新当前ID
          this.donatebaseinfoEdit({
            id: this.$route.query.infoid,
            extracontent: JSON.stringify(this.extracontentinfo)
          });
          if (!this.isEditMode && response.data && response.data.id) {
            this.currentMaintenanceId = response.data.id;
            this.isEditMode = true;
@@ -784,6 +843,7 @@
        result: "阴性",
        attachments: []
      };
      this.cultureFileList = [];
      this.cultureDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.cultureForm && this.$refs.cultureForm.clearValidate();
@@ -793,6 +853,14 @@
    handleEditCulture(row) {
      this.cultureDialogTitle = "编辑培养记录";
      this.cultureForm = { ...row };
      this.cultureFileList = row.attachments ? row.attachments.map(item => ({
        uid: item.id || Math.random(),
        name: item.fileName,
        fileSize: item.fileSize,
        url: item.path || item.fileUrl,
        uploadTime: item.uploadTime,
        status: "success"
      })) : [];
      this.cultureDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.cultureForm && this.$refs.cultureForm.clearValidate();
@@ -805,7 +873,6 @@
          this.cultureSaveLoading = true;
          if (this.cultureForm.id) {
            // 编辑现有记录
            const index = this.cultureList.findIndex(
              item => item.id === this.cultureForm.id
            );
@@ -813,7 +880,6 @@
              this.cultureList.splice(index, 1, { ...this.cultureForm });
            }
          } else {
            // 新增记录
            this.cultureForm.id = Date.now();
            this.cultureList.push({ ...this.cultureForm });
          }
@@ -853,6 +919,7 @@
        checkRecord: "",
        attachments: []
      };
      this.recordFileList = [];
      this.recordDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.recordForm && this.$refs.recordForm.clearValidate();
@@ -862,6 +929,14 @@
    handleEditRecord(row) {
      this.recordDialogTitle = "编辑护理核查记录";
      this.recordForm = { ...row };
      this.recordFileList = row.attachments ? row.attachments.map(item => ({
        uid: item.id || Math.random(),
        name: item.fileName,
        fileSize: item.fileSize,
        url: item.path || item.fileUrl,
        uploadTime: item.uploadTime,
        status: "success"
      })) : [];
      this.recordDialogVisible = true;
      this.$nextTick(() => {
        this.$refs.recordForm && this.$refs.recordForm.clearValidate();
@@ -874,7 +949,6 @@
          this.recordSaveLoading = true;
          if (this.recordForm.id) {
            // 编辑现有记录
            const index = this.recordList.findIndex(
              item => item.id === this.recordForm.id
            );
@@ -882,7 +956,6 @@
              this.recordList.splice(index, 1, { ...this.recordForm });
            }
          } else {
            // 新增记录
            this.recordForm.id = Date.now();
            this.recordList.push({ ...this.recordForm });
          }
@@ -907,13 +980,90 @@
        .catch(() => {});
    },
    // 附件相关方法
    // 培养记录附件相关方法
    handleCultureAttachmentChange(fileList) {
      this.cultureForm.attachments = fileList;
      this.cultureFileList = fileList;
    },
    handleCultureUploadSuccess({ file, fileList, response }) {
      if (response.code === 200) {
        const attachmentObj = {
          fileName: file.name,
          path: response.fileUrl || file.url,
          fileUrl: response.fileUrl || file.url,
          fileType: this.getFileExtension(file.name),
          fileSize: file.size,
          uploadTime: dayjs().format("YYYY-MM-DD HH:mm:ss")
        };
        if (!Array.isArray(this.cultureForm.attachments)) {
          this.cultureForm.attachments = [];
        }
        this.cultureForm.attachments.push(attachmentObj);
        this.cultureFileList = fileList;
        this.$message.success("文件上传成功");
      }
    },
    handleCultureUploadError({ file, fileList, error }) {
      console.error("培养记录附件上传失败:", error);
      this.$message.error("文件上传失败,请重试");
    },
    handleCultureAttachmentRemove(file) {
      if (file.url) {
        const index = this.cultureForm.attachments.findIndex(
          item => item.path === file.url || item.fileUrl === file.url
        );
        if (index > -1) {
          this.cultureForm.attachments.splice(index, 1);
          this.$message.success("附件删除成功");
        }
      }
    },
    // 护理记录附件相关方法
    handleRecordAttachmentChange(fileList) {
      this.recordForm.attachments = fileList;
      this.recordFileList = fileList;
    },
    handleRecordUploadSuccess({ file, fileList, response }) {
      if (response.code === 200) {
        const attachmentObj = {
          fileName: file.name,
          path: response.fileUrl || file.url,
          fileUrl: response.fileUrl || file.url,
          fileType: this.getFileExtension(file.name),
          fileSize: file.size,
          uploadTime: dayjs().format("YYYY-MM-DD HH:mm:ss")
        };
        if (!Array.isArray(this.recordForm.attachments)) {
          this.recordForm.attachments = [];
        }
        this.recordForm.attachments.push(attachmentObj);
        this.recordFileList = fileList;
        this.$message.success("文件上传成功");
      }
    },
    handleRecordUploadError({ file, fileList, error }) {
      console.error("护理记录附件上传失败:", error);
      this.$message.error("文件上传失败,请重试");
    },
    handleRecordAttachmentRemove(file) {
      if (file.url) {
        const index = this.recordForm.attachments.findIndex(
          item => item.path === file.url || item.fileUrl === file.url
        );
        if (index > -1) {
          this.recordForm.attachments.splice(index, 1);
          this.$message.success("附件删除成功");
        }
      }
    },
    handleViewCultureAttachments(row) {
@@ -926,6 +1076,124 @@
      this.currentAttachmentList = row.attachments || [];
      this.attachmentPreviewTitle = `护理核查记录附件 - ${row.recorder}`;
      this.attachmentPreviewVisible = true;
    },
    handleAttachmentPreviewClose() {
      this.currentAttachmentList = [];
      this.attachmentPreviewTitle = "";
    },
    handlePreviewAttachment(file) {
      this.currentPreviewFile = {
        fileName: file.fileName,
        fileUrl: file.path || file.fileUrl,
        fileType: this.getFileType(file.fileName)
      };
      this.filePreviewVisible = true;
    },
    handleDownloadAttachment(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";
    },
    /** 获取文件图标颜色 */
    getFileIconColor(fileName) {
      const type = this.getFileType(fileName);
      const colorMap = {
        image: "#67C23A",
        pdf: "#F56C6C",
        office: "#409EFF",
        other: "#909399"
      };
      return colorMap[type] || "#909399";
    },
    /** 获取文件标签类型 */
    getFileTagType(fileName) {
      const type = this.getFileType(fileName);
      const typeMap = {
        image: "success",
        pdf: "danger",
        office: "primary",
        other: "info"
      };
      return typeMap[type] || "info";
    },
    /** 获取文件类型文本 */
    getFileTypeText(fileName) {
      const type = this.getFileType(fileName);
      const textMap = {
        image: "图片",
        pdf: "PDF",
        office: "文档",
        other: "其他"
      };
      return textMap[type] || "未知";
    },
    /** 检查是否可预览 */
    isPreviewable(fileName) {
      const type = this.getFileType(fileName);
      return ["image", "pdf"].includes(type);
    },
    /** 获取文件扩展名 */
    getFileExtension(filename) {
      return filename.split(".").pop().toLowerCase();
    },
    /** 格式化文件大小 */
    formatFileSize(bytes) {
      if (!bytes || bytes === 0) return "0 B";
      const k = 1024;
      const sizes = ["B", "KB", "MB", "GB"];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    },
    /** 日期时间格式化 */
    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");
        return `${year}-${month}-${day} ${hours}:${minutes}`;
      } catch (error) {
        return dateTime;
      }
    },
    // 评估数据变更处理
@@ -991,4 +1259,9 @@
.fixed-width .el-button {
  margin: 0 2px;
}
.file-name {
  font-size: 13px;
  margin-left: 8px;
}
</style>