| | |
| | | width="70"></el-table-column> |
| | | <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="checkTime" |
| | | :formatter="formatCheckMonth"></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"> |
| | | <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.recordContrastStatus === 0" |
| | | <el-button v-if="scope.row.recordStatus !== 2" |
| | | size="small" link type="danger" @click="deleteFun1(scope.row.planDetailsId)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | <div class="form-section-title">基本信息</div> |
| | | <el-row :gutter="12"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="仪器名称:" prop="deviceName"> |
| | | <el-form-item label="设备名称:" prop="deviceName"> |
| | | <el-input v-model="form.deviceName" disabled size="small"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检查日期:" prop="checkTime"> |
| | | <el-date-picker v-model="form.checkTime" :disabled="operationType === 'view'" clearable |
| | | format="YYYY-MM" placeholder="选择检查日期" size="small" style="width:100%" type="month" |
| | | value-format="YYYY-MM"> |
| | | </el-date-picker> |
| | | <el-input v-if="operationType === 'view'" :model-value="formatCheckMonth(null, null, form.checkTime)" |
| | | disabled size="small"></el-input> |
| | | <template v-else> |
| | | <el-date-picker v-model="checkTimeEditValue" clearable format="YYYY-MM-DD" placeholder="选择检查日期" |
| | | size="small" style="width:100%" type="date" value-format="YYYY-MM-DD"> |
| | | </el-date-picker> |
| | | <div v-if="isMonthOnlyCheckTime" class="check-time-tip">系统登记只到月份,选择具体日期后将按日保存</div> |
| | | </template> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | |
| | | </div> |
| | | </el-form> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="resetForm">取 消</el-button> |
| | | <el-button @click="handleCancel">取 消</el-button> |
| | | <el-button :loading="submitFormLoading" type="primary" @click="submitForm" |
| | | v-if="operationType !== 'view'">确 认</el-button> |
| | | </span></template> |
| | |
| | | <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([]) |
| | | }) |
| | | }, |
| | | // 切换年份 |
| | |
| | | this.$nextTick(() => { |
| | | this.form = this.HaveJson(row) |
| | | if (this.operationType !== 'view') { |
| | | this.draftRestore('equipmentVerificationPlan', 'form', this.form.planDetailsId, 'dialogVisible') |
| | | const rowDeviceName = this.form.deviceName |
| | | this.draftRestore('equipmentVerificationPlan', 'form', this.form.planDetailsId, 'dialogVisible', |
| | | // 设备名称是禁用字段,草稿里为空说明是被表单重置清空的废草稿,直接丢弃 |
| | | draft => !!draft.deviceName || !rowDeviceName) |
| | | } |
| | | }) |
| | | }, |
| | |
| | | }, |
| | | // 明细-删除 |
| | | 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(() => { }) |
| | | }, |
| | | // 本次是否有改动(含打开时恢复的草稿) |
| | | hasUnsavedEdit() { |
| | | const state = this.draftStates && this.draftStates['equipmentVerificationPlan'] |
| | | return !!state && this.draftSnapshot(state) !== state.baseline |
| | | }, |
| | | // 取消:无编辑直接退出;有编辑先确认,确认后丢弃草稿退出 |
| | | handleCancel() { |
| | | if (this.operationType === 'view' || !this.hasUnsavedEdit()) { |
| | | this.dialogVisible = false |
| | | return |
| | | } |
| | | this.$confirm('是否确认取消编辑?本次编辑记录不保存!', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '继续编辑', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | this.draftClear('equipmentVerificationPlan') |
| | | this.dialogVisible = false |
| | | }).catch(() => { }) |
| | | }, |
| | | resetForm() { |
| | | // 右上角关闭时 close 事件先于显隐监听触发,先把草稿存下再重置表单,避免重置后的空内容被存成草稿 |
| | | this.draftStop('equipmentVerificationPlan') |
| | | this.$refs.modelForm.resetFields(); |
| | | this.dialogVisible = false |
| | |
| | | }, |
| | | // 打开附件 |
| | | openAttachment(row) { |
| | | const isImage = /\.(jpg|jpeg|png|gif)$/i.test(row.fileUrl) |
| | | window.open(this.javaApi + (isImage ? '/img/' : '/word/') + row.fileUrl, '_blank') |
| | | return this.$download.saveAs(row.fileUrl, row.fileName) |
| | | }, |
| | | // 列表附件列只读查看(上传/删除入口只在编辑、新增弹窗内) |
| | | handleAttachment(row) { |
| | |
| | | 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); |
| | | }; |
| | | }, |
| | | // 核查记录导出 |
| | |
| | | return [...list, { id, name: this.form.checkChargerUser || String(id) }] |
| | | } |
| | | return list |
| | | }, |
| | | // 日期控件只接受 YYYY-MM-DD;系统登记的待核查行只有年月,未改日期时不能把“日”写进表单 |
| | | checkTimeEditValue: { |
| | | get() { |
| | | const val = this.form.checkTime || '' |
| | | return /^\d{4}-\d{2}$/.test(val) ? `${val}-01` : val |
| | | }, |
| | | set(val) { |
| | | this.form.checkTime = val || '' |
| | | } |
| | | }, |
| | | isMonthOnlyCheckTime() { |
| | | return /^\d{4}-\d{2}$/.test(this.form.checkTime || '') |
| | | }, |
| | | }, |
| | | } |
| | |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .check-time-tip { |
| | | width: 100%; |
| | | font-size: 12px; |
| | | line-height: 1.4; |
| | | color: #909399; |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | .export-panel { |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 6px; |