feat(device,supply,satisfaction): 设备计划改造、耗材采购调整与满意度照片上传
- 设备保养计划:审核/退回、计划与记录联动、只读台账与Word导出、年份下拉规则
- 设备核查计划:检查日期精确到日、审核完成时间口径、附件随记录提交
- 服务和供应品采购:存放位置手填、入库单价联动参考价格、移除目录维护
- 客户满意度:新增/编辑支持照片上传与预览
- 附件与文件预览:待上传照片预览、更多文件格式支持
| | |
| | | params: query, |
| | | }); |
| | | } |
| | | //设备核查计划 年份列表(没有明细的空年份自动删除) |
| | | export function getExaminePlanYears(query) { |
| | | return request({ |
| | | url: "/deviceExaminePlan/getPlanYears", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // 设备核查计划提交批准通知 |
| | | export function submitRatifyDeviceExaminePlan(data) { |
| | |
| | | export function getMaintenancePlanByYear(query) { |
| | | return request({ |
| | | url: "/deviceMaintenancePlan/getPlanByYear", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | //设备保养计划 年份列表(没有明细的空年份自动删除) |
| | | export function getMaintenancePlanYears(query) { |
| | | return request({ |
| | | url: "/deviceMaintenancePlan/getPlanYears", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | |
| | | data: query, |
| | | }); |
| | | } |
| | | |
| | | //保养记录 审核 |
| | | export function reviewDeviceMaintenance(data) { |
| | | return request({ |
| | | url: "/deviceMaintain/reviewDeviceMaintenance", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | //使用记录 导出 |
| | | export function exportDeviceMaintenance(query) { |
| | | return request({ |
| | |
| | | <div class="el-upload__tip"> |
| | | {{ readonly ? '仅可预览、下载附件' : ((currentId || deferUpload) ? tip : emptyTip) }} |
| | | </div> |
| | | <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple |
| | | <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple :accept="accept" |
| | | :show-file-list="false" :disabled="!canUpload" :auto-upload="!deferUpload" |
| | | :on-change="handleFileChange" :on-success="handleUploadSuccess" |
| | | :on-error="handleUploadError"> |
| | |
| | | <el-table-column label="操作" width="170"> |
| | | <template #default="scope"> |
| | | <template v-if="scope.row.pending"> |
| | | <el-button link type="primary" @click="previewPending(scope.row)">预览</el-button> |
| | | <el-button link type="danger" @click="removePending(scope.row)">删除</el-button> |
| | | </template> |
| | | <template v-else> |
| | |
| | | <el-dialog v-else :title="dialogTitle" v-model="visible" width="760px" append-to-body @close="$emit('closed')"> |
| | | <div class="attachment-header"> |
| | | <div class="el-upload__tip">{{ readonly ? '仅可预览、下载附件' : tip }}</div> |
| | | <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple |
| | | <el-upload v-if="!readonly" :action="uploadAction" :headers="uploadHeader" multiple :accept="accept" |
| | | :show-file-list="false" :on-success="handleUploadSuccess" :on-error="handleUploadError"> |
| | | <el-button size="small" type="primary">上传附件</el-button> |
| | | </el-upload> |
| | |
| | | <el-button @click="visible = false">关 闭</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | <el-dialog title="预览附件" v-model="previewVisible" fullscreen append-to-body> |
| | | <el-dialog title="预览附件" v-model="previewVisible" fullscreen append-to-body @close="releasePreviewBlob"> |
| | | <file-preview v-if="previewVisible" :file-url="previewUrl" :current-file="previewRow" /> |
| | | </el-dialog> |
| | | </div> |
| | |
| | | deferUpload: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | // 允许选择的文件类型,如 .jpg,.png;为空不限制 |
| | | accept: { |
| | | type: String, |
| | | default: '' |
| | | } |
| | | }, |
| | | watch: { |
| | |
| | | currentRow: {}, |
| | | previewVisible: false, |
| | | previewRow: {}, |
| | | previewUrl: '' |
| | | previewUrl: '', |
| | | previewBlobUrl: '' |
| | | } |
| | | }, |
| | | computed: { |
| | |
| | | uploadAction() { |
| | | return this.javaApi + this.uploadUrl + '?' + this.idParam + '=' + this.currentId |
| | | } |
| | | }, |
| | | beforeUnmount() { |
| | | this.releasePreviewBlob() |
| | | }, |
| | | methods: { |
| | | // 打开附件管理弹窗 |
| | |
| | | this.loadList() |
| | | }) |
| | | }, |
| | | // 待上传文件用本地临时地址预览,提交后再走正式地址 |
| | | previewPending(row) { |
| | | const item = this.pendingFiles.find(pending => pending.uid === row.uid) |
| | | if (!item) { |
| | | return |
| | | } |
| | | this.releasePreviewBlob() |
| | | this.previewBlobUrl = URL.createObjectURL(item.raw) |
| | | this.previewRow = { fileName: item.fileName, fileUrl: this.previewBlobUrl } |
| | | this.previewUrl = this.previewBlobUrl |
| | | this.previewVisible = true |
| | | }, |
| | | releasePreviewBlob() { |
| | | if (this.previewBlobUrl) { |
| | | URL.revokeObjectURL(this.previewBlobUrl) |
| | | this.previewBlobUrl = '' |
| | | } |
| | | }, |
| | | previewFile(row) { |
| | | this.releasePreviewBlob() |
| | | this.previewRow = row |
| | | this.previewUrl = this.fullUrl(row.fileUrl) |
| | | this.previewVisible = true |
| | |
| | | } |
| | | }, |
| | | computed: { |
| | | // blob 临时地址本身不带扩展名,待上传文件靠原始文件名判断类型 |
| | | currentFileName() { |
| | | return (this.currentFile && this.currentFile.fileName) || '' |
| | | }, |
| | | isImage() { |
| | | return /\.(jpg|jpeg|png|gif)$/i.test(this.fileUrl) |
| | | return /\.(jpg|jpeg|png|gif)$/i.test(this.fileUrl) || /\.(jpg|jpeg|png|gif)$/i.test(this.currentFileName) |
| | | }, |
| | | imgUrl() { |
| | | // 图片存在 /img 静态路径下,调用方传的可能是 /word 地址,这里统一换成 /img |
| | |
| | | } |
| | | }, |
| | | fileExt() { |
| | | const match = this.fileUrl.match(/\.([a-zA-Z0-9]+)$/) |
| | | const match = (this.currentFileName || this.fileUrl).match(/\.([a-zA-Z0-9]+)$/) |
| | | return match ? match[1].toUpperCase() : '未知' |
| | | }, |
| | | // 调用方传了 OnlyOffice 的配置才走文档服务,否则用浏览器内置阅读器 |
| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="dialogVisible" |
| | | title="添加耗材项目信息" |
| | | width="70%" |
| | | :title="model.id ? '编辑耗材' : '新增耗材'" |
| | | width="1100px" |
| | | > |
| | | <el-form ref="modelForm" :model="model" :rules="rules" label-width="100px"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="耗材类型" prop="consumablesType"> |
| | | <el-select v-model="model.consumablesType" placeholder="请选择耗材类型" size="small" style="width: 100%"> |
| | | <el-option v-for="(v, i) in dict.type.consumables_type" :key="i" :label="v.label" :value="v.value"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="货号"> |
| | | <el-input v-model="model.itemNumber" placeholder="请输入货号" size="small"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="耗材名称"> |
| | | <el-input v-model="model.consumablesName" placeholder="请输入耗材名称" size="small"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="规格"> |
| | | <el-input v-model="model.specifications" placeholder="请输入规格" size="small"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="计量单位"> |
| | | <el-input v-model="model.unit" placeholder="请输入计量单位" size="small"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="参考价格"> |
| | | <el-input-number v-model="model.referencePrice" :min="0" :precision="2" :step="0.01" placeholder="请输入参考价格" |
| | | size="small"></el-input-number> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="存放位置"> |
| | | <el-select v-model="model.contentId" placeholder="请选择存放位置" size="small" style="width: 100%"> |
| | | <el-option v-for="(v, i) in procurementSuppliesContentOptions" :key="i" :label="v.nodeName" |
| | | :value="v.id"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="负责人"> |
| | | <el-select v-model="model.personInCharge" placeholder="请选择负责人" size="small" style="width: 100%"> |
| | | <el-option v-for="(v, i) in userOptions" :key="i" :label="v.name" :value="v.id"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="库存上限"> |
| | | <el-input-number v-model="model.upperLimit" :min="0" :step="1" placeholder="请输入库存上限" size="small"></el-input-number> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="库存下限"> |
| | | <el-input-number v-model="model.lowerLimit" :min="0" :step="1" placeholder="请输入库存下限" size="small"></el-input-number> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="供应商"> |
| | | <el-select v-model="model.supplier" placeholder="请选择供应商" size="small" style="width: 100%"> |
| | | <el-option v-for="(v, i) in supplierOptions" :key="i" :label="v.supplierName" |
| | | :value="v.supplierManagementId"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="耗材图标"> |
| | | <div class="rows"> |
| | | <el-input v-model="model.consumablesIcon" placeholder="请输入耗材图标" size="small" style="width: 90%;"/> |
| | | <el-upload |
| | | ref="upload" |
| | | :action="action" |
| | | :headers="uploadHeader" |
| | | :on-success="onSuccessIcon" |
| | | :show-file-list="false" |
| | | style="float: left; margin: 0 12px 0 20px;" |
| | | > |
| | | <template #trigger><el-button class="uploadFile" size="small" type="primary">浏览</el-button></template> |
| | | </el-upload> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="耗材附件"> |
| | | <div class="rows"> |
| | | <el-input v-model="model.attachment" placeholder="请输入耗材附件" size="small" style="width: 90%;"/> |
| | | <el-upload |
| | | ref="upload" |
| | | :action="action" |
| | | :on-success="onSuccessFile" |
| | | :show-file-list="false" |
| | | :headers="uploadHeader" |
| | | style="float: left; margin: 0 12px 0 20px;" |
| | | > |
| | | <template #trigger><el-button class="uploadFile" size="small" type="primary">浏览</el-button></template> |
| | | </el-upload> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="备注"> |
| | | <el-input |
| | | v-model="model.remark" |
| | | :rows="2" |
| | | placeholder="请输入备注" |
| | | size="small" |
| | | type="textarea" |
| | | > |
| | | </el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <div class="section-title">基本信息</div> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="耗材类型" prop="consumablesType"> |
| | | <el-select v-model="model.consumablesType" placeholder="请选择耗材类型" style="width: 100%"> |
| | | <el-option v-for="(v, i) in dict.type.consumables_type" :key="i" :label="v.label" :value="v.value"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="耗材名称"> |
| | | <el-input v-model="model.consumablesName" clearable placeholder="请输入耗材名称"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="货号"> |
| | | <el-input v-model="model.itemNumber" clearable placeholder="请输入货号"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="规格"> |
| | | <el-input v-model="model.specifications" clearable placeholder="请输入规格"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="计量单位"> |
| | | <el-input v-model="model.unit" clearable placeholder="请输入计量单位"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="参考价格"> |
| | | <el-input-number v-model="model.referencePrice" :min="0" :precision="2" :step="0.01" placeholder="请输入参考价格" |
| | | controls-position="right" style="width: 100%"></el-input-number> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="存放位置"> |
| | | <el-input v-model="model.storageLocation" clearable placeholder="请输入存放位置"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="负责人"> |
| | | <el-select v-model="model.personInCharge" placeholder="请选择负责人" style="width: 100%"> |
| | | <el-option v-for="(v, i) in userOptions" :key="i" :label="v.name" :value="v.id"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <div class="section-title">库存与供应商</div> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="库存上限"> |
| | | <el-input-number v-model="model.upperLimit" :min="0" :step="1" placeholder="请输入库存上限" |
| | | controls-position="right" style="width: 100%"></el-input-number> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="库存下限"> |
| | | <el-input-number v-model="model.lowerLimit" :min="0" :step="1" placeholder="请输入库存下限" |
| | | controls-position="right" style="width: 100%"></el-input-number> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="供应商"> |
| | | <el-select v-model="model.supplier" placeholder="请选择供应商" style="width: 100%"> |
| | | <el-option v-for="(v, i) in supplierOptions" :key="i" :label="v.supplierName" |
| | | :value="v.supplierManagementId"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <div class="section-title">图标与附件</div> |
| | | <el-row :gutter="24"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="耗材图标"> |
| | | <div class="upload-row"> |
| | | <el-input v-model="model.consumablesIcon" clearable placeholder="上传后自动填充,也可手动填写"></el-input> |
| | | <el-upload |
| | | :action="action" |
| | | :headers="uploadHeader" |
| | | :on-success="onSuccessIcon" |
| | | :show-file-list="false" |
| | | > |
| | | <el-button :icon="$icon('el-icon-upload2')" type="primary" plain>上传</el-button> |
| | | </el-upload> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="耗材附件"> |
| | | <div class="upload-row"> |
| | | <el-input v-model="model.attachment" clearable placeholder="上传后自动填充,也可手动填写"></el-input> |
| | | <el-upload |
| | | :action="action" |
| | | :headers="uploadHeader" |
| | | :on-success="onSuccessFile" |
| | | :show-file-list="false" |
| | | > |
| | | <el-button :icon="$icon('el-icon-upload2')" type="primary" plain>上传</el-button> |
| | | </el-upload> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-form-item class="remark-item" label-width="0"> |
| | | <el-input v-model="model.remark" :rows="4" placeholder="请输入备注" type="textarea"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="resetForm">取 消</el-button> |
| | | <el-button type="primary" @click="submit">保 存</el-button> |
| | | </span></template> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="resetForm">取 消</el-button> |
| | | <el-button type="primary" @click="submit">保 存</el-button> |
| | | </span></template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | |
| | | addProcurementSuppliesList, |
| | | updateProcurementSuppliesList, |
| | | selectSupplierManagementAll, |
| | | getProcurementSuppliesContentsNodeNames, |
| | | selectUserCondition |
| | | } from '@/api/cnas/externalService/serviceAndSupplyPro/serviceAndSupplyPro' |
| | | export default { |
| | |
| | | consumablesIcon: undefined, |
| | | attachment: undefined, |
| | | }, |
| | | procurementSuppliesContentOptions: [], |
| | | userOptions: [], |
| | | supplierOptions: [], |
| | | rules: { |
| | |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.findProcurementSuppliesContentOptions() |
| | | this.findUserOptions() |
| | | this.findSupplierOptions() |
| | | }, |
| | |
| | | console.log("row", row) |
| | | this.model = row |
| | | } else { |
| | | this.model = {} |
| | | // 新增时挂在当前左树选中的目录节点下,存放位置改为手动填写 |
| | | this.model = { contentId: this.contentsId } |
| | | } |
| | | this.dialogVisible = true |
| | | }, |
| | | findProcurementSuppliesContentOptions() { |
| | | getProcurementSuppliesContentsNodeNames().then(res => { |
| | | if (res.code === 200) { |
| | | this.procurementSuppliesContentOptions = res.data |
| | | } |
| | | }) |
| | | }, |
| | | findUserOptions() { |
| | | selectUserCondition().then(res => { |
| | |
| | | submit() { |
| | | this.$refs.modelForm.validate((valid) => { |
| | | if (valid) { |
| | | // 新增的耗材挂在左侧选中的目录节点下,未选节点会保存成列表里看不到的数据 |
| | | if (!this.model.id && !this.contentsId) { |
| | | this.$message.warning('请先在左侧选择耗材目录节点') |
| | | return |
| | | } |
| | | if (this.model.id) { |
| | | updateProcurementSuppliesList(this.model).then(res => { |
| | | if (res.code === 200) { |
| | |
| | | margin: 6vh auto 50px !important; |
| | | } |
| | | :deep(.el-dialog__body) { |
| | | max-height: 42em; |
| | | max-height: 70vh; |
| | | overflow-y: auto; |
| | | padding: 24px 32px; |
| | | } |
| | | .rows { |
| | | width: 100%; |
| | | .section-title { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | color: var(--lims-text); |
| | | padding-bottom: 10px; |
| | | border-bottom: 1px solid var(--lims-divider); |
| | | margin: 8px 0 20px; |
| | | } |
| | | :deep(.el-form-item__content) { |
| | | line-height: 39px; |
| | | .section-title:not(:first-child) { |
| | | margin-top: 28px; |
| | | } |
| | | .section-title::before { |
| | | content: ''; |
| | | display: inline-block; |
| | | width: 3px; |
| | | height: 15px; |
| | | border-radius: 2px; |
| | | background: var(--el-color-primary); |
| | | margin-right: 8px; |
| | | } |
| | | .upload-row { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | width: 100%; |
| | | } |
| | | .upload-row .el-input { |
| | | flex: 1; |
| | | } |
| | | :deep(.el-form-item) { |
| | | margin-bottom: 20px; |
| | | } |
| | | .remark-item { |
| | | margin-top: 28px; |
| | | } |
| | | </style> |
| | |
| | | <div> |
| | | <div> |
| | | <span>耗材名称:</span> |
| | | <el-select v-model="formTwo.id" filterable placeholder="请选择耗材名称" size="small" style="width: 70%"> |
| | | <el-select v-model="formTwo.id" filterable placeholder="请选择耗材名称" size="small" style="width: 70%" |
| | | @change="handleConsumableChange"> |
| | | <el-option v-for="(v, i) in consumableOptions" :key="i" :label="v.consumablesName" |
| | | :value="v.id"></el-option> |
| | | </el-select> |
| | |
| | | console.log(val) |
| | | return this.options.find(item => item.value === val).label |
| | | }, |
| | | // 选择耗材名称后,单价自动带出耗材列表里的参考价格(仍可手动修改) |
| | | handleConsumableChange(id) { |
| | | const item = this.consumableOptions.find(v => v.id === id) |
| | | this.formTwo.unitPrice = item && item.referencePrice != null ? item.referencePrice : null |
| | | }, |
| | | // 添加表格数据 |
| | | addTableData() { |
| | | this.$nextTick() |
| | |
| | | <el-tab-pane label="耗材入库" name="third" :lazy="true"> |
| | | <Store v-if="activeName == 'third'" :contentsId="contentsId"></Store> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="目录维护" name="fourth" :lazy="true"> |
| | | <Contents |
| | | v-if="activeName == 'fourth'" |
| | | :id="contentsId" |
| | | @contentsUpdate="contentsUpdate" |
| | | :treeData="treeData" |
| | | from="耗材树" |
| | | ></Contents> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import Contents from "./component/contents.vue"; |
| | | import Store from "./component/Store.vue"; |
| | | import ConsumableOverview from "./component/ConsumableOverview.vue"; |
| | | import ConsumableList from "./component/ConsumableList.vue" |
| | |
| | | }; |
| | | }, |
| | | components: { |
| | | Contents, |
| | | Store, |
| | | ConsumableOverview, |
| | | ConsumableList |
| | |
| | | findNodesWithFiber(this.treeData); |
| | | }, |
| | | |
| | | // 目录维护更新 |
| | | contentsUpdate(val, flag = false) { |
| | | if (val) { |
| | | this.getTreeData(); |
| | | this.expandedKeys = []; |
| | | if (flag) { |
| | | const findNodesWithFiber = (nodes) => { |
| | | nodes.forEach((item) => { |
| | | if (item.parentId == val) { |
| | | this.expandedKeys.push(item.id); |
| | | } |
| | | if(item.children && item.children.length > 0) { |
| | | findNodesWithFiber(item.children); |
| | | } |
| | | }); |
| | | }; |
| | | findNodesWithFiber(this.treeData); |
| | | this.expandedKeys = this.expandedKeys.filter((item) => item !== val); |
| | | } else { |
| | | this.expandedKeys.push(val); |
| | | } |
| | | }else { |
| | | this.getTreeData(); |
| | | } |
| | | }, |
| | | // 查询所有目录 |
| | | getTreeData() { |
| | | directoryListing().then((res) => { |
| | |
| | | return |
| | | } |
| | | const isMonthOnly = /^\d{4}-\d{2}$/.test(checkTime) |
| | | const nowYear = nowMonth.slice(0, 4) |
| | | const todayStr = `${nowMonth}-${String(now.getDate()).padStart(2, '0')}` |
| | | const plannedText = isMonthOnly |
| | | ? (this.planDueDate ? `${this.planDueDate}(计划月份 ${checkTime})` : `${checkTime}(系统计划只登记到月份)`) |
| | | ? (this.planDueDate ? `${this.planDueDate}(计划月份 ${checkTime})` : `${checkTime}(系统登记只到月份)`) |
| | | : checkTime |
| | | const head = `<div class="er-head">该条记录的计划核查时间为 <b>${plannedText}</b>,当前审核日期是 <b>${todayStr}</b>,属于<b>提前审核</b>。</div>` |
| | | const items = isMonthOnly |
| | | ? [ |
| | | `本轮记录按实际审核月份归档:核查时间登记为 <b>${nowMonth}</b>(实际审核日期 ${todayStr}),并归入 <b>${nowYear} 年设备核查计划</b>(切到 ${nowYear} 年可看到,状态显示“通过”)。`, |
| | | `系统会按设备的核查周期自动生成下一轮待核查任务(在下次核查日期所属年份的计划中),初始状态“未开始”——这是正常现象,不是审核没生效。`, |
| | | `设备档案的最近核查日期更新为 <b>${todayStr}</b>,下次核查日期按核查周期自动计算。` |
| | | ] |
| | | : [ |
| | | `该记录保留原核查日期 <b>${checkTime}</b>,审核状态显示“通过”。`, |
| | | `系统会按设备的核查周期自动生成下一轮待核查任务(在下次核查日期所属年份的计划中),初始状态“未开始”,这是正常现象。`, |
| | | `设备档案的最近核查日期更新为 <b>${todayStr}</b>,下次核查日期按核查周期自动计算。` |
| | | ] |
| | | const head = `<div class="er-head">该条记录的计划检查日期为 <b>${plannedText}</b>,当前审核日期是 <b>${todayStr}</b>,属于<b>提前审核</b>。</div>` |
| | | const items = [ |
| | | `本轮记录的计划检查日期保留为 <b>${plannedText}</b> 不变;审核通过后,「核查时间」记录为实际审核日期 <b>${todayStr}</b>。`, |
| | | `设备档案的最近核查日期更新为 <b>${todayStr}</b>,下次核查日期按核查周期自动计算。`, |
| | | `系统会按设备的核查周期自动生成下一轮待核查任务(在下次核查日期所属年份的计划中),初始状态“未开始”,这是正常现象,不是审核没生效。` |
| | | ] |
| | | const content = `${head}<div class="er-title">通过后系统会做三件事:</div>` + |
| | | `<ol class="er-list">${items.map(item => `<li>${item}</li>`).join('')}</ol>` + |
| | | `<div class="er-question">是否确认通过?</div>` |
| | |
| | | dangerouslyUseHTMLString: true, |
| | | customClass: 'early-review-message', |
| | | }).then(() => { |
| | | this.submitReview(statue, isMonthOnly) |
| | | this.submitReview(statue) |
| | | }).catch(() => {}) |
| | | }, |
| | | // 真正提交审核 |
| | | submitReview(statue, isMonthOnly = false) { |
| | | submitReview(statue) { |
| | | this.submitFormLoading = true |
| | | const params = { |
| | | planDetailsId: this.form.planDetailsId, |
| | |
| | | } |
| | | reviewExamineRecord(params).then(res => { |
| | | if (res.code == 200) { |
| | | if (statue === 1 && isMonthOnly) { |
| | | const now = new Date() |
| | | this.$message.success(`审核通过,本轮已归入 ${now.getFullYear()} 年设备核查计划`) |
| | | } else { |
| | | this.$message.success(statue === 1 ? '审核通过' : '已退回') |
| | | } |
| | | this.$message.success(statue === 1 ? '审核通过' : '审核不通过') |
| | | this.resetForm() |
| | | } |
| | | this.submitFormLoading = false |
| | |
| | | <template> |
| | | <!-- 设备维护保养(只读台账,记录由保养计划生成)--> |
| | | <div> |
| | | <div class="search"> |
| | | <el-button size="small" type="primary" @click="refreshTableList">刷新</el-button> |
| | | <el-button size="small" type="primary" @click="openDia('add')">新 建</el-button> |
| | | <el-button :loading="outLoading" size="small" type="primary" @click="openHandleOut">导 出</el-button> |
| | | </div> |
| | | <div> |
| | | <lims-table :tableData="tableData" :column="column" |
| | | height="calc(100vh - 20em)" @pagination="pagination" |
| | | :page="page" :tableLoading="tableLoading"></lims-table> |
| | | <el-table v-loading="tableLoading" :data="tableData" border height="calc(100vh - 20em)" style="width: 100%;"> |
| | | <el-table-column align="center" header-align="center" label="序号" prop="prop" type="index" |
| | | width="60"></el-table-column> |
| | | <el-table-column align="center" header-align="center" label="维护日期" min-width="110"> |
| | | <template #default="scope">{{ formatDate(scope.row.maintenanceDate) }}</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" header-align="center" label="维护保养内容"> |
| | | <el-table-column v-for="item in checkColumns" :key="item.prop" align="center" header-align="center" |
| | | :label="item.label" width="110"> |
| | | <template #default="scope">{{ scope.row[item.prop] || '—' }}</template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column align="center" header-align="center" label="维护人" min-width="100"> |
| | | <template #default="scope">{{ scope.row.maintenanceUserName || '—' }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="审核状态" min-width="100"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="scope.row.recordStatus === 1" type="warning" disable-transitions>待审核</el-tag> |
| | | <el-tag v-else-if="scope.row.recordStatus === 2" type="success" disable-transitions>通过</el-tag> |
| | | <el-tag v-else-if="scope.row.recordStatus === 3" type="danger" disable-transitions>不通过</el-tag> |
| | | <el-tag v-else type="info" disable-transitions>历史</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="备注" min-width="140" show-overflow-tooltip> |
| | | <template #default="scope">{{ scope.row.remark || '—' }}</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" fixed="right" label="操作" min-width="120"> |
| | | <template #default="scope"> |
| | | <el-button size="small" link type="primary" @click="handleView(scope.row)">查看</el-button> |
| | | <el-button v-if="scope.row.recordStatus === 1 || scope.row.recordStatus === 3" size="small" link |
| | | type="danger" @click="handleDeleteClick(scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination :current-page="pagination.current" :page-size="pagination.size" |
| | | :page-sizes="[10, 20, 30, 50, 100]" background :total="pagination.total" |
| | | layout="->,total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange"> |
| | | </el-pagination> |
| | | </div> |
| | | <el-dialog v-model="dialogVisible" title="仪器设备使用维护保养表" width="55%"> |
| | | <el-form ref="form" :model="form" label-width="130px" :rules="rules"> |
| | | <el-dialog :close-on-click-modal="false" v-model="dialogVisible" title="查看保养记录" width="880px"> |
| | | <el-form :model="form" label-width="150px" size="small"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维护日期:" prop="maintenanceDate"> |
| | | <el-date-picker v-model="form.maintenanceDate" :disabled="operationType === 'view'" |
| | | format="YYYY-MM-DD" size="small" placeholder="选择日期" style="width:100%" |
| | | type="date" value-format="YYYY-MM-DD"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="维护内容:" prop="maintenanceContentArr"> |
| | | <el-checkbox-group v-if="qualificationList.length" v-model="form.maintenanceContentArr" |
| | | :disabled="operationType === 'view'"> |
| | | <el-checkbox v-for="city in qualificationList" :key="city.label" :label="city.label" |
| | | :value="city.label"></el-checkbox> |
| | | </el-checkbox-group> |
| | | <el-input v-else v-model="form.maintenanceContentText" :disabled="operationType === 'view'" |
| | | size="small" placeholder="请输入维护内容" style="width: 100%"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维护人:" prop="maintenanceUserId"> |
| | | <el-select v-model="form.maintenanceUserId" |
| | | clearable filterable |
| | | placeholder="请选择" size="small" style="width: 100%;"> |
| | | <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id"> |
| | | </el-option> |
| | | </el-select> |
| | | <el-form-item label="设备名称:"> |
| | | <el-input v-model="form.deviceName" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="备注:" prop="remark"> |
| | | <el-input v-model="form.remark" :disabled="operationType === 'view'" size="small" |
| | | style="width: 100%;"></el-input> |
| | | <el-form-item label="设备编号:"> |
| | | <el-input v-model="form.managementNumber" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维护日期:"> |
| | | <el-input v-model="form.maintenanceDate" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维护人:"> |
| | | <el-input v-model="form.maintenanceUserName" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <div class="form-section-title">维护保养内容</div> |
| | | <el-row> |
| | | <el-col v-for="item in checkColumns" :key="item.prop" :span="12"> |
| | | <el-form-item :label="item.label + ':'"> |
| | | <el-input v-model="form[item.prop]" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="保养备注:"> |
| | | <el-input v-model="form.remark" :rows="2" disabled type="textarea"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="审核状态:"> |
| | | <el-tag v-if="form.recordStatus === 1" type="warning" disable-transitions>待审核</el-tag> |
| | | <el-tag v-else-if="form.recordStatus === 2" type="success" disable-transitions>通过</el-tag> |
| | | <el-tag v-else-if="form.recordStatus === 3" type="danger" disable-transitions>不通过</el-tag> |
| | | <el-tag v-else type="info" disable-transitions>历史</el-tag> |
| | | </el-form-item> |
| | | <el-row v-if="form.reviewUserName || form.reviewTime"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="审核人:"> |
| | | <el-input v-model="form.reviewUserName" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="审核时间:"> |
| | | <el-input v-model="form.reviewTime" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item v-if="form.reviewRemark" label="审核意见:"> |
| | | <el-input v-model="form.reviewRemark" :rows="2" disabled type="textarea"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="closeDia">取 消</el-button> |
| | | <el-button v-if="operationType !== 'view'" type="primary" @click="saveRecord" :loading="buttonLoading">确 定</el-button> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">关 闭</el-button> |
| | | </span></template> |
| | | </el-dialog> |
| | | </div> |
| | |
| | | |
| | | <script> |
| | | import { |
| | | addDeviceMaintenance, |
| | | deleteDeviceMaintenance, exportDeviceMaintenance, |
| | | selectDeviceMaintenancePage |
| | | } from "@/api/cnas/resourceDemand/device"; |
| | | import limsTable from "@/components/Table/lims-table.vue"; |
| | | import {selectUserCondition} from "@/api/system/user"; |
| | | import {saveBlobOrShowError} from '@/utils/saveBlob' |
| | | deleteDeviceMaintenance, |
| | | exportDeviceMaintenance, |
| | | selectDeviceMaintenancePage, |
| | | } from '@/api/cnas/resourceDemand/device' |
| | | import { formatDateOnly, formatListDate } from './dateFormat' |
| | | import { saveBlobOrShowError } from '@/utils/saveBlob' |
| | | |
| | | // 维护保养检查项,与仪器设备维护保养记录表一致 |
| | | const CHECK_ITEMS = [ |
| | | { label: '外观是否良好', prop: 'appearanceGood' }, |
| | | { label: '是否可以正常使用', prop: 'normalUse' }, |
| | | { label: '是否清洁仪器表面', prop: 'surfaceClean' }, |
| | | { label: '标识是否完好', prop: 'labelIntact' }, |
| | | { label: '显示器灯是否正常', prop: 'displayLightNormal' }, |
| | | { label: '仪器是否生锈', prop: 'noRust' }, |
| | | { label: '校准是否正常', prop: 'calibrationNormal' }, |
| | | { label: '配件是否需要更换', prop: 'partsReplace' }, |
| | | { label: '维护结果是否正常', prop: 'resultNormal' }, |
| | | ] |
| | | |
| | | export default { |
| | | name: '', |
| | | // import 引入的组件需要注入到对象中才能使用 |
| | | components: {limsTable}, |
| | | name: 'equipment-maintenance', |
| | | props: { |
| | | clickNodeVal: { |
| | | type: Object, |
| | |
| | | }, |
| | | }, |
| | | data() { |
| | | // 这里存放数据 |
| | | return { |
| | | search: { |
| | | maintenanceDate: '', |
| | | }, |
| | | outLoading: false, |
| | | tableData: [], |
| | | tableLoading: false, |
| | | page: { |
| | | pagination: { |
| | | total: 0, |
| | | size: 20, |
| | | current: 1 |
| | | current: 1, |
| | | }, |
| | | column: [ |
| | | { label: '维护日期', prop: 'maintenanceDate' }, |
| | | { label: '维护内容', prop: 'maintenanceContent' }, |
| | | { label: '维护人', prop: 'maintenanceUserName' }, |
| | | { label: '备注', prop: 'remark' }, |
| | | { |
| | | dataType: 'action', |
| | | label: '操作', |
| | | operation: [ |
| | | { |
| | | name: '编辑', |
| | | type: 'text', |
| | | clickFun: (row) => { |
| | | this.openDia('edit', row); |
| | | }, |
| | | }, |
| | | { |
| | | name: '删除', |
| | | type: 'text', |
| | | clickFun: (row) => { |
| | | this.handleDeleteClick(row); |
| | | }, |
| | | }, |
| | | ] |
| | | } |
| | | ], |
| | | checkColumns: CHECK_ITEMS.map(item => ({ ...item })), |
| | | dialogVisible: false, |
| | | form: { |
| | | id: '', |
| | | deviceId: '', |
| | | maintenanceDate: '', |
| | | maintenanceContentArr: [], |
| | | maintenanceContent: '', |
| | | maintenanceContentText: '', |
| | | maintenanceUserId: '', |
| | | remark: '', |
| | | }, |
| | | operationType: '', |
| | | buttonLoading: false, |
| | | qualificationList: [], |
| | | rules: { |
| | | maintenanceDate: [{ required: true, message: '请选择维护日期', trigger: 'change' }], |
| | | maintenanceContentArr: [{ |
| | | validator: (rule, value, callback) => { |
| | | if (this.qualificationList.length) { |
| | | if (!value || value.length === 0) { |
| | | return callback(new Error('请选择维护内容')) |
| | | } |
| | | } else if (!this.form.maintenanceContentText || !this.form.maintenanceContentText.trim()) { |
| | | return callback(new Error('请输入维护内容')) |
| | | } |
| | | callback() |
| | | }, |
| | | trigger: 'change' |
| | | }], |
| | | maintenanceUserId: [{ required: true, message: '请选择维护人', trigger: 'change' }], |
| | | }, |
| | | responsibleOptions: [], |
| | | form: {}, |
| | | }; |
| | | }, |
| | | mounted() { |
| | | this.refreshTableList() |
| | | }, |
| | | // 方法集合 |
| | | methods: { |
| | | // 点击刷新 |
| | | refreshTableList () { |
| | | this.page.current = 1; |
| | | refreshTableList() { |
| | | this.pagination.current = 1 |
| | | this.getTableList() |
| | | }, |
| | | // 分页切换 |
| | | pagination(page) { |
| | | this.page.current = page.page |
| | | this.page.size = page.limit |
| | | formatDate(value) { |
| | | return formatDateOnly(value) || '—' |
| | | }, |
| | | // 分页 |
| | | handleSizeChange(val) { |
| | | this.pagination.size = val |
| | | this.getTableList() |
| | | }, |
| | | getTableList () { |
| | | // 分页 |
| | | handleCurrentChange(val) { |
| | | this.pagination.current = val |
| | | this.getTableList() |
| | | }, |
| | | getTableList() { |
| | | if (!this.clickNodeVal.value) { |
| | | this.tableData = [] |
| | | this.pagination.total = 0 |
| | | return |
| | | } |
| | | this.tableLoading = true |
| | | selectDeviceMaintenancePage({ |
| | | deviceId: this.clickNodeVal.value, |
| | | ...this.page |
| | | current: this.pagination.current, |
| | | size: this.pagination.size, |
| | | }).then(res => { |
| | | this.tableLoading = false |
| | | this.tableData = res.data.records |
| | | this.page.total = res.data.total |
| | | }).catch(err => { |
| | | if (res.code == 200) { |
| | | this.tableData = res.data.records || [] |
| | | this.pagination.total = res.data.total || 0 |
| | | } |
| | | }).catch(() => { |
| | | this.tableLoading = false |
| | | }) |
| | | }, |
| | | // 打开操作弹框 |
| | | openDia (type, row) { |
| | | this.operationType = type |
| | | this.dialogVisible = true |
| | | this.$nextTick(() => { |
| | | this.$refs['form'].resetFields() |
| | | this.form.id = '' |
| | | if (this.operationType === 'edit') { |
| | | this.form = {...row} |
| | | this.form['maintenanceContentArr'] = this.form.maintenanceContent ? this.form.maintenanceContent.split(',') : [] |
| | | this.form['maintenanceContentText'] = this.form.maintenanceContent || '' |
| | | } |
| | | }) |
| | | this.getDictS() |
| | | this.getUserList() |
| | | }, |
| | | // 查询维护内容选择框内容 |
| | | getDictS () { |
| | | // 定义实验室名称与维护内容类型的映射关系 |
| | | const labTypeMapping = { |
| | | '老化室': 'aging_maintenance_content', |
| | | '老化实验室': 'aging_maintenance_content', |
| | | '电性能实验室': 'electrical_maintenance_content', |
| | | '环境实验室': 'environmental_maintenance_content', |
| | | '燃烧实验室': 'burn_maintenance_content', |
| | | '混炼实验室': 'mixing_maintenance_content', |
| | | '检测中心电性能实验室': 'center_electrical_maintenance_content', |
| | | '恒温二': 'temperature2_maintenance_content', |
| | | '恒温一': 'temperature1_maintenance_content', |
| | | '化学实验室': 'chemistry_maintenance_content', |
| | | '制样室': 'sample_maintenance_content', |
| | | '低温实验室': 'hypothermia_maintenance_content', |
| | | }; |
| | | // 取设备存放点名称作为映射键 |
| | | const name = this.clickNodeVal.storagePoint || '其他'; |
| | | // 根据映射关系获取对应的类型 |
| | | const type = labTypeMapping[name]; |
| | | if (!type) { |
| | | this.qualificationList = []; |
| | | return; |
| | | // 查看保养记录(只读) |
| | | handleView(row) { |
| | | this.form = { |
| | | deviceName: row.deviceName || '', |
| | | managementNumber: row.managementNumber || '', |
| | | maintenanceDate: formatDateOnly(row.maintenanceDate), |
| | | maintenanceUserName: row.maintenanceUserName || '', |
| | | remark: row.remark || '', |
| | | reviewUserName: row.reviewUserName || '', |
| | | reviewTime: formatListDate(row.reviewTime) || '', |
| | | reviewRemark: row.reviewRemark || '', |
| | | recordStatus: row.recordStatus, |
| | | } |
| | | this.getDicts(type).then((response) => { |
| | | this.qualificationList = response.data.map((m) => { |
| | | return { |
| | | label: m.dictLabel, |
| | | value: m.dictValue, |
| | | }; |
| | | }); |
| | | }); |
| | | this.checkColumns.forEach(item => { |
| | | this.form[item.prop] = row[item.prop] || '' |
| | | }) |
| | | this.dialogVisible = true |
| | | }, |
| | | openHandleOut () { |
| | | openHandleOut() { |
| | | if (!this.clickNodeVal.value) { |
| | | this.$message.warning('请先选择设备') |
| | | return |
| | | } |
| | | this.outLoading = true |
| | | exportDeviceMaintenance({ |
| | | deviceId: this.clickNodeVal.value |
| | | }).then(res => { |
| | | this.outLoading = false |
| | | saveBlobOrShowError(res, '设备维护保养.doc', 'application/msword') |
| | | saveBlobOrShowError(res, '仪器设备维护保养记录.docx', 'application/msword') |
| | | }).catch(() => { |
| | | this.outLoading = false |
| | | }) |
| | | |
| | | }, |
| | | // 只允许删除待审核/不通过的记录(历史与审核通过记录留档) |
| | | handleDeleteClick(row) { |
| | | this.$confirm('此操作将永久删除该条保养记录, 是否继续?', '提示', { |
| | | confirmButtonText: '确定', |
| | |
| | | type: 'success', |
| | | message: '删除成功!' |
| | | }); |
| | | this.refreshTableList() |
| | | this.getTableList() |
| | | }) |
| | | }).catch(() => { |
| | | this.$message({ |
| | |
| | | }); |
| | | }); |
| | | }, |
| | | // 提交新增和保存 |
| | | saveRecord () { |
| | | this.$refs.form.validate((valid) => { |
| | | if (valid) { |
| | | this.buttonLoading = true; |
| | | this.form.maintenanceContent = this.qualificationList.length |
| | | ? this.form.maintenanceContentArr.join(',') |
| | | : (this.form.maintenanceContentText || '').trim() |
| | | this.form.deviceId = this.clickNodeVal.value |
| | | addDeviceMaintenance(this.form).then(res => { |
| | | this.buttonLoading = false; |
| | | this.$message.success('新增成功') |
| | | this.closeDia() |
| | | this.getTableList() |
| | | }).catch(err => { |
| | | this.buttonLoading = false; |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | closeDia () { |
| | | this.$refs['form'].resetFields(); |
| | | this.dialogVisible = false |
| | | this.refreshTableList() |
| | | }, |
| | | // 获取负责人信息接口 |
| | | getUserList() { |
| | | selectUserCondition({type: 2}).then(res => { |
| | | if (res.code == 200) { |
| | | this.responsibleOptions = res.data |
| | | } |
| | | }) |
| | | }, |
| | | }, |
| | | watch: { |
| | | // 监听点击el-tree的数据,进行数据刷新 |
| | | clickNodeVal(newVal) { |
| | | if (newVal.value) { |
| | | this.refreshTableList(); |
| | | } |
| | | this.refreshTableList(); |
| | | }, |
| | | } |
| | | }; |
| | |
| | | |
| | | <style scoped> |
| | | .search { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | height: 46px; |
| | | text-align: right; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .form-section-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: var(--lims-text); |
| | | margin: 4px 0 16px; |
| | | padding-left: 8px; |
| | | border-left: 4px solid var(--el-color-primary); |
| | | } |
| | | </style> |
| | |
| | | </el-select> |
| | | </div> |
| | | <div> |
| | | <el-button size="small" type="primary" @click="loadPlan">刷新</el-button> |
| | | <el-button size="small" type="primary" @click="loadYearOptions(true)">刷新</el-button> |
| | | <el-button size="small" type="primary" :loading="outLoading" @click="handleDownOne">导出</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | :row-class-name="tableRowClassName" :height="'calc(100vh - 29em)'" style="width: 100%;"> |
| | | <el-table-column align="center" header-align="center" label="序号" prop="prop" type="index" |
| | | width="70"></el-table-column> |
| | | <el-table-column label="设备名称及型号" min-width="180" show-overflow-tooltip> |
| | | <el-table-column label="设备名称" min-width="150" prop="deviceName" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="设备型号" min-width="130" prop="specificationModel" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="设备编号" min-width="140" prop="deviceNumber"></el-table-column> |
| | | <el-table-column label="存放点" min-width="120" prop="storagePoint"></el-table-column> |
| | | <el-table-column align="center" header-align="center" label="审核日期" min-width="110"> |
| | | <template #default="scope">{{ formatReviewDate(scope.row) }}</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" header-align="center" label="维护保养内容"> |
| | | <el-table-column v-for="item in checkColumns" :key="item.prop" align="center" header-align="center" |
| | | :label="item.label" width="110"> |
| | | <template #default="scope">{{ scope.row[item.prop] || '—' }}</template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column align="center" header-align="center" label="维护人" min-width="100"> |
| | | <template #default="scope">{{ scope.row.maintenanceUserName || '—' }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="审核状态" min-width="100"> |
| | | <template #default="scope"> |
| | | {{ scope.row.deviceName }}{{ scope.row.specificationModel ? ' ' + scope.row.specificationModel : '' }} |
| | | <el-tag v-if="!scope.row.recordStatus" type="info" disable-transitions>未开始</el-tag> |
| | | <el-tag v-else-if="scope.row.recordStatus === 1" type="warning" disable-transitions>待审核</el-tag> |
| | | <el-tag v-else-if="scope.row.recordStatus === 2" type="success" disable-transitions>通过</el-tag> |
| | | <el-tag v-else-if="scope.row.recordStatus === 3" type="danger" disable-transitions>不通过</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="设备编号" min-width="140" prop="deviceNumber"></el-table-column> |
| | | <el-table-column label="归属实验室" min-width="120" prop="storagePoint"></el-table-column> |
| | | <el-table-column label="保养关键部位" min-width="150" prop="maintenanceSite" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="保养内容" min-width="180" prop="maintenanceContent" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="保养周期" min-width="100" prop="maintenanceIntervals"></el-table-column> |
| | | <el-table-column label="计划保养时间" min-width="130" prop="maintenanceDate" |
| | | :formatter="formatDateCell"></el-table-column> |
| | | <el-table-column align="center" fixed="right" label="操作" min-width="160"> |
| | | <el-table-column label="备注" min-width="140" show-overflow-tooltip> |
| | | <template #default="scope">{{ scope.row.recordRemark || '—' }}</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" fixed="right" label="操作" min-width="300"> |
| | | <template #default="scope"> |
| | | <el-button size="small" link type="primary" |
| | | :disabled="scope.row.recordStatus === 2 || scope.row.recordStatus === 3" |
| | | @click="handleForm('edit', scope.row)">编辑</el-button> |
| | | <el-button size="small" link type="primary" @click="handleForm('view', scope.row)">查看</el-button> |
| | | <el-button size="small" link type="danger" |
| | | @click="deleteRow(scope.row)">删除</el-button> |
| | | <el-button size="small" link type="primary" :disabled="!scope.row.recordId" |
| | | @click="handleForm('view', scope.row)">查看</el-button> |
| | | <el-button v-if="scope.row.recordStatus === 0 || scope.row.recordStatus === 1" |
| | | size="small" link type="primary" :disabled="!scope.row.maintenanceUserName" |
| | | @click="handleReview(scope.row)">审核</el-button> |
| | | <el-button v-if="scope.row.recordStatus !== 2" |
| | | size="small" link type="danger" @click="deleteRow(scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </el-pagination> |
| | | </div> |
| | | <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible" |
| | | title="设备保养计划明细" width="60%" @close="resetForm"> |
| | | <el-form ref="modelForm" :model="form" :rules="rules" label-width="130px"> |
| | | :title="dialogTitle" width="880px" @close="resetForm"> |
| | | <el-form ref="modelForm" :model="form" :rules="rules" label-width="150px" size="small"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备名称:"> |
| | | <el-input v-model="form.deviceName" disabled size="small"></el-input> |
| | | <el-input v-model="form.deviceName" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备型号:"> |
| | | <el-input v-model="form.specificationModel" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备编号:"> |
| | | <el-input v-model="form.deviceNumber" disabled size="small"></el-input> |
| | | <el-input v-model="form.deviceNumber" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="归属实验室:"> |
| | | <el-input v-model="form.storagePoint" disabled size="small"></el-input> |
| | | <el-form-item label="存放点:"> |
| | | <el-input v-model="form.storagePoint" disabled></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="保养周期:"> |
| | | <el-input v-model="form.maintenanceIntervals" :disabled="operationType === 'view'" clearable |
| | | size="small"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="保养关键部位:"> |
| | | <el-input v-model="form.maintenanceSite" :disabled="operationType === 'view'" clearable size="small" |
| | | type="textarea"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="保养内容:"> |
| | | <el-input v-model="form.maintenanceContent" :disabled="operationType === 'view'" clearable size="small" |
| | | type="textarea"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="计划保养时间:" prop="maintenanceDate"> |
| | | <el-date-picker v-model="form.maintenanceDate" :disabled="operationType === 'view'" clearable |
| | | format="YYYY-MM-DD" placeholder="选择日期" size="small" style="width:100%" type="date" |
| | | <el-form-item label="维护日期:" prop="maintenanceDate"> |
| | | <el-date-picker v-model="form.maintenanceDate" :disabled="!isEdit" clearable |
| | | format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%" type="date" |
| | | value-format="YYYY-MM-DD"></el-date-picker> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维护人:" prop="maintenanceUserId"> |
| | | <el-select v-model="form.maintenanceUserId" :disabled="!isEdit" clearable filterable |
| | | placeholder="请选择" style="width: 100%"> |
| | | <el-option v-for="item in maintainerOptions" :key="item.id" :label="item.name" |
| | | :value="item.id"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <div class="form-section-title">维护保养内容</div> |
| | | <el-row> |
| | | <el-col v-for="item in checkColumns" :key="item.prop" :span="12"> |
| | | <el-form-item :label="item.label + ':'" :prop="item.prop"> |
| | | <el-radio-group v-model="form[item.prop]" :disabled="!isEdit"> |
| | | <el-radio value="√">√</el-radio> |
| | | <el-radio value="×">×</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="保养备注:"> |
| | | <el-input v-model="form.remark" :disabled="!isEdit" :rows="2" placeholder="可填写保养备注" |
| | | type="textarea"></el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="operationType === 'review'" label="审核备注:"> |
| | | <el-input v-model="form.reviewRemark" :rows="2" placeholder="可填写审核意见" |
| | | type="textarea"></el-input> |
| | | </el-form-item> |
| | | <div class="check-note">备注:正常、良好打“√”,不正常及否打“×”。</div> |
| | | <div v-if="cycleNote" class="check-note">{{ cycleNote }}</div> |
| | | </el-form> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="resetForm">取 消</el-button> |
| | | <el-button :loading="submitFormLoading" type="primary" @click="submitForm" |
| | | v-if="operationType !== 'view'">确 认</el-button> |
| | | <template v-if="operationType === 'review'"> |
| | | <el-button :loading="reviewLoading" @click="submitReview(0)">不通过</el-button> |
| | | <el-button :loading="reviewLoading" type="primary" @click="submitReview(1)">通 过</el-button> |
| | | </template> |
| | | <el-button v-else-if="operationType === 'edit'" :loading="submitFormLoading" type="primary" |
| | | @click="submitForm">确 认</el-button> |
| | | </span></template> |
| | | </el-dialog> |
| | | </div> |
| | |
| | | |
| | | <script> |
| | | import { |
| | | selectDeviceMaintenancePlanByPage, |
| | | getMaintenancePlanYears, |
| | | getMaintenancePlanByYear, |
| | | pageMaintenancePlanDetail, |
| | | updateMaintenancePlanDetail, |
| | | deleteMaintenancePlanDetail, |
| | | exportDeviceMaintenancePlan, |
| | | addDeviceMaintenance, |
| | | reviewDeviceMaintenance, |
| | | } from '@/api/cnas/resourceDemand/device.js' |
| | | import { selectUserCondition } from '@/api/system/user' |
| | | import dayjs from 'dayjs' |
| | | import { formatDateOnly } from './dateFormat' |
| | | import { saveBlobOrShowError } from '@/utils/saveBlob' |
| | | |
| | | // 维护保养检查项,与仪器设备维护保养记录表一致 |
| | | const CHECK_ITEMS = [ |
| | | { label: '外观是否良好', prop: 'appearanceGood' }, |
| | | { label: '是否可以正常使用', prop: 'normalUse' }, |
| | | { label: '是否清洁仪器表面', prop: 'surfaceClean' }, |
| | | { label: '标识是否完好', prop: 'labelIntact' }, |
| | | { label: '显示器灯是否正常', prop: 'displayLightNormal' }, |
| | | { label: '仪器是否生锈', prop: 'noRust' }, |
| | | { label: '校准是否正常', prop: 'calibrationNormal' }, |
| | | { label: '配件是否需要更换', prop: 'partsReplace' }, |
| | | { label: '维护结果是否正常', prop: 'resultNormal' }, |
| | | ] |
| | | |
| | | export default { |
| | | name: "equipment-maintenance-plan", |
| | | props: { |
| | |
| | | } |
| | | }, |
| | | data() { |
| | | const rules = { |
| | | maintenanceDate: [{ required: true, message: '请选择维护日期', trigger: 'change' }], |
| | | maintenanceUserId: [{ required: true, message: '请选择维护人', trigger: 'change' }], |
| | | } |
| | | return { |
| | | planYear: '', |
| | | yearOptions: [], |
| | |
| | | current: 1, |
| | | total: 0, |
| | | }, |
| | | checkColumns: CHECK_ITEMS.map(item => ({ ...item })), |
| | | dialogVisible: false, |
| | | operationType: '', |
| | | form: {}, |
| | | rules: { |
| | | maintenanceDate: [{ required: true, message: '请选择计划保养时间', trigger: 'change' }], |
| | | }, |
| | | rules, |
| | | submitFormLoading: false, |
| | | outLoading: false, |
| | | reviewLoading: false, |
| | | userOptions: [], |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.loadYearOptions() |
| | | this.getUserList() |
| | | }, |
| | | methods: { |
| | | // 年份下拉选项:已有计划年份 + 当前年份 |
| | | loadYearOptions() { |
| | | // 年份下拉:只列出有明细的年份(空年份计划由后端删除),默认显示本年度(本年度无计划时退回最新年份) |
| | | loadYearOptions(preserveYear = false) { |
| | | const currentYear = String(new Date().getFullYear()) |
| | | const finish = (years) => { |
| | | if (years.indexOf(currentYear) === -1) { |
| | | years.push(currentYear) |
| | | let list = [...new Set(years.map(y => String(y)).filter(Boolean))] |
| | | list.sort((a, b) => b.localeCompare(a)) |
| | | if (!list.length) { |
| | | list = [currentYear] |
| | | } |
| | | this.yearOptions = [...new Set(years)].sort((a, b) => b.localeCompare(a)) |
| | | this.planYear = currentYear |
| | | this.yearOptions = list |
| | | const keep = preserveYear && this.planYear && list.includes(String(this.planYear)) |
| | | this.planYear = keep ? String(this.planYear) : (list.includes(currentYear) ? currentYear : list[0]) |
| | | this.loadPlan() |
| | | } |
| | | selectDeviceMaintenancePlanByPage({ |
| | | current: 1, |
| | | size: 99, |
| | | }).then(res => { |
| | | let years = [] |
| | | if (res.code == 200) { |
| | | years = (res.data.records || []).map(r => r.planYear).filter(Boolean) |
| | | } |
| | | finish(years) |
| | | getMaintenancePlanYears().then(res => { |
| | | finish(res.code == 200 ? (res.data || []) : []) |
| | | }).catch(() => { |
| | | finish([]) |
| | | }) |
| | |
| | | this.tableLoading = false |
| | | }) |
| | | }, |
| | | // 到点需保养的行标红 |
| | | formatDateCell(row, column, cellValue) { |
| | | return formatDateOnly(cellValue) |
| | | // 未审核显示计划保养时间;审核通过后显示审核当天(与核查计划一致) |
| | | formatReviewDate(row) { |
| | | const date = row.reviewStatus === 1 ? row.reviewTime : row.maintenanceDate |
| | | return formatDateOnly(date) || '—' |
| | | }, |
| | | tableRowClassName({ row }) { |
| | | return row.redFlag === 1 ? 'red-row' : '' |
| | |
| | | this.pagination1.current = val |
| | | this.getTableList() |
| | | }, |
| | | // 打开明细弹框 |
| | | // 打开明细弹框:edit 填写/修改保养记录,view 查看,review 审核 |
| | | handleForm(type, row) { |
| | | this.operationType = type |
| | | this.form = this.HaveJson(row) |
| | | this.form = this.buildForm(row) |
| | | this.dialogVisible = true |
| | | this.$nextTick(() => { |
| | | if (this.$refs.modelForm) { |
| | |
| | | } |
| | | }) |
| | | }, |
| | | // 提交表单(只回传明细表字段) |
| | | buildForm(row) { |
| | | const form = { |
| | | id: row.recordId || null, |
| | | maintenancePlanDetailId: row.maintenancePlanDetailId, |
| | | deviceId: row.deviceId, |
| | | deviceName: row.deviceName, |
| | | specificationModel: row.specificationModel, |
| | | deviceNumber: row.deviceNumber, |
| | | storagePoint: row.storagePoint, |
| | | // 已有记录用记录日期;还没记录时默认今天,避免把计划日期当成实际保养日期 |
| | | maintenanceDate: row.recordId |
| | | ? formatDateOnly(row.recordMaintenanceDate) |
| | | : dayjs().format('YYYY-MM-DD'), |
| | | maintenanceCycle: row.maintenanceCycle || row.maintenanceIntervals || '', |
| | | maintenanceUserId: row.maintenanceUserId || '', |
| | | maintenanceUserName: row.maintenanceUserName || '', |
| | | remark: row.recordRemark || '', |
| | | reviewRemark: '', |
| | | } |
| | | this.checkColumns.forEach(item => { |
| | | form[item.prop] = row[item.prop] || '' |
| | | }) |
| | | return form |
| | | }, |
| | | // 保存保养记录(新增或修改后进入待审核) |
| | | submitForm() { |
| | | this.$refs.modelForm.validate(valid => { |
| | | if (valid) { |
| | | this.submitFormLoading = true |
| | | const payload = { |
| | | maintenancePlanDetailId: this.form.maintenancePlanDetailId, |
| | | maintenancePlanId: this.form.maintenancePlanId, |
| | | deviceId: this.form.deviceId, |
| | | maintenanceSite: this.form.maintenanceSite, |
| | | maintenanceContent: this.form.maintenanceContent, |
| | | maintenanceIntervals: this.form.maintenanceIntervals, |
| | | maintenanceDate: this.form.maintenanceDate, |
| | | } |
| | | updateMaintenancePlanDetail(payload).then(res => { |
| | | if (res.code == 200) { |
| | | this.$message.success('修改成功') |
| | | this.dialogVisible = false |
| | | this.getTableList() |
| | | } |
| | | this.submitFormLoading = false |
| | | }).catch(() => { |
| | | this.submitFormLoading = false |
| | | }) |
| | | if (!valid) { |
| | | return |
| | | } |
| | | this.submitFormLoading = true |
| | | const payload = { |
| | | maintenancePlanDetailId: this.form.maintenancePlanDetailId, |
| | | deviceId: this.form.deviceId, |
| | | maintenanceDate: this.form.maintenanceDate, |
| | | maintenanceUserId: this.form.maintenanceUserId, |
| | | remark: this.form.remark, |
| | | } |
| | | if (this.form.id) { |
| | | payload.id = this.form.id |
| | | } |
| | | this.checkColumns.forEach(item => { |
| | | payload[item.prop] = this.form[item.prop] |
| | | }) |
| | | addDeviceMaintenance(payload).then(res => { |
| | | this.submitFormLoading = false |
| | | if (res.code == 200) { |
| | | this.$message.success(this.form.id ? '修改成功' : '保存成功') |
| | | this.dialogVisible = false |
| | | this.loadPlan() |
| | | } |
| | | }).catch(() => { |
| | | this.submitFormLoading = false |
| | | }) |
| | | }) |
| | | }, |
| | | resetForm() { |
| | |
| | | }, |
| | | // 明细-删除 |
| | | deleteRow(row) { |
| | | this.$confirm('此操作将永久删除该条明细, 是否继续?', '提示', { |
| | | this.$confirm('删除后,该行的保养记录(未审核或审核不通过)会一并删除,是否继续?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | deleteMaintenancePlanDetail({ maintenancePlanDetailId: row.maintenancePlanDetailId }).then(() => { |
| | | this.$message.success('删除成功!'); |
| | | this.getTableList() |
| | | // 删完可能是该年份最后一条,重新取年份,空年份会一并清掉 |
| | | this.loadYearOptions(true) |
| | | }); |
| | | }).catch(() => { |
| | | this.$message({ |
| | |
| | | }).catch(() => { |
| | | this.outLoading = false |
| | | }) |
| | | } |
| | | }, |
| | | // 打开保养记录审核弹框 |
| | | handleReview(row) { |
| | | this.handleForm('review', row) |
| | | }, |
| | | // 提交审核结果:1 通过,0 不通过 |
| | | submitReview(status) { |
| | | this.reviewLoading = true |
| | | reviewDeviceMaintenance({ |
| | | maintenancePlanDetailId: this.form.maintenancePlanDetailId, |
| | | reviewStatus: status, |
| | | reviewRemark: this.form.reviewRemark, |
| | | }).then(res => { |
| | | this.reviewLoading = false |
| | | if (res.code == 200) { |
| | | this.$message.success(status === 1 ? '审核通过' : '审核不通过') |
| | | this.dialogVisible = false |
| | | // 审核通过后明细会归到审核年份的计划,重新取年份避免停在不存在的年份 |
| | | this.loadYearOptions(true) |
| | | } |
| | | }).catch(() => { |
| | | this.reviewLoading = false |
| | | }) |
| | | }, |
| | | // 维护人下拉 |
| | | getUserList() { |
| | | selectUserCondition({ type: 2 }).then(res => { |
| | | if (res.code == 200) { |
| | | this.userOptions = res.data || [] |
| | | } |
| | | }) |
| | | }, |
| | | }, |
| | | computed: { |
| | | // 是否已完成审核(通过/不通过) |
| | | isAudited() { |
| | | return this.planInfo.status === 0 || this.planInfo.status === 1; |
| | | }, |
| | | // 仅编辑状态可填写表单 |
| | | isEdit() { |
| | | return this.operationType === 'edit' |
| | | }, |
| | | // 按设备档案的保养周期(月)生成底部说明 |
| | | cycleNote() { |
| | | const months = parseInt((this.form && this.form.maintenanceCycle) || '', 10) |
| | | if (!months || months <= 0) { |
| | | return '' |
| | | } |
| | | if (months === 1) { |
| | | return '此设备维护保养每月 1 次。' |
| | | } |
| | | if (months === 3) { |
| | | return '此设备维护保养每季度 1 次。' |
| | | } |
| | | if (months === 6) { |
| | | return '此设备维护保养每半年 1 次。' |
| | | } |
| | | if (months === 12) { |
| | | return '此设备维护保养每年 1 次。' |
| | | } |
| | | if (months % 12 === 0) { |
| | | return `此设备维护保养每 ${months / 12} 年 1 次。` |
| | | } |
| | | return `此设备维护保养每 ${months} 个月 1 次。` |
| | | }, |
| | | dialogTitle() { |
| | | if (this.operationType === 'view') { |
| | | return '查看保养记录' |
| | | } |
| | | if (this.operationType === 'review') { |
| | | return '保养记录审核' |
| | | } |
| | | return '编辑保养记录' |
| | | }, |
| | | // 已选维护人不在当前人员列表时补一条,保证下拉能显示姓名 |
| | | maintainerOptions() { |
| | | const list = this.userOptions.slice() |
| | | const form = this.form || {} |
| | | if (form.maintenanceUserId && !list.some(item => item.id === form.maintenanceUserId)) { |
| | | list.unshift({ |
| | | id: form.maintenanceUserId, |
| | | name: form.maintenanceUserName || String(form.maintenanceUserId), |
| | | }) |
| | | } |
| | | return list |
| | | }, |
| | | }, |
| | | } |
| | |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .form-section-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: var(--lims-text); |
| | | margin: 4px 0 16px; |
| | | padding-left: 8px; |
| | | border-left: 4px solid var(--el-color-primary); |
| | | } |
| | | |
| | | .check-note { |
| | | font-size: 13px; |
| | | color: #909399; |
| | | line-height: 22px; |
| | | padding-left: 150px; |
| | | } |
| | | |
| | | :deep(.red-row td) { |
| | | background: #ffcccc !important; |
| | | } |
| | |
| | | <el-table-column label="设备编号" min-width="170" prop="deviceNumber"></el-table-column> |
| | | <el-table-column label="设备名称" min-width="180" prop="deviceName" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="设备型号" min-width="120" prop="deviceModel" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="核查时间" min-width="120" prop="checkTime" |
| | | :formatter="formatCheckMonth"></el-table-column> |
| | | <el-table-column label="核查时间" min-width="120"> |
| | | <template #default="scope"> |
| | | {{ scope.row.completeDate || formatCheckMonth(null, null, scope.row.checkTime) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="核查指标" min-width="140" prop="checkIndex"> </el-table-column> |
| | | <el-table-column label="核查方法" min-width="140" prop="checkMethod" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="结果如何判定" min-width="140" prop="howResults" show-overflow-tooltip></el-table-column> |
| | |
| | | @click="handleRecord(scope.row)">审核</el-button> |
| | | <el-button v-if="scope.row.recordStatus === 2 || scope.row.recordStatus === 3" |
| | | size="small" link type="primary" @click="handleDown(scope.row)">导出</el-button> |
| | | <el-button v-if="scope.row.recordStatus === 0 || scope.row.recordStatus === 1" |
| | | <el-button v-if="scope.row.recordStatus !== 2" |
| | | size="small" link type="danger" @click="deleteFun1(scope.row.planDetailsId)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | <span class="export-panel-label">设备名称</span>{{ downRow.deviceName || '—' }} |
| | | </div> |
| | | <div class="export-panel-item"> |
| | | <span class="export-panel-label">核查时间</span>{{ formatCheckMonth(null, null, downRow.checkTime) || '—' }} |
| | | <span class="export-panel-label">核查时间</span>{{ downRow.completeDate || formatCheckMonth(null, null, downRow.checkTime) || '—' }} |
| | | </div> |
| | | </div> |
| | | <div v-if="!canExport" class="export-panel-tip"> |
| | |
| | | import CheckRecord from "./checkRecord.vue"; |
| | | import LimsAttachment from '@/components/Attachment/lims-attachment.vue' |
| | | import { |
| | | pageDeviceExaminePlan, |
| | | getExaminePlanByYear, |
| | | getExaminePlanYears, |
| | | exportDeviceExaminePlanDetail, |
| | | delDeviceExaminePlanDetail, |
| | | pageDeviceExaminePlanDetail, |
| | |
| | | }, |
| | | // 方法集合 |
| | | methods: { |
| | | // 年份下拉只保留有计划明细的年份,空年份自动消失 |
| | | // 年份下拉只保留有计划明细的年份,空年份计划自动删除,默认显示本年度(本年度无计划时退回最新年份) |
| | | loadYearOptions() { |
| | | pageDeviceExaminePlan({ |
| | | current: 1, |
| | | size: 99, |
| | | }).then(res => { |
| | | let years = [] |
| | | if (res.code == 200) { |
| | | years = (res.data.records || []).map(r => r.planYear).filter(Boolean) |
| | | } |
| | | const options = [...new Set(years)].sort((a, b) => b.localeCompare(a)) |
| | | this.yearOptions = options |
| | | const currentYear = String(new Date().getFullYear()) |
| | | const finish = (years) => { |
| | | let options = [...new Set((years || []).map(y => String(y)).filter(Boolean))] |
| | | options.sort((a, b) => b.localeCompare(a)) |
| | | if (options.length === 0) { |
| | | this.planYear = '' |
| | | this.planInfo = {} |
| | | this.yearTableDetailData = [] |
| | | this.pagination1.total = 0 |
| | | return |
| | | options = [currentYear] |
| | | } |
| | | if (options.indexOf(this.planYear) === -1) { |
| | | const currentYear = String(new Date().getFullYear()) |
| | | this.planYear = options.indexOf(currentYear) > -1 ? currentYear : options[0] |
| | | } |
| | | this.yearOptions = options |
| | | const keep = options.indexOf(String(this.planYear)) > -1 |
| | | this.planYear = keep ? String(this.planYear) : (options.includes(currentYear) ? currentYear : options[0]) |
| | | this.loadPlan() |
| | | } |
| | | getExaminePlanYears().then(res => { |
| | | finish(res.code == 200 ? (res.data || []) : []) |
| | | }).catch(() => { |
| | | finish([]) |
| | | }) |
| | | }, |
| | | // 切换年份 |
| | |
| | | }, |
| | | // 明细-删除 |
| | | deleteFun1(id) { |
| | | this.$confirm('删除后,该行未审核的核查记录及附件会一并删除;若该设备还有审核通过的核查记录,档案的最近核查日期将回退到最近一次完成记录;若没有,则清空档案的核查日期和核查周期。是否继续?', '提示', { |
| | | this.$confirm('删除后,该行的核查记录(未审核或审核不通过)及附件会一并删除;若该设备还有审核通过的核查记录,档案的最近核查日期将回退到最近一次完成记录;若没有,则清空档案的核查日期和核查周期。是否继续?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | |
| | | }); |
| | | }); |
| | | }, |
| | | // 导出年度计划表 |
| | | // 导出年度计划表(Excel):有筛选条件导出筛选结果,没有筛选导出该年份全部 |
| | | downLoadPost() { |
| | | exportDeviceExaminePlanDetail({ planId: this.planInfo.planId }).then(res => { |
| | | this.saveDocx(res, '仪器设备期间核查计划表.docx') |
| | | exportDeviceExaminePlanDetail({ |
| | | planId: this.planInfo.planId, |
| | | deviceName: this.searchForm.deviceName, |
| | | deviceNumber: this.searchForm.deviceNumber, |
| | | }).then(res => { |
| | | const planName = this.planInfo.planName || (this.planYear ? this.planYear + '年度设备核查计划' : '设备核查计划') |
| | | this.saveDocx(res, planName + '.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') |
| | | }).catch(() => { }) |
| | | }, |
| | | // 本次是否有改动(含打开时恢复的草稿) |
| | |
| | | this.downloadDialog = true |
| | | }, |
| | | // 导出结果拦截: 后端返回错误 JSON 时提示错误, 不存成坏文件 |
| | | saveDocx(res, filename) { |
| | | saveDocx(res, filename, mime = 'application/msword') { |
| | | const reader = new FileReader(); |
| | | reader.readAsText(res, 'utf-8'); |
| | | reader.onload = () => { |
| | |
| | | try { msg = JSON.parse(text).msg || msg; } catch (e) { } |
| | | this.$message.error(msg); |
| | | } else { |
| | | this.$download.saveAs(new Blob([res], { type: 'application/msword' }), filename); |
| | | this.$download.saveAs(new Blob([res], { type: mime }), filename); |
| | | } |
| | | }; |
| | | reader.onerror = () => { |
| | | this.$download.saveAs(new Blob([res], { type: 'application/msword' }), filename); |
| | | this.$download.saveAs(new Blob([res], { type: mime }), filename); |
| | | }; |
| | | }, |
| | | // 核查记录导出 |
| | |
| | | <el-table-column type="selection" width="55"></el-table-column> |
| | | <el-table-column label="设备名称" prop="label" width="190"></el-table-column> |
| | | <el-table-column prop="value" label="设备编号" width="130"></el-table-column> |
| | | <el-table-column prop="storagePoint" label="归属实验室"></el-table-column> |
| | | <el-table-column prop="storagePoint" label="存放点"></el-table-column> |
| | | </el-table> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="addEquipDia = false">取 消</el-button> |
| | |
| | | </el-input> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td class="td-title"> |
| | | <p>照片:</p> |
| | | </td> |
| | | <td class="td-info" colspan="5"> |
| | | <lims-attachment ref="photoAttachment" inline defer-upload accept=".jpg,.jpeg,.png,.gif" |
| | | :main-id="form.clientSatisfactionId || ''" upload-url="/clientSatisfaction/uploadAttachment" |
| | | select-url="/clientSatisfaction/selectAttachments" delete-url="/clientSatisfaction/deleteAttachment" |
| | | id-param="clientSatisfactionId" tip="支持 jpg / png / gif 照片,可预览,提交时一并上传"></lims-attachment> |
| | | </td> |
| | | </tr> |
| | | </table> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="closeFormDia">取 消</el-button> |
| | |
| | | updateClientSatisfaction |
| | | } from '@/api/cnas/systemManagement/customerSatisfaction.js' |
| | | import { selectCompletedOrders } from '@/api/business/productOrder' |
| | | import limsAttachment from '@/components/Attachment/lims-attachment.vue' |
| | | export default { |
| | | name: 'formDialog', |
| | | // import 引入的组件需要注入到对象中才能使用 |
| | | components: {}, |
| | | components: { limsAttachment }, |
| | | data() { |
| | | // 这里存放数据 |
| | | return { |
| | |
| | | } |
| | | if (this.operationType === 'add') { |
| | | addClientSatisfaction(payload).then(res => { |
| | | this.editLoad = false |
| | | this.$message.success('提交成功') |
| | | this.closeFormDia() |
| | | // 后端返回保存后的记录(含自增id),用于把新增时暂存的照片传上去 |
| | | const savedId = res.data && res.data.clientSatisfactionId |
| | | this.finishSave(savedId) |
| | | }).catch(err => { |
| | | console.log('err---', err); |
| | | this.editLoad = false |
| | | }) |
| | | } else { |
| | | updateClientSatisfaction(payload).then(res => { |
| | | this.editLoad = false |
| | | this.$message.success('提交成功') |
| | | this.closeFormDia() |
| | | updateClientSatisfaction(payload).then(() => { |
| | | this.finishSave(this.form.clientSatisfactionId) |
| | | }).catch(err => { |
| | | console.log('err---', err); |
| | | this.editLoad = false |
| | | }) |
| | | } |
| | | }, |
| | | // 记录保存成功后上传暂存照片;照片上传失败不影响记录本身 |
| | | finishSave(clientSatisfactionId) { |
| | | this.uploadPendingPhotos(clientSatisfactionId).then(() => { |
| | | this.editLoad = false |
| | | this.$message.success('提交成功') |
| | | this.closeFormDia() |
| | | }).catch(err => { |
| | | console.log('照片上传失败', err) |
| | | this.editLoad = false |
| | | this.$message.warning('记录已保存,但照片上传失败,请回到列表用“附件”补充上传') |
| | | this.closeFormDia() |
| | | }) |
| | | }, |
| | | uploadPendingPhotos(clientSatisfactionId) { |
| | | const attachment = this.$refs.photoAttachment |
| | | if (!attachment || !attachment.pendingFiles.length) { |
| | | return Promise.resolve() |
| | | } |
| | | if (!clientSatisfactionId) { |
| | | return Promise.reject(new Error('未获取到记录id,无法上传照片')) |
| | | } |
| | | return attachment.flushPending(clientSatisfactionId) |
| | | }, |
| | | closeFormDia() { |
| | | this.formDia = false; |
| | | this.$emit('closeFormDia') |