<template>
|
<el-dialog
|
:title="`${isEdit ? '编辑' : '新建'}转运单`"
|
:visible.sync="editOpen"
|
width="900px"
|
append-to-body
|
:close-on-click-modal="false"
|
@close="handleClose"
|
>
|
<el-form
|
ref="editForm"
|
:model="formData"
|
:rules="formRules"
|
label-width="120px"
|
>
|
<!-- 基础信息 -->
|
<el-card class="form-section" shadow="never">
|
<div slot="header" class="section-header">
|
<i class="el-icon-document" style="color: #409EFF; margin-right: 8px;"></i>
|
<span>基础信息</span>
|
</div>
|
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<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>
|
</el-col>
|
</el-row>
|
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<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="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>
|
</el-row>
|
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="年龄" prop="age">
|
<el-input-number
|
v-model="formData.age"
|
:min="0"
|
:max="120"
|
placeholder="请输入年龄"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<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>
|
</el-card>
|
|
<!-- 转运信息 -->
|
<el-card class="form-section" shadow="never">
|
<div slot="header" class="section-header">
|
<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="transportStartPlace">
|
<el-input
|
v-model="formData.transportStartPlace"
|
placeholder="请输入出发地点"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="出发时间" prop="transportStartTime">
|
<el-date-picker
|
v-model="formData.transportStartTime"
|
type="datetime"
|
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="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-card>
|
|
<!-- 医护人员信息 -->
|
<el-card class="form-section" shadow="never">
|
<div slot="header" class="section-header">
|
<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="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>
|
</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-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: #409EFF; margin-right: 8px;"></i>
|
<span>备注信息</span>
|
</div>
|
<el-form-item prop="remark">
|
<el-input
|
v-model="formData.remark"
|
type="textarea"
|
:rows="4"
|
placeholder="请输入备注信息"
|
maxlength="500"
|
show-word-limit
|
/>
|
</el-form-item>
|
</el-card>
|
</el-form>
|
|
<div slot="footer" class="dialog-footer">
|
<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,
|
default: false
|
},
|
transportData: {
|
type: Object,
|
default: () => ({})
|
},
|
isEdit: {
|
type: Boolean,
|
default: false
|
}
|
},
|
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" }
|
],
|
patName: [
|
{ required: true, message: "请输入患者姓名", trigger: "blur" }
|
],
|
sex: [{ required: true, message: "请选择性别", trigger: "change" }],
|
age: [{ required: true, message: "请输入年龄", trigger: "blur" }],
|
diagnosisname: [
|
{ required: true, message: "请输入疾病诊断名称", trigger: "blur" }
|
],
|
treatmentHospitalName: [
|
{ required: true, message: "请输入治疗医院名称", trigger: "blur" }
|
],
|
transportStartPlace: [
|
{ required: true, message: "请输入出发地点", trigger: "blur" }
|
],
|
transportStartTime: [
|
{ required: true, message: "请选择出发时间", trigger: "change" }
|
],
|
contactPerson: [
|
{ required: true, message: "请输入负责协调员", trigger: "blur" }
|
]
|
}
|
};
|
},
|
watch: {
|
editOpen(val) {
|
if (val) {
|
this.formData = this.isEdit
|
? { ...this.getDefaultFormData(), ...this.transportData }
|
: this.getDefaultFormData();
|
|
this.initAttachmentList();
|
|
this.$nextTick(() => {
|
this.$refs.editForm && this.$refs.editForm.clearValidate();
|
});
|
}
|
}
|
},
|
methods: {
|
/** 获取默认表单数据 */
|
getDefaultFormData() {
|
return {
|
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.previewVisible = false;
|
},
|
|
async handleSave() {
|
try {
|
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;
|
|
const requestData = { ...this.formData };
|
let response;
|
|
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("操作失败,请稍后重试");
|
} finally {
|
this.saveLoading = false;
|
}
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.form-section {
|
margin-bottom: 16px;
|
}
|
|
.section-header {
|
display: flex;
|
align-items: center;
|
font-weight: bold;
|
color: #303133;
|
}
|
|
.dialog-footer {
|
text-align: right;
|
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;
|
}
|
</style>
|