| | |
| | | <div style="display: flex;justify-content: space-between"> |
| | | <div style="display: flex;"> |
| | | <div style="margin-bottom: 18px;margin-right: 10px;display: flex;align-items: center;line-height: 32px;"> |
| | | <el-radio-group v-model="yearDetailForm.causeType" @change="getYearDetailPlan" size="small"> |
| | | <el-radio-button :value="1">定期监督</el-radio-button> |
| | | <el-radio-button :value="2">动态监督</el-radio-button> |
| | | </el-radio-group> |
| | | </div> |
| | | <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.supervisePurpose" placeholder="请输入" size="small" |
| | | @keyup.enter="getYearDetailPlan"></el-input> |
| | |
| | | <!--导入计划--> |
| | | <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: 80px">年份:</span> |
| | | <el-date-picker v-model="superviseYear" type="year" value-format="YYYY" clearable size="small" format="YYYY" |
| | | placeholder="选择年"> |
| | | <el-form label-width="70px" size="small"> |
| | | <el-form-item label="年份"> |
| | | <el-date-picker v-model="superviseYear" type="year" value-format="YYYY" clearable format="YYYY" |
| | | placeholder="选择年" style="width: 100%"> |
| | | </el-date-picker> |
| | | <span style="width: 110px">监督员:</span> |
| | | <el-select v-model="recordUserIds" placeholder="请选择" size="small" @change="splitList" :multiple-limit="2" |
| | | </el-form-item> |
| | | <el-form-item label="监督员"> |
| | | <el-select v-model="recordUserIds" placeholder="请选择" @change="splitList" :multiple-limit="2" |
| | | filterable multiple style="width: 100%"> |
| | | <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"></el-option> |
| | | </el-select> |
| | | </div> |
| | | <div style="display: flex;align-items: center;margin: 10px 0"> |
| | | <div style="width: 60px">批准人:</div> |
| | | <el-select v-model="ratifyUserId" clearable filterable size="small" style="width: 50%;"> |
| | | </el-form-item> |
| | | <el-form-item label="批准人"> |
| | | <el-select v-model="ratifyUserId" clearable filterable style="width: 100%"> |
| | | <el-option v-for="item in userList" :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="upload1" :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' |
| | | :limit="1" accept=".xls,.xlsx" |
| | | :on-change="beforeUpload" :on-error="onError" :on-success="handleSuccessUp" drag |
| | | :data="{ recordUserIds: recordUserIds1, superviseYear: superviseYear, ratifyUserId: ratifyUserId }" |
| | | 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>监督日期建议填“年.月”(如 2026.3);填成 2026-03-15 也可以,系统会自动换算为 2026.3。</div> |
| | | <div>被监督人员必须填写系统中已存在的人员姓名,否则整批导入失败。</div> |
| | | <div>导入只读取模板的第一个工作表。</div> |
| | | <div style="color: var(--el-color-warning);">导入后计划为“待批准”:需使用所选批准人账号登录并点击“批准”,批准后才能下发和导出。</div> |
| | | </div> |
| | | <template #footer><span class="dialog-footer"> |
| | | <el-button @click="closeUploadDia">取 消</el-button> |
| | |
| | | } else if (params === 1) { |
| | | return '批准'; |
| | | } else { |
| | | return null; |
| | | return '待批准'; |
| | | } |
| | | }, |
| | | formatType: (params) => { |
| | |
| | | } else if (params === 1) { |
| | | return 'success'; |
| | | } else { |
| | | return null; |
| | | return 'warning'; |
| | | } |
| | | } |
| | | }, { |
| | |
| | | yearLoading: false, |
| | | yearDetailForm: { |
| | | supervisePurpose: '', |
| | | superviseProject: '', |
| | | causeType: 1 |
| | | superviseProject: '' |
| | | }, |
| | | yearDetailColumnData: [ |
| | | { |
| | |
| | | this.yearPage.size = limit; |
| | | this.getYearPlanList(); |
| | | }, |
| | | // 下载导入模板 |
| | | downloadTemplate() { |
| | | const link = document.createElement('a') |
| | | // 带版本参数避免浏览器继续使用缓存里的旧模板 |
| | | link.href = '/import-templates/质量监督计划导入模板.xlsx?v=3' |
| | | 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.upload1.clearFiles() |
| | | return false; |
| | | } |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | this.$message.error('上传文件不超过10M'); |
| | | this.$refs.upload1.clearFiles() |
| | | return false; |
| | | } |
| | | return true; |
| | | }, |
| | | onError(err, file, fileList) { |
| | | this.$message.error('上传失败') |
| | |
| | | handleSuccessUp(response) { |
| | | this.uploading = false; |
| | | if (response.code == 200) { |
| | | this.$message.success('上传成功'); |
| | | const approver = this.userList.find(item => Number(item.id) === Number(this.ratifyUserId)) |
| | | const approverName = approver ? approver.name : '所选批准人' |
| | | if (Number(this.ratifyUserId) === Number(this.userId)) { |
| | | this.$message.success('导入成功,请在列表中点击“批准”完成批准,批准后才能下发和导出') |
| | | } else { |
| | | this.$message.success(`导入成功,计划已提交给${approverName}批准;请用该账号登录批准,批准后才能下发和导出`) |
| | | } |
| | | this.recordUserIds = [] |
| | | this.superviseYear = '' |
| | | this.fileList = [] |
| | |
| | | getUserList() { |
| | | // 质量监督面向全实验室, 人员列表不按部门筛选 |
| | | selectUserCondition({ type: 1 }).then((res) => { |
| | | this.userList = res.data || []; |
| | | const list = res.data || [] |
| | | // 当前登录用户可能因角色(如 admin)被接口过滤,仍允许选自己作为批准人,避免导入后无人可批准 |
| | | if (this.userId && !list.some(item => Number(item.id) === Number(this.userId))) { |
| | | list.unshift({ id: this.userId, name: this.nickName }) |
| | | } |
| | | this.userList = list |
| | | }) |
| | | }, |
| | | // 批准 |
| | |
| | | this.getYearDetailPlanList() |
| | | }, |
| | | // 获取年度明细表 |
| | | // 监督日期统一成 "YYYY.M":兼容 2026-03-15 / 2026/3/15 / 2026年3月15日 等导入写法 |
| | | normalizeSuperviseMonth(value) { |
| | | if (!value) return value |
| | | const text = String(value).trim() |
| | | const matched = text.match(/^(\d{4})\s*[./年-]\s*(\d{1,2})(?:\s*[./月-]\s*\d{1,2}\s*日?)?$/) |
| | | if (!matched) return text |
| | | const month = Number(matched[2]) |
| | | return month >= 1 && month <= 12 ? `${matched[1]}.${month}` : text |
| | | }, |
| | | getYearDetailPlanList() { |
| | | const entity = { |
| | | superviseId: this.superviseId, |
| | | supervisePurpose: this.yearDetailForm.supervisePurpose, |
| | | superviseProject: this.yearDetailForm.superviseProject, |
| | | causeType: this.yearDetailForm.causeType, |
| | | } |
| | | const page = this.yearDetailPage |
| | | this.yearDetailLoading = true |
| | | pageQualitySuperviseDetail({ ...entity, ...page }).then(res => { |
| | | this.yearDetailLoading = false |
| | | this.yearDetailTableData = res.data.records |
| | | // 历史导入的监督日期可能是 2026/3/15、2026-03-15 等完整日期,统一显示成 2026.3 |
| | | this.yearDetailTableData = (res.data.records || []).map(item => ({ |
| | | ...item, |
| | | superviseTime: this.normalizeSuperviseMonth(item.superviseTime) |
| | | })) |
| | | this.yearDetailPage.total = res.data.total |
| | | }).catch(err => { |
| | | console.log('err---', err); |
| | |
| | | showDialog(type, row) { |
| | | this.formDia = true |
| | | this.$nextTick(() => { |
| | | this.$refs.formDia.openDia(type, row, this.yearDetailForm.causeType) |
| | | this.$refs.formDia.openDia(type, row) |
| | | }) |
| | | }, |
| | | closeDia() { |
| | |
| | | action() { |
| | | return this.javaApi + '/qualitySupervise/importQualitySupervise' |
| | | }, |
| | | ...mapGetters(["userId"]), |
| | | ...mapGetters(["userId", "nickName"]), |
| | | }, |
| | | }; |
| | | </script> |