| | |
| | | </div> |
| | | </div> |
| | | <div class="plan-detail-card"> |
| | | <el-alert v-if="currentPlan && currentPlan.ratifyStatus !== 1" type="info" :closable="false" show-icon |
| | | style="margin-bottom: 12px" |
| | | title="检测类质控项目需在年度计划审核、批准通过后,点击对应行的“下发任务”进行下发;非检测类项目无需下发。" /> |
| | | <div class="plan-detail-toolbar"> |
| | | <div style="display: flex;"> |
| | | <span class="section-title">质控项目</span> |
| | | <div style="margin-bottom: 18px;margin-right: 10px;display: flex;align-items: center;line-height: 32px;"> |
| | | <span style="width: 88px;font-size: 14px;font-weight: 700;color: var(--lims-text-2);">质控项目</span> |
| | | <el-input v-model="yearDetailForm.monitorProject" placeholder="请输入" size="small" |
| | |
| | | <!--导入计划--> |
| | | <el-dialog v-model="uploadDia" title="数据导入" width="500px" :close-on-click-modal="false" |
| | | :close-on-press-escape="false"> |
| | | <div style="display: flex; align-items: center;"> |
| | | <span style="width: 60px">年份:</span> |
| | | <el-date-picker v-model="planYear" type="year" value-format="YYYY" clearable size="small" format="YYYY" |
| | | placeholder="选择年"> |
| | | </el-date-picker> |
| | | </div> |
| | | <div style="display: flex;align-items: center;margin: 10px 0"> |
| | | <div style="width: 60px">审核人:</div> |
| | | <el-select v-model="examineUserId" clearable filterable size="small" style="width: 50%;"> |
| | | <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id"> |
| | | </el-option> |
| | | </el-select> |
| | | <el-form label-width="70px" size="small"> |
| | | <el-form-item label="年份"> |
| | | <el-date-picker v-model="planYear" type="year" value-format="YYYY" clearable format="YYYY" |
| | | placeholder="选择年" style="width: 100%"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item label="审核人"> |
| | | <el-select v-model="examineUserId" clearable filterable 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> |
| | | </el-form> |
| | | <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 10px; padding: 8px 12px; border-radius: 4px; background: var(--el-color-primary-light-9); font-size: 13px;"> |
| | | <span>第一次导入请先下载模板,按模板格式填写后再上传。</span> |
| | | <el-button link type="primary" @click="downloadTemplate">下载导入模板</el-button> |
| | | </div> |
| | | <div style="margin: 0 auto;"> |
| | | <el-upload ref="upload" :action="action" :auto-upload="false" :file-list="fileList" :headers="uploadHeader" |
| | | :limit="1" accept='.jpg,.jpeg,.png,.gif,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.zip,.rar' |
| | | <el-upload ref="upload" :action="action" :auto-upload="false" v-model:file-list="fileList" :headers="uploadHeader" |
| | | :limit="1" accept=".xls,.xlsx" |
| | | :on-change="beforeUpload" :on-error="onError" :on-success="handleSuccessUp" drag |
| | | :data="{ planYear: planYear, examineUserId: examineUserId }" name="file"> |
| | | :data="{ monitorYear: planYear, examineUserId: examineUserId }" name="file"> |
| | | <lims-icon name="el-icon-upload"></lims-icon> |
| | | <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> |
| | | </el-upload> |
| | | </div> |
| | | <div style="margin-top: 10px; color: var(--el-text-color-secondary); font-size: 12px; line-height: 20px;"> |
| | | <div>支持格式:.xls、.xlsx;单个文件不超过10MB。</div> |
| | | <div>质控项目、技术标准、质控方式、完成时限、负责人为必填项。</div> |
| | | <div>完成时限格式必须为 YYYY-MM(模板中该列为文本格式,直接输入 2026-12 即可);负责人必须填写系统中已存在的人员姓名。</div> |
| | | <div>导入后计划保存为草稿。请在计划详情中编辑质控项目并选择事项类别;检测类还需选择检测标准、原始记录模板、检测员、评价人并填写任务截止日,确认后再提交审核。</div> |
| | | <div>导入只读取模板的第一个工作表。</div> |
| | | </div> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="uploadDia = false">取 消</el-button> |
| | |
| | | </div> |
| | | <div style="margin: 0 auto;"> |
| | | <el-upload ref="upload1" :action="action1" :auto-upload="false" |
| | | :data="{ qualityMonitorDetailsId: qualityMonitorDetailsId }" :file-list="fileList1" :headers="uploadHeader" |
| | | :data="{ qualityMonitorDetailsId: qualityMonitorDetailsId }" v-model:file-list="fileList1" :headers="uploadHeader" |
| | | :limit="1" :on-change="beforeUpload1" :on-error="onError1" :on-success="onSuccess1" accept='.doc,.docx,application/pdf,' drag |
| | | name="file"> |
| | | <lims-icon name="el-icon-upload"></lims-icon> |
| | |
| | | }, { |
| | | label: '监控任务编号', prop: 'inspectionTaskCode', minWidth: '150px' |
| | | }, { |
| | | label: '任务状态', prop: 'inspectionTaskState', width: '100px', |
| | | formatData: value => this.inspectionTaskStatus(value) |
| | | label: '任务状态', prop: 'taskStatusText', width: '110px' |
| | | },{ |
| | | dataType: 'tag', |
| | | label: '评价状态', |
| | |
| | | leadInto() { |
| | | this.uploadDia = true |
| | | this.planYear = this.selectedYear |
| | | this.fileList = [] |
| | | this.getUserList() |
| | | }, |
| | | // 下载导入模板 |
| | | downloadTemplate() { |
| | | const link = document.createElement('a') |
| | | // 带版本参数避免浏览器继续使用缓存里的旧模板 |
| | | link.href = '/import-templates/质量监控计划导入模板.xlsx?v=2' |
| | | link.download = '质量监控计划导入模板.xlsx' |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | document.body.removeChild(link) |
| | | }, |
| | | // 导入流程 |
| | | beforeUpload(file) { |
| | | if (!/\.(xls|xlsx)$/i.test(file.name || '')) { |
| | | this.$message.error('请选择 .xls 或 .xlsx 格式的文件'); |
| | | this.$refs.upload.clearFiles() |
| | | return false; |
| | | } |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | this.$message.error('上传文件不超过10M'); |
| | | this.$refs.upload.clearFiles() |
| | |
| | | } |
| | | }, |
| | | onError(err, file, fileList) { |
| | | this.$message.error('上传失败') |
| | | this.$refs.upload.clearFiles() |
| | | this.uploading = false |
| | | this.fileList = [] |
| | | this.$message.error('上传失败,请重新选择文件') |
| | | }, |
| | | handleSuccessUp(response) { |
| | | this.uploading = false; |
| | | if (response.code == 200) { |
| | | this.$message.success('上传成功'); |
| | | this.$message.success('导入成功,计划已保存为草稿,请补全质控项目后提交审核'); |
| | | const importedPlan = response.data || null |
| | | this.timer = setTimeout(() => { |
| | | this.uploadDia = false |
| | | this.fileList = [] |
| | | this.planYear = this.selectedYear |
| | | this.examineUserId = '' |
| | | this.getYearPlanList() |
| | | // 导入完成后直接进入计划详情,方便继续编辑质控项目、选择检测标准等 |
| | | if (importedPlan && importedPlan.qualityMonitorId) { |
| | | this.openPlan(importedPlan) |
| | | } else { |
| | | this.getYearPlanList() |
| | | } |
| | | }, 1000) |
| | | } else { |
| | | this.$message.error(response.msg) |
| | | this.$message.error(response.msg || '上传失败') |
| | | // 后端返回业务错误时 HTTP 状态仍是 200,el-upload 会把文件标记为 success, |
| | | // 直接再次调用 submit() 不会重新上传,这里把文件恢复为待上传状态。 |
| | | this.resetUploadFiles() |
| | | } |
| | | }, |
| | | resetUploadFiles() { |
| | | const files = this.$refs.upload?.uploadFiles || this.fileList || [] |
| | | files.forEach(file => { |
| | | file.status = 'ready' |
| | | file.response = undefined |
| | | file.percentage = 0 |
| | | }) |
| | | }, |
| | | submitUpload() { |
| | | if (!this.planYear) { |
| | |
| | | this.$message.warning('请选择审核人') |
| | | return; |
| | | } |
| | | const files = this.$refs.upload?.uploadFiles || this.fileList || [] |
| | | if (!files.length) { |
| | | this.$message.warning('请选择要导入的文件') |
| | | return; |
| | | } |
| | | this.uploading = true |
| | | this.$refs.upload.submit(); |
| | | }, |
| | | // end |
| | |
| | | this.yearDetailLoading = true |
| | | pageQualityMonitorDetail({ ...entity, ...page }).then(res => { |
| | | this.yearDetailLoading = false |
| | | this.yearDetailTableData = res.data.records |
| | | this.yearDetailTableData = res.data.records.map(item => ({ |
| | | ...item, |
| | | taskStatusText: this.inspectionTaskStatus(item) |
| | | })) |
| | | this.yearDetailPage.total = res.data.total |
| | | this.$nextTick(() => this.$refs.yearDetailTableData?.$refs?.multipleTable?.doLayout()) |
| | | }).catch(err => { |
| | |
| | | } |
| | | this.lookDialogVisible = true |
| | | } else { |
| | | this.fileList1 = [] |
| | | this.uploadDia1 = true |
| | | } |
| | | }, |
| | |
| | | this.uploading1 = false |
| | | }, |
| | | submitUpload1() { |
| | | if (this.$refs.upload1.uploadFiles.length === 0) { |
| | | if (!this.fileList1 || this.fileList1.length === 0) { |
| | | this.$message.error('未选择文件') |
| | | return |
| | | } |
| | |
| | | if (command === 'export') this.handleDown(row) |
| | | if (command === 'delete') this.delPlan(row) |
| | | }, |
| | | inspectionTaskStatus(value) { |
| | | inspectionTaskStatus(row) { |
| | | if (row.itemKind !== 'INSPECTION') return '无需下发' |
| | | const value = row.inspectionTaskState |
| | | if (value === null || value === undefined) { |
| | | return Number(row.planRatifyStatus) === 1 ? '未下发' : '待计划批准' |
| | | } |
| | | const map = { 0: '待检测', 1: '检测中', 2: '检测中', 3: '待复核', 4: '复核退回', 5: '待评价' } |
| | | return value === null || value === undefined ? '未下发' : (map[value] || '处理中') |
| | | return map[value] || '处理中' |
| | | }, |
| | | handleDetailCommand(command, row) { |
| | | const handlers = { |