gaoluyang
7 小时以前 29be8639dc16b5d82bddc6099b1fa5cdca75f77a
src/views/CNAS/process/ensureResults/ensureResultsValidity/index.vue
@@ -62,9 +62,11 @@
      </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"
@@ -212,27 +214,38 @@
    <!--导入计划-->
    <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>
@@ -247,7 +260,7 @@
      </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>
@@ -397,8 +410,7 @@
        }, {
          label: '监控任务编号', prop: 'inspectionTaskCode', minWidth: '150px'
        }, {
          label: '任务状态', prop: 'inspectionTaskState', width: '100px',
          formatData: value => this.inspectionTaskStatus(value)
          label: '任务状态', prop: 'taskStatusText', width: '110px'
        },{
          dataType: 'tag',
          label: '评价状态',
@@ -575,10 +587,26 @@
    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()
@@ -588,23 +616,40 @@
      }
    },
    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) {
@@ -615,6 +660,12 @@
        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
@@ -738,7 +789,10 @@
      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 => {
@@ -791,6 +845,7 @@
        }
        this.lookDialogVisible = true
      } else {
        this.fileList1 = []
        this.uploadDia1 = true
      }
    },
@@ -820,7 +875,7 @@
      this.uploading1 = false
    },
    submitUpload1() {
      if (this.$refs.upload1.uploadFiles.length === 0) {
      if (!this.fileList1 || this.fileList1.length === 0) {
        this.$message.error('未选择文件')
        return
      }
@@ -991,9 +1046,14 @@
      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 = {