WXL
5 天以前 631c8f37b449b09d19345b76400a39abdb7800f6
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 ? '修改成功' : '新建成功');
        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');
          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;