吴羡
7 小时以前 c6e96cdb8b1cfb51e9a45bf86c38d1353e983127
设备模块业务完善及前序页面优化

- 设备故障与维修/事故/报废/利用外部仪器设备:增加当前环节责任人只读控制,审批完成后锁定单据
- 设备停用/启用:按当前责任人只读;配合审批完成回写设备档案状态;设备借用按借出/归还责任人只读,附件上传删除同步控制
- 设备校准/核查/保养计划:按年份自动创建并补全计划明细、日期格式化、查询重置页码、审批后锁定、加载失败容错;设备核查计划相关弹窗保留编辑草稿自动恢复
- 设备导出统一失败拦截:后端返回错误 JSON 时提示错误,不再保存损坏文件;设备工具明细、使用记录导出支持当前筛选条件
- 设备模块日期统一格式化,新增 dateFormat.js、saveBlob.js、calibrationRecordDia.vue;清理无引用死代码、死接口及旧弹窗
- 标准物质台账:新增余量列,按验收日期倒序,余量为 0 时领用按钮置灰
- 设施和环境条件:移除电源稳定性、防雷检测、照度记录
- 方法验证-标准查新:新增弹框排版优化
- 不符合工作-不符合项分发:创建/修改时间格式化
已添加3个文件
已删除1个文件
已修改37个文件
4509 ■■■■■ 文件已修改
src/api/cnas/resourceDemand/device.js 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/saveBlob.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/process/method/standardNoveltyRetrieval/component/FormDialog.vue 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/process/nonconformingWork/nonconformingDistribution/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/acceptanceForm.vue 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/accidentForm.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/addVerificationYearPlanDia.vue 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/addYearPlanDia.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/applicationForm.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/borrow.vue 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/calibration.vue 376 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/calibrationRecordDia.vue 448 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/check.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/checkRecord.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/dateFormat.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/deviceOverview.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentAcceptance.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentAccident.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentCalibrationPlan.vue 623 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentCheck.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentFailure.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentMaintenance.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentMaintenancePlan.vue 730 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentScrap.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue 665 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/failureForm.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/fault.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/files.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/inspectionForm.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/inspectionOfEquipment.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/management.vue 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/operationInstruction.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/quantityValueTraceabilityPlan.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/record.vue 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/scrapApplicationForm.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/state.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/usageAuthorization.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/component/usingExternalInstruments.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/device/index.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/facilitiesEnvironment/component/facilities-environmental-conditions.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/resourceDemand/standardMaterial/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/cnas/resourceDemand/device.js
@@ -152,6 +152,15 @@
  });
}
// æŒ‰å¹´ä»½æŸ¥è¯¢è®¾å¤‡æ ¡å‡†è®¡åˆ’(不存在则自动创建,并自动补全到点明细)
export function getCalibrationPlanByYear(query) {
  return request({
    url: "/deviceCalibrationPlan/getPlanByYear",
    method: "get",
    params: query,
  });
}
// æäº¤æ‰¹å‡†é€šçŸ¥
export function submiatRatifyDeviceCalibrationPlan(data) {
  return request({
@@ -310,6 +319,15 @@
export function pageDeviceExaminePlan(query) {
  return request({
    url: "/deviceExaminePlan/pageDeviceExaminePlan",
    method: "get",
    params: query,
  });
}
// æŒ‰å¹´ä»½æŸ¥è¯¢è®¾å¤‡æ ¸æŸ¥è®¡åˆ’(不存在则自动创建,并自动补全到点明细)
export function getExaminePlanByYear(query) {
  return request({
    url: "/deviceExaminePlan/getPlanByYear",
    method: "get",
    params: query,
  });
@@ -517,6 +535,51 @@
  });
}
// æŒ‰å¹´ä»½æŸ¥è¯¢è®¾å¤‡ä¿å…»è®¡åˆ’(不存在则自动创建,并自动补全到点明细)
export function getMaintenancePlanByYear(query) {
  return request({
    url: "/deviceMaintenancePlan/getPlanByYear",
    method: "get",
    params: query,
  });
}
// åˆ†é¡µæŸ¥è¯¢è®¾å¤‡ä¿å…»è®¡åˆ’详情
export function pageMaintenancePlanDetail(query) {
  return request({
    url: "/deviceMaintenancePlan/pageMaintenancePlanDetail",
    method: "get",
    params: query,
  });
}
// ä¿®æ”¹è®¾å¤‡ä¿å…»è®¡åˆ’详情
export function updateMaintenancePlanDetail(data) {
  return request({
    url: "/deviceMaintenancePlan/updateMaintenancePlanDetail",
    method: "post",
    data: data,
  });
}
// åˆ é™¤è®¾å¤‡ä¿å…»è®¡åˆ’详情
export function deleteMaintenancePlanDetail(query) {
  return request({
    url: "/deviceMaintenancePlan/delMaintenancePlanDetail",
    method: "delete",
    params: query,
  });
}
// å®¡æ ¸è®¾å¤‡ä¿å…»è®¡åˆ’
export function reviewMaintenancePlanStatus(data) {
  return request({
    url: "/deviceMaintenancePlan/reviewMaintenancePlanStatus",
    method: "post",
    data: data,
  });
}
//分页查询量值溯源计划
export function selectDeviceTraceabilityManagementByPage(query) {
  return request({
src/utils/saveBlob.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
import { ElMessage } from 'element-plus'
import { saveAs } from 'file-saver'
/**
 * ä¿å­˜æŽ¥å£è¿”回的二进制文件;若后端实际返回的是错误 JSON,则提示错误而不是存成坏文件。
 * @param {Blob} data è¯·æ±‚返回的 blob
 * @param {string} filename ä¸‹è½½æ–‡ä»¶å
 * @param {string} mime æ–‡ä»¶ç±»åž‹
 */
export function saveBlobOrShowError(data, filename, mime = 'application/octet-stream') {
  const reader = new FileReader()
  reader.readAsText(data, 'utf-8')
  reader.onload = () => {
    const text = (reader.result || '').trim()
    if (text.startsWith('{') || text.startsWith('[')) {
      let msg = '导出失败'
      try {
        msg = JSON.parse(text).msg || msg
      } catch (e) {
        // éžæ ‡å‡†é”™è¯¯ç»“构,保留默认提示
      }
      ElMessage.error(msg)
    } else {
      saveAs(new Blob([data], { type: mime }), filename)
    }
  }
  reader.onerror = () => {
    saveAs(new Blob([data], { type: mime }), filename)
  }
}
src/views/CNAS/process/method/standardNoveltyRetrieval/component/FormDialog.vue
@@ -1,47 +1,51 @@
<template>
  <div>
    <el-dialog v-model="formDia" title="新增" width="80%" @close="closeDia">
      <el-form ref="form" :model="form" :rules="formRules" label-width="auto">
        <el-button size="small" type="primary" @click="addBtn">添加一条</el-button>
    <el-dialog v-model="formDia" title="新增" width="800px" @close="closeDia">
      <el-form ref="form" :model="form" :rules="formRules" label-width="120px">
        <div class="form-info">
          <div v-for="(items,index) in form.taskRel" :key="index">
            <el-col :span="12">
              <el-form-item :prop="`taskRel.${index}.newMethodName`" :rules="{required: true, message: '请填写标准名称',trigger: 'blur',}" label="新标准名称:">
                <el-input v-model="items.newMethodName" size="small"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item :prop="`taskRel.${index}.newStandardNo`" :rules="{required: true,message: '请填写标准号',trigger: 'blur',}" label="新标准号:">
                <el-input v-model="items.newStandardNo" size="small"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item :prop="`taskRel.${index}.searchNewSource`" :rules="{required: true,message: '请选择查新记录来源',trigger: 'change',}" label="查新记录来源:">
                <el-radio-group v-model="items.searchNewSource">
                  <el-radio :value="0">标准网</el-radio>
                  <el-radio :value="1">委托情报</el-radio>
                  <el-radio :value="2">标准数</el-radio>
                  <el-radio :value="3">其他</el-radio>
                </el-radio-group>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item :prop="`taskRel.${index}.remark`" :rules="{required: false,message: '请选择备注',trigger: 'change',}" label="备注:">
                <el-select v-model="items.remark" :prop="`taskRel.${index}.remark`"
                           :rules="{required: false,message: '请选择备注',trigger: 'change',}"
                           clearable size="small">
                  <el-option :value="0" label="作废"></el-option>
                  <el-option :value="1" label="替换"></el-option>
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="4">
              <el-button v-if="index !== 0" circle :icon="$icon('el-icon-delete')" size="small" type="danger" @click="deleteHeaderRow(index)"></el-button>
            </el-col>
            <el-col :span="24">
              <el-divider></el-divider>
            </el-col>
          <div v-for="(items,index) in form.taskRel" :key="index" class="record-block">
            <div class="record-head">
              <span class="record-title">
                <span class="record-index">{{ index + 1 }}</span>
                æŸ¥æ–°è®°å½•
              </span>
              <el-button v-if="index !== 0" link type="danger" :icon="$icon('el-icon-delete')"
                @click="deleteHeaderRow(index)">删除本条</el-button>
            </div>
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item :prop="`taskRel.${index}.newMethodName`" :rules="{required: true, message: '请填写标准名称',trigger: 'blur',}" label="新标准名称:">
                  <el-input v-model="items.newMethodName" size="small"></el-input>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item :prop="`taskRel.${index}.newStandardNo`" :rules="{required: true,message: '请填写标准号',trigger: 'blur',}" label="新标准号:">
                  <el-input v-model="items.newStandardNo" size="small"></el-input>
                </el-form-item>
              </el-col>
              <el-col :span="24">
                <el-form-item :prop="`taskRel.${index}.searchNewSource`" :rules="{required: true,message: '请选择查新记录来源',trigger: 'change',}" label="查新记录来源:">
                  <el-radio-group v-model="items.searchNewSource">
                    <el-radio :value="0">标准网</el-radio>
                    <el-radio :value="1">委托情报</el-radio>
                    <el-radio :value="2">标准数</el-radio>
                    <el-radio :value="3">其他</el-radio>
                  </el-radio-group>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item :prop="`taskRel.${index}.remark`" :rules="{required: false,message: '请选择备注',trigger: 'change',}" label="备注:">
                  <el-select v-model="items.remark" clearable size="small" style="width: 100%;">
                    <el-option :value="0" label="作废"></el-option>
                    <el-option :value="1" label="替换"></el-option>
                  </el-select>
                </el-form-item>
              </el-col>
            </el-row>
          </div>
        </div>
        <div class="add-btn-wrap">
          <el-button class="add-btn" @click="addBtn">添加一条</el-button>
        </div>
      </el-form>
      <template #footer><span  class="dialog-footer">
@@ -120,10 +124,70 @@
<style scoped>
.form-info {
  display: inline-block;
  max-height: 42em;
  max-height: 52vh;
  overflow-y: auto;
  padding-right: 4px;
}
.record-block {
  background: #fafafa;
  border: 1px solid #ebeef5;
  border-radius: 6px;
  padding: 14px 16px 0;
  margin-bottom: 14px;
}
.record-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 10px;
  margin-bottom: 14px;
  border-bottom: 1px dashed #e4e7ed;
}
.record-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--el-text-color-primary);
}
.record-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--el-color-primary);
  color: #fff;
  font-size: 12px;
}
.add-btn-wrap {
  margin-top: 4px;
}
.add-btn {
  width: 100%;
  color: var(--el-color-primary);
  border: 1px dashed var(--el-color-primary);
  background: transparent;
}
.add-btn:hover {
  color: var(--el-color-primary);
  border-color: var(--el-color-primary);
  background: var(--el-color-primary-light-9);
}
:deep(.record-block .el-form-item) {
  margin-bottom: 16px;
}
:deep(.el-dialog) {
  margin: 6vh auto 50px !important;
}
src/views/CNAS/process/nonconformingWork/nonconformingDistribution/index.vue
@@ -42,6 +42,7 @@
  delInconsistentDistribution,
  exportInconsistentDistribution,
} from '@/api/cnas/process/nonconformingWork.js'
import { formatListDate } from '@/views/CNAS/resourceDemand/device/component/dateFormat'
export default {
  name: 'NonconformingDistribution',
@@ -67,7 +68,8 @@
        {
          label: '创建时间',
          prop: 'createTime',
          minWidth: '100'
          minWidth: '150',
          formatData: val => formatListDate(val)
        },
        {
          label: '修改人',
@@ -77,7 +79,8 @@
        {
          label: '修改时间',
          prop: 'updateTime',
          minWidth: '100'
          minWidth: '150',
          formatData: val => formatListDate(val)
        },
        {
          dataType: 'action',
src/views/CNAS/resourceDemand/device/component/acceptanceForm.vue
@@ -138,6 +138,7 @@
    submitForm() {
      this.$refs.modelForm.validate((valid) => {
        if (valid) {
          this.submitFormLoading = true
          if (this.operationType === 'add') {
            addDeviceAcceptance(this.form).then(res => {
              if (res.code == 200) {
src/views/CNAS/resourceDemand/device/component/accidentForm.vue
@@ -9,7 +9,7 @@
        <el-step title="技术负责人意见" @click="setStep(3)"></el-step>
        <el-step title="主任意见" @click="setStep(4)"></el-step>
      </el-steps>
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px">
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px" :disabled="!canOperate">
        <el-col v-if="showStep === 0" :span="12">
          <el-form-item label="地点:" prop="address">
            <el-input v-model="form.address" :disabled="currentStep !== 0" clearable size="small"></el-input>
@@ -87,7 +87,7 @@
      </el-form>
      <template #footer><span  class="dialog-footer">
        <el-button @click="resetForm">取 æ¶ˆ</el-button>
        <el-button v-if="currentStep !== 5" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
        <el-button v-if="currentStep !== 5 && canOperate" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
          è®¤</el-button>
      </span></template>
    </el-dialog>
@@ -96,6 +96,7 @@
<script>
import { selectUserCondition } from "@/api/business/inspectionTask";
import { mapGetters } from "@/utils/store-compat";
import {
  getDeviceAccidentReport,
  addDeviceAccidentReport,
@@ -109,6 +110,7 @@
    return {
      dialogVisible: false,
      submitFormLoading: false,
      canOperate: true,
      form: {
        accidentReportId: '',
        address: '',
@@ -145,6 +147,7 @@
    // æ‰“开弹框
    openDialog(id, deviceId) {
      this.dialogVisible = true
      this.canOperate = true
      this.form.accidentReportId = id
      this.form.deviceId = deviceId
      this.getUserList()
@@ -178,10 +181,30 @@
            this.currentStep = 5
            this.showStep = 4
          }
          this.applyPermission()
        }
      }).catch(error => {
        console.error(error)
      })
    },
    // éžå½“前环节责任人只允许查看
    applyPermission() {
      if (this.form.isFinish === 1 || this.currentStep >= 5) {
        this.canOperate = false
        return
      }
      const responsibleList = [
        this.form.reportUser,
        this.form.assessorUser,
        this.form.departmentHeadUser,
        this.form.technicalDirectorUser,
        this.form.directorHeadUser,
      ]
      const responsible = responsibleList[this.currentStep]
      this.canOperate = !responsible || responsible === this.nickName
      if (!this.canOperate) {
        this.$message.warning('当前环节责任人为:' + responsible + ',您只能查看')
      }
    },
    setStep(step) {
      this.showStep = step
@@ -191,6 +214,7 @@
      this.form.flowType = this.currentStep
      this.$refs.modelForm.validate((valid) => {
        if (valid) {
          this.submitFormLoading = true
          addDeviceAccidentReport(this.form).then(res => {
            if (res.code == 200) {
              this.$message.success('新增成功')
@@ -214,6 +238,9 @@
      })
    },
  },
  computed: {
    ...mapGetters(["nickName"]),
  },
}
</script>
src/views/CNAS/resourceDemand/device/component/addVerificationYearPlanDia.vue
ÎļþÒÑɾ³ý
src/views/CNAS/resourceDemand/device/component/addYearPlanDia.vue
@@ -162,7 +162,13 @@
      this.selectionRows = selection
    },
    changeMachineName() {
      this.selectionRows.map(val => {
      const existingIds = new Set(this.calibrationPlanDetailList.map(item => item.deviceId))
      let skipped = 0
      this.selectionRows.forEach(val => {
        if (existingIds.has(val.id)) {
          skipped++
          return
        }
        // å°† val.nextCalibrationDate è½¬æ¢ä¸º Date å¯¹è±¡å¹¶å‡åŽ» 5 å¤©
        let nextCalibrationDate = val.nextCalibrationDate ? new Date(val.nextCalibrationDate) : null;
        if (nextCalibrationDate) {
@@ -177,7 +183,11 @@
          verificationUnit: val.calibrationServices,
          deviceAmount: 1
        })
        existingIds.add(val.id)
      })
      if (skipped > 0) {
        this.$message.warning(`已跳过 ${skipped} å°å·²åœ¨è®¡åˆ’中的设备`)
      }
      this.addEquipDia = false
      this.rowDrop()
    },
@@ -209,6 +219,18 @@
    },
    // æäº¤æ–°å¢ž
    submitForm() {
      if (!this.form.planName) {
        this.$message.warning('请输入计划名称')
        return
      }
      if (!this.form.planYear) {
        this.$message.warning('请选择年份')
        return
      }
      if (!this.calibrationPlanDetailList.length) {
        this.$message.warning('请添加设备')
        return
      }
      this.form.calibrationPlanDetailList = this.HaveJson(this.calibrationPlanDetailList)
      this.submitFormLoading = true
      if (this.operationType === 'add') {
@@ -225,7 +247,7 @@
      } else {
        updateDeviceCalibrationPlan(this.form).then(res => {
          if (res.code == 200) {
            this.$message.success('新增成功')
            this.$message.success('修改成功')
            this.closeDialog()
            this.$emit('closeDia')
          }
src/views/CNAS/resourceDemand/device/component/applicationForm.vue
@@ -8,7 +8,7 @@
        <el-step title="计量室意见" @click="setStep(2)"></el-step>
        <el-step title="批准人" @click="setStep(3)"></el-step>
      </el-steps>
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px">
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px" :disabled="!canOperate">
        <el-col v-if="showStep === 0" :span="12">
          <el-form-item label="单位名称:" prop="unitName">
            <el-input v-model="form.unitName" :disabled="currentStep !== 0" clearable size="small"></el-input>
@@ -102,7 +102,7 @@
      </el-form>
      <template #footer><span  class="dialog-footer">
        <el-button @click="resetForm">取 æ¶ˆ</el-button>
        <el-button v-if="currentStep !== 4" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
        <el-button v-if="currentStep !== 4 && canOperate" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
          è®¤</el-button>
      </span></template>
    </el-dialog>
@@ -115,6 +115,7 @@
  addDeviceExternalApply,
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { mapGetters } from "@/utils/store-compat";
export default {
  name: "applicationForm",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -124,6 +125,7 @@
    return {
      dialogVisible: false,
      submitFormLoading: false,
      canOperate: true,
      form: {
        externalApplyId: '',
        unitName: '',
@@ -161,6 +163,7 @@
    // æ‰“开弹框
    openDialog(id) {
      this.dialogVisible = true
      this.canOperate = true
      this.form.externalApplyId = id
      this.getUserList()
      if (this.form.externalApplyId) {
@@ -189,10 +192,29 @@
            this.currentStep = 4
            this.showStep = 3
          }
          this.applyPermission()
        }
      }).catch(error => {
        console.error(error)
      })
    },
    // éžå½“前环节责任人只允许查看
    applyPermission() {
      if (this.form.isFinish === 1 || this.currentStep >= 4) {
        this.canOperate = false
        return
      }
      const responsibleList = [
        this.form.applicantUser,
        this.form.departmentHeadUser,
        this.form.meteringRoomUser,
        this.form.approverUser,
      ]
      const responsible = responsibleList[this.currentStep]
      this.canOperate = !responsible || responsible === this.nickName
      if (!this.canOperate) {
        this.$message.warning('当前环节责任人为:' + responsible + ',您只能查看')
      }
    },
    setStep(step) {
      this.showStep = step
@@ -202,6 +224,7 @@
      this.form.flowType = this.currentStep
      this.$refs.modelForm.validate((valid) => {
        if (valid) {
          this.submitFormLoading = true
          addDeviceExternalApply(this.form).then(res => {
            if (res.code == 200) {
              this.$message.success('新增成功')
@@ -225,6 +248,9 @@
      })
    },
  },
  computed: {
    ...mapGetters(["nickName"]),
  },
}
</script>
src/views/CNAS/resourceDemand/device/component/borrow.vue
@@ -26,7 +26,7 @@
        <el-step style="cursor:pointer" v-for="(v, i) in steps" :title="v" :key="i"
          @click="choiceStep(i)"></el-step>
      </el-steps>
      <el-form ref="form" :model="form" :rules="rules" label-width="130px">
      <el-form ref="form" :model="form" :rules="rules" label-width="130px" :disabled="!canOperate">
        <div v-show="currentStepClick === 0">
          <el-card style="margin-top: 1em; height: 51vh; overflow-y: scroll;">
            <!-- æ–°å¢žè®¾å¤‡äº‹è®°å½•卡片 -->
@@ -57,7 +57,7 @@
              </el-col>
              <el-col :span="12">
                <el-form-item label="借用人联系方式:" prop="borrowerContactInformation" label-width="150px">
                  <el-input v-model="form.borrowerContactInformation" size="small"></el-input>
                  <el-input v-model="form.borrowerContactInformation" size="small" :disabled="currentStep > 0"></el-input>
                </el-form-item>
              </el-col>
              <el-col :span="12">
@@ -81,13 +81,13 @@
                <el-form-item label="相关附件:" prop="fileName">
                  <el-input v-model="form.fileName" disabled size="small"
                    :style="`width: ${currentStep == 0 ? '88%' : '100%'};`">
                    <template #append><el-button  v-if="currentStep === 0" :icon="$icon('el-icon-delete-solid')"
                    <template #append><el-button  v-if="currentStep === 0 && canOperate" :icon="$icon('el-icon-delete-solid')"
                      @click="deleteFile"></el-button></template>
                  </el-input>
                  <el-upload ref="upload" style="float: right;" :action="action" :show-file-list="false"
                    :on-success="onSuccess" :disabled="currentStep !== 0" :headers="uploadHeader">
                    :on-success="onSuccess" :disabled="currentStep !== 0 || !canOperate" :headers="uploadHeader">
                    <template #trigger><el-button style="position: relative;top: -4px" class="uploadFile"  size="small"
                      type="primary" v-if="currentStep === 0">附件上传</el-button></template>
                      type="primary" v-if="currentStep === 0 && canOperate">附件上传</el-button></template>
                  </el-upload>
                </el-form-item>
              </el-col>
@@ -170,9 +170,9 @@
        </div>
      </el-form>
      <template #footer><span  class="dialog-footer">
        <el-button @click="submitForm('3reject')" v-if="currentStep !== 0 && currentStep !== 2">驳回</el-button>
        <el-button @click="submitForm('2save')" v-if="currentStep === 0">保存</el-button>
        <el-button type="primary" v-if="currentStep !== 2" @click="submitForm('1submit')">{{ currentStep === 0 ? '提交' :
        <el-button :loading="submitLoading" @click="submitForm('3reject')" v-if="currentStep !== 0 && currentStep !== 2 && canOperate">驳回</el-button>
        <el-button :loading="submitLoading" @click="submitForm('2save')" v-if="currentStep === 0 && canOperate">保存</el-button>
        <el-button :loading="submitLoading" type="primary" v-if="currentStep !== 2 && canOperate" @click="submitForm('1submit')">{{ currentStep === 0 ? '提交' :
          '通过'
          }}</el-button>
      </span></template>
@@ -183,7 +183,7 @@
        </el-table-column>
        <el-table-column prop="operator" label="操作人" width="180">
        </el-table-column>
        <el-table-column prop="operationTime" label="操作日期" width="180">
        <el-table-column prop="operationTime" label="操作日期" width="180" :formatter="formatDateCell">
        </el-table-column>
        <el-table-column prop="operationType" label="提交类型">
        </el-table-column>
@@ -207,6 +207,8 @@
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { mapGetters } from "@/utils/store-compat";
import { formatListDate } from './dateFormat'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  props: {
    clickNodeVal: {
@@ -223,9 +225,10 @@
    return {
      dialogVisible: false,
      dialogVisible0: false,
      canOperate: true,
      currentStep: 0, // æ­¥éª¤æ¡æ˜¾ç¤ºç¬¬å‡ æ­¥
      currentStepClick: 0, // ç‚¹å‡»æ­¥éª¤æ¡å˜åŒ–
      steps: ['借出', '借用'],
      steps: ['借出', '归还'],
      responsibleOptions: [], // ä¸‹çŽ¯èŠ‚è´Ÿè´£äººlist
      form: {
        processNumber: null,
@@ -251,6 +254,7 @@
      },
      deviceLogs: [],
      outLoading: false,
      submitLoading: false,
      recipientStateList: [{
        value: 0,
        type: 'success',
@@ -279,18 +283,20 @@
        },
        { label: "借用人", prop: "recipientUser" },
        { label: "借用人联系方式", prop: "borrowerContactInformation", width: '140px' },
        { label: "借用日期", prop: "recipientTime" },
        { label: "借用日期", prop: "recipientTime", formatData: (params) => formatListDate(params) },
        {
          label: "借用时状态", prop: "recipientState", dataType: "tag",
          formatData: (params) => {
            return this.recipientStateList.find((m) => m.value == params).label;
            const item = this.recipientStateList.find((m) => m.value == params)
            return item ? item.label : '-'
          },
          formatType: (params) => {
            return this.recipientStateList.find((m) => m.value == params).type;
            const item = this.recipientStateList.find((m) => m.value == params)
            return item ? item.type : 'info'
          },
        },
        { label: "借出人", prop: "submitUser" },
        { label: "借出日期", prop: "createTime" },
        { label: "借出日期", prop: "createTime", formatData: (params) => formatListDate(params) },
        {
          label: "当前状态", prop: "nowState"
        },
@@ -337,7 +343,7 @@
    // ç›‘听点击el-tree的数据,进行数据刷新
    clickNodeVal(newVal) {
      if (newVal.value) {
        thisqueryParams.deviceId = this.clickNodeVal.value
        this.queryParams.deviceId = this.clickNodeVal.value
        this.refreshTable()
      }
    },
@@ -362,6 +368,9 @@
    this.refreshTable()
  },
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    getList() {
      this.tableLoading = true;
      let param = { ...this.queryParams, ...this.page };
@@ -384,7 +393,7 @@
      this.getList();
    },
    refresh() {
      this.queryParams = {};
      this.queryParams = { deviceId: this.clickNodeVal.value };
      this.page.current = 1;
      this.getList();
    },
@@ -445,12 +454,16 @@
          this.form.nowState = currentStepAction === 2 ? '关闭' : this.steps[currentStepAction]
          this.form.deviceId = this.clickNodeVal.value
          delete this.form.deviceLogs
          this.submitLoading = true
          saveDeviceBorrow(this.form).then(res => {
            if (res.code == 200) {
              this.$message.success('提交成功')
              this.dialogVisible = false
              this.refreshTable()
            }
            this.submitLoading = false
          }).catch(err => {
            this.submitLoading = false
          })
        } else {
          let step = this.steps[this.currentStep]
@@ -467,6 +480,8 @@
        deleteCNASFile({ fileName: this.form.fileName }).then(res => {
          if (res.code == 200) {
            this.$message.success('删除成功!')
            this.form.fileName = null
            this.form.url = null
          }
        })
      }).catch(() => {
@@ -510,12 +525,31 @@
            this.currentStepClick = i
          }
          console.log(this.currentStepClick)
          this.applyPermission()
          this.dialogVisible = true
        }
      })
    },
    // éžå½“前环节责任人只允许查看
    applyPermission() {
      if (this.form.nowState === '关闭') {
        this.canOperate = false
        return
      }
      let responsible = null
      if (this.form.nowState === '归还') {
        responsible = this.form.nowUser
      } else if (this.form.nowState === '借出') {
        responsible = this.form.submitOperationUser
      }
      this.canOperate = !responsible || responsible === this.nickName
      if (!this.canOperate) {
        this.$message.warning('当前环节责任人为:' + responsible + ',您只能查看')
      }
    },
    // æ–°å¢ž
    add() {
      this.canOperate = true
      this.dialogVisible = true
      this.form = {
        processNumber: null,
@@ -523,10 +557,11 @@
        unifyNumber: null,
        recipientUser: null,
        recipientTime: null,
        recipientState: 0,
        nextUser: null,
        rebackUser: null,
        rebackTime: null,
        receiveState: null,
        receiveState: 0,
        deviceUser: null,
        fileName: null,
      }
@@ -538,11 +573,10 @@
      this.outLoading = true
      deviceBorrowExport({ deviceId: this.clickNodeVal.value }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], {
          type: 'application/force-download'
        })
        const filename = decodeURI(this.clickNodeVal.label + '设备借出统计' + '.xlsx')
        this.$download.saveAs(blob, filename)
        saveBlobOrShowError(res, filename, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
      }).catch(() => {
        this.outLoading = false
      })
    },
    handleLookList(row) {
src/views/CNAS/resourceDemand/device/component/calibration.vue
@@ -3,7 +3,7 @@
  <div>
    <div class="btnS">
      <el-button size="small" type="primary" @click="calibrationMaintenance()">校准项目维护</el-button>
      <el-button size="small" type="primary" @click="add('add')">添加校准记录</el-button>
      <el-button size="small" type="primary" @click="add()">添加校准记录</el-button>
    </div>
    <div class="tables" style="margin-top: 10px;">
      <el-table :data="tableData" height="calc(100vh - 20em)" border>
@@ -21,11 +21,15 @@
        </el-table-column>
        <el-table-column label="校准证书编号" min-width="150" prop="certificateSerialNumber"></el-table-column>
        <el-table-column label="说明" min-width="150" prop="remark" show-overflow-tooltip></el-table-column>
        <el-table-column label="校准日期" min-width="150" prop="calibrationDate"></el-table-column>
        <el-table-column label="下次校准日期" min-width="150" prop="nextCalibrationDate"></el-table-column>
        <el-table-column label="确认日期" min-width="150" prop="confirmDate"></el-table-column>
        <el-table-column label="校准日期" min-width="150" prop="calibrationDate"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="下次校准日期" min-width="150" prop="nextCalibrationDate"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="确认日期" min-width="150" prop="confirmDate"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="登记人" min-width="150" prop="createUser"></el-table-column>
        <el-table-column label="登记日期" min-width="150" prop="createTime"></el-table-column>
        <el-table-column label="登记日期" min-width="150" prop="createTime"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column fixed="right" label="操作" min-width="180" align="center">
          <template #default="{ row }">
            <el-button size="small" link type="primary" @click="handleAttachmentClick(row)">下载附件</el-button>
@@ -34,7 +38,7 @@
          </template>
        </el-table-column>
      </el-table>
      <el-pagination :current-page="1" :page-size="search.size" :page-sizes="[10, 20, 30, 50, 100]"
      <el-pagination :current-page="search.current" :page-size="search.size" :page-sizes="[10, 20, 30, 50, 100]"
        :total="search.total" layout="->,total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange" @current-change="handleCurrentChange" background>
      </el-pagination>
@@ -85,7 +89,7 @@
        <el-table-column label="最大允许误差" prop="maxPermissibleError"></el-table-column>
        <el-table-column label="判定标准" prop="judgmentCriteria"></el-table-column>
        <el-table-column label="创建人" prop="createdBy"></el-table-column>
        <el-table-column label="创建时间" prop="creationTime"></el-table-column>
        <el-table-column label="创建时间" prop="creationTime" :formatter="formatDateCell"></el-table-column>
        <el-table-column fixed="right" label="操作">
          <template #default="scope">
            <el-button size="small" link type="primary" @click="handleDelete(scope.row)">删除</el-button>
@@ -94,178 +98,25 @@
      </el-table>
    </el-dialog>
    <!-- æ·»åŠ æ ¡å‡†è®°å½• -->
    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible1"
      title="添加校准记录" top="5vh" width="80%" @close="resetCalibrationRecord">
      <div style="height: 70vh;overflow-y: auto;overflow-x: hidden;">
        <h4>
          <div style="display: flex;align-items: center;">
            <span class="line"></span>
            <span>添加设备校准记录</span>
          </div>
        </h4>
        <el-form ref="calibrationRecord" :model="calibrationRecord" :rules="formRules" label-position="right"
          label-width="120px">
          <el-row>
            <el-col :span="6">
              <el-form-item label="校准服务机构:" prop="unitOfMeasure">
                <el-select v-model="calibrationRecord.unitOfMeasure" :disabled="operationType === 'view'" clearable filterable
                  size="small" style="width: 100%">
                  <el-option v-for="name in calibrationServiceOptions" :key="name" :label="name" :value="name"></el-option>
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="校准日期:" prop="calibrationDate">
                <el-date-picker v-model="calibrationRecord.calibrationDate" :disabled="operationType === 'view'"
                  format="YYYY-MM-DD" placeholder="选择日期" size="small" style="width: 90%" type="date"
                  value-format="YYYY-MM-DD" @change="getNextCalibrationDate">
                </el-date-picker>
              </el-form-item>
            </el-col>
            <el-col :span="10">
              <el-form-item label="下次校准日期:" label-width="140px">
                <el-date-picker v-model="calibrationRecord.nextCalibrationDate" disabled format="YYYY-MM-DD"
                  placeholder="选择日期" size="small" style="width: 90%" type="date" value-format="YYYY-MM-DD">
                </el-date-picker>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="计算器具:" prop="calculatingApparatus">
                <el-input v-model="calibrationRecord.calculatingApparatus" :disabled="operationType === 'view'"
                  size="small"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="计算标准量程:" prop="standardRange">
                <el-input v-model="calibrationRecord.standardRange" :disabled="operationType === 'view'" size="small"
                  style="width: 90%"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="10">
              <el-form-item label="计量标准不确定度:" label-width="140px" prop="calibrationStandardUncertainty">
                <el-input v-model="calibrationRecord.calibrationStandardUncertainty"
                  :disabled="operationType === 'view'" size="small" style="width: 90%"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="所依据文件:" prop="byDocument">
                <el-input v-model="calibrationRecord.byDocument" :disabled="operationType === 'view'"
                  size="small"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="证书编号:" prop="certificateSerialNumber">
                <el-input v-model="calibrationRecord.certificateSerialNumber" :disabled="operationType === 'view'"
                  size="small" style="width: 90%"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="10">
              <el-form-item label="状态:" label-width="140px" prop="status" required>
                <el-radio-group v-model="calibrationRecord.status" :disabled="operationType === 'view'">
                  <el-radio value="0yes">合格</el-radio>
                  <el-radio value="1no">不合格</el-radio>
                  <el-radio value="2other">其他</el-radio>
                </el-radio-group>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="确认日期:">
                <el-date-picker v-model="calibrationRecord.confirmDate" :disabled="operationType === 'view'"
                  format="YYYY-MM-DD HH:mm:ss" placeholder="选择日期" size="small" style="width: 100%" type="datetime"
                  value-format="YYYY-MM-DD HH:mm:ss">
                </el-date-picker>
              </el-form-item>
            </el-col>
            <el-col :span="17">
              <el-form-item label="附件:" prop="fileName">
                <el-input v-model="calibrationRecord.fileName"
                  :style="`width: ${operationType === 'add' ? '85%' : '100%'};}`" disabled size="small">
                  <template #append><el-button v-if="operationType === 'add'"  :icon="$icon('el-icon-delete-solid')"
                    @click="deleteFile"></el-button></template>
                </el-input>
                <el-upload v-if="operationType === 'add'" ref="upload" :action="action" :before-upload="beforeUpload"
                  :headers="uploadHeader" :limit="1" :on-error="onError" :on-success="handleSuccessUp"
                  :show-file-list="false" style="float: right;">
                  <el-button :loading="upLoading" size="small" style="position: relative; top: -4px;"
                    type="primary">附件上传
                  </el-button>
                </el-upload>
              </el-form-item>
            </el-col>
            <el-col :span="24">
              <el-form-item label="备注:">
                <el-input v-model="calibrationRecord.remark" :disabled="operationType === 'view'" :rows="3" size="small"
                  style="width: 96%" type="textarea"></el-input>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
        <h4>
          <span style="display: flex;align-items: center;">
            <span class="line"></span><span>校准条目确认结果</span>
          </span>
        </h4>
        <el-table ref="calibrateTable" :data="calibrateParams" border>
          <el-table-column label="编号" type="index" width="60"></el-table-column>
          <el-table-column label="计量参数" prop="measurementParameter"></el-table-column>
          <el-table-column label="量程范围" prop="rangeOfMeasurement"></el-table-column>
          <el-table-column label="最大允许误差" prop="maxPermissibleError"></el-table-column>
          <el-table-column label="判定标准" prop="judgmentCriteria"></el-table-column>
          <el-table-column label="是否校准" prop="isCalibration">
            <template #header="scope">
              <span class="required-span">* </span>是否校准
            </template>
            <template #default="scope">
              <el-radio-group v-model="scope.row.isCalibration" :disabled="operationType === 'view'">
                <el-radio value="0yes">是</el-radio>
                <el-radio value="1no">否</el-radio>
              </el-radio-group>
            </template>
          </el-table-column>
          <el-table-column label="判定结果" min-width="140" prop="result">
            <template #header="scope">
              <span class="required-span">* </span>判定结果
            </template>
            <template #default="scope">
              <el-radio-group v-model="scope.row.result" :disabled="operationType === 'view'" @change="checkRadio()">
                <el-radio value="0yes">合格</el-radio>
                <el-radio value="1no">不合格</el-radio>
                <el-radio value="2other">其他</el-radio>
              </el-radio-group>
            </template>
          </el-table-column>
          <el-table-column label="单项结果说明" prop="singleResultStatement">
            <template #default="scope">
              <el-input v-model="scope.row.singleResultStatement" :disabled="operationType === 'view'"
                size="small"></el-input>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <template #footer><span  class="dialog-footer">
        <el-button v-if="operationType === 'add'" @click="dialogVisible1 = false">取 æ¶ˆ</el-button>
        <el-button v-if="operationType === 'add'" :loading="addRecordLoading" type="primary" @click="addRecord">ç¡®
          å®š</el-button>
      </span></template>
    </el-dialog>
    <!-- æ·»åŠ /查看校准记录弹窗 -->
    <calibration-record-dia ref="calibrationRecordDia"
      @success="getTableList(clickNodeVal.value)"></calibration-record-dia>
  </div>
</template>
<script>
import {
  deviceMetricRecordPage,
  showDeviceMetricsCopy,
  deleteDeviceMetricRecord,
  deleteCNASFile,
  selectDeviceMetric,
  deleteDeviceMetrics,
  addOrUpdateDeviceMetricRecord,
  saveOrUpdateDeviceMetric
} from '@/api/cnas/resourceDemand/device.js'
import { selectQualifiedSupplierManagementPage } from '@/api/cnas/externalService/supplierManage/supplierManage'
import CalibrationRecordDia from './calibrationRecordDia.vue'
import { formatListDate } from './dateFormat'
import { mapGetters } from "@/utils/store-compat";
export default {
  components: { CalibrationRecordDia },
  props: {
    clickNodeVal: {
      type: Object,
@@ -280,33 +131,8 @@
      calibrateParams: [],
      calibrateParamsLoading: false,
      addCalibrateLoading: false,
      calibrationRecord: {
        unitOfMeasure: '', // è®¡é‡å•位
        calibrationDate: null, // æ ¡å‡†æ—¥æœŸ
        nextCalibrationDate: null, // ä¸‹æ¬¡æ ¡å‡†æ—¥æœŸ
        calculatingApparatus: '', // è®¡ç®—器具
        confirmDate: null, // ç¡®è®¤æ—¥æœŸ
        standardRange: '', // è®¡ç®—标准量程
        calibrationStandardUncertainty: '', // è®¡é‡æ ‡å‡†ä¸ç¡®å®šåº¦
        byDocument: '', // ä¾æ®æ–‡ä»¶
        certificateSerialNumber: '', // è¯ä¹¦ç¼–号
        status: '', // çŠ¶æ€
        remark: '', // å¤‡æ³¨
        systemFileName: '', //
        fileName: '', //
      },
      formRules: {
        unitOfMeasure: [{ required: true, message: '请选择校准服务机构', trigger: 'change' }],
        calibrationDate: [{ required: true, message: '请选择校准日期', trigger: 'change' }],
        calculatingApparatus: [{ required: true, message: '请输入计算器具', trigger: 'blur' }],
        standardRange: [{ required: true, message: '请输入计算标准量程', trigger: 'blur' }],
        calibrationStandardUncertainty: [{ required: true, message: '请输入计量标准不确定度', trigger: 'blur' }],
        byDocument: [{ required: true, message: '请输入所依据文件', trigger: 'blur' }],
        status: [{ required: true, message: '请选择状态', trigger: 'change' }],
      },
      tableData: [],
      dialogVisible0: false,
      dialogVisible1: false,
      form0: {
        measurementParameter: '', // è®¡é‡å‚æ•°
        rangeOfMeasurement: '',
@@ -330,10 +156,6 @@
          { required: true, message: '请输入判定标准', trigger: 'blur' }
        ],
      },
      addRecordLoading: false,
      upLoading: false,
      operationType: '',
      qualifiedSupplierNames: [],
      search: {
        size: 20,
        current: 1,
@@ -343,50 +165,15 @@
  },
  // ç”¨äºŽä¸Šä¼ æ–‡ä»¶çš„信息
  computed: {
    // æ ¡å‡†æœåŠ¡æœºæž„ä¸‹æ‹‰é€‰é¡¹ï¼ˆåˆæ ¼ä¾›åº”å•† + å½“前值兜底)
    calibrationServiceOptions() {
      const list = this.qualifiedSupplierNames.slice();
      const value = this.calibrationRecord.unitOfMeasure;
      if (value && list.indexOf(value) === -1) list.push(value);
      return list;
    },
    ...mapGetters(["nickName"]),
    action() {
      return this.javaApi + '/personBasicInfo/saveCNASFile'
    }
  },
  mounted() {
    this.obtainQualifiedSupplierList()
    //获取操作记录信息
    this.getTableList(this.clickNodeVal.value) // èŽ·å–è®¾å¤‡æ ¡å‡†åˆ—è¡¨æ•°æ®
  },
  methods: {
    // æ‹‰å–合格供应商列表(校准服务机构下拉选项)
    obtainQualifiedSupplierList() {
      selectQualifiedSupplierManagementPage({ current: 1, size: 999 }).then(res => {
        if (res.code === 200) {
          const rows = (res.data && res.data.records) || [];
          this.qualifiedSupplierNames = [...new Set(rows.map(r => r.supplierName).filter(Boolean))];
        }
      });
    },
    //状态判定
    checkRadio() {
      let resultList = this.calibrateParams.map(ele => ele.result)
      if (resultList && resultList.filter(ele => ele == '1no').length > 0) {
        this.calibrationRecord.status = '1no'
      } else if (resultList && resultList.filter(ele => ele == '2other').length == resultList.length) {
        this.calibrationRecord.status = '2other'
      } else if (resultList && resultList.filter(ele => ele == '0yes').length == resultList.length) {
        this.calibrationRecord.status = '0yes'
      }
    },
    getNextCalibrationDate(val) {
      let oneYearLaterDate = new Date(val)
      oneYearLaterDate.setFullYear(oneYearLaterDate.getFullYear() + 1);
      oneYearLaterDate.setDate(oneYearLaterDate.getDate() - 1);
      // let obj = oneYearLaterDate.toISOString().split('T')[0];
      this.calibrationRecord.nextCalibrationDate = oneYearLaterDate
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    handleSizeChange(val) {
      this.search.size = val
@@ -402,20 +189,13 @@
        this.search.total = res.data.total
      })
    },
    // æ·»åŠ æ ¸æŸ¥è®°å½•
    add(type) {
      this.operationType = type
      this.dialogVisible1 = true
      this.getXmsg()
    // æ·»åŠ æ ¡å‡†è®°å½•
    add() {
      this.$refs.calibrationRecordDia.open(this.clickNodeVal.value, 'add')
    },
    // æŸ¥çœ‹è¯¦æƒ…
    handleViewClick(type, row) {
      showDeviceMetricsCopy({ id: row.id, type: 'calibrate' }).then(res => {
        this.calibrateParams = res.data
      })
      this.calibrationRecord = { ...row }
      this.operationType = type
      this.dialogVisible1 = true
      this.$refs.calibrationRecordDia.open(this.clickNodeVal.value, type, row)
    },
    // è¡¨æ ¼åˆ é™¤æ“ä½œ
    handleDeleteClick(row) {
@@ -436,28 +216,14 @@
      })
    },
    handleAttachmentClick(row) {
      this.$download.saveAs(row.systemFileName, row.systemFileName)
    },
    deleteFile() {
      this.$confirm('此操作将永久删除文件, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteCNASFile({ fileName: this.calibrationRecord.systemFileName }).then(res => {
          this.calibrationRecord.fileName = ''
          this.$refs.upload.clearFiles()
          if (res.code == 200) {
            this.$message.success('删除成功!')
          }
        })
      }).catch((err) => {
        console.log('err----', err)
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
      if (!row.systemFileName) {
        this.$message.warning('未上传文件!')
        return
      }
      // å›¾ç‰‡å­˜ /img/,其他文档存 /word/
      const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(row.systemFileName)
      const url = this.javaApi + (isImage ? '/img/' : '/word/') + row.systemFileName
      this.$download.saveAs(url, row.fileName || row.systemFileName)
    },
    // æ ¡å‡†é¡¹ç›®ç»´æŠ¤
    calibrationMaintenance() {
@@ -520,69 +286,6 @@
        }
      })
    },
    addRecord() {
      this.$refs['calibrationRecord'].validate((valid) => {
        if (valid) {
          try {
            if (this.calibrateParams.some(m => m.isCalibration === undefined)) {
              this.$message.error('请选择是否校准')
              return
            }
            if (!this.calibrateParams.every(m => m.result !== undefined)) {
              this.$message.error('请选择判定结果')
              return
            }
            this.addRecordLoading = true
            this.calibrationRecord.deviceId = this.clickNodeVal.value;
            this.calibrationRecord.createUser = this.nickName
            this.calibrationRecord.type = 'calibrate'
            this.calibrationRecord.deviceMetricsCopyList = this.calibrateParams
            addOrUpdateDeviceMetricRecord(this.calibrationRecord).then(res => {
              if (res.code == 200) {
                this.$message.success('添加成功')
                this.dialogVisible1 = false
                this.getTableList(this.clickNodeVal.value)
              }
              this.addRecordLoading = false
            })
          } catch (e) {
            console.log('addRecord---', e)
            this.addRecordLoading = false
          }
        } else {
          this.$message.warning('有必填项未填');
        }
      })
    },
    resetCalibrationRecord() {
      this.$refs.calibrationRecord.resetFields()
    },
    // ä¸Šä¼ é™„ä»¶
    handleSuccessUp(response, file) {
      if (response.code == 200) {
        // åœ¨ä¿å­˜èµ‹å€¼æ–°æ–‡ä»¶
        this.calibrationRecord.fileName = file.name
        this.calibrationRecord.systemFileName = response.data
        this.upLoading = false;
      } else {
        this.upLoading = false;
        this.$message.error(response.message)
      }
    },
    beforeUpload(file) {
      if (file.size > 1024 * 1024 * 10) {
        this.$message.error('上传文件不超过10M');
        this.$refs.upload.clearFiles()
        return false;
      } else {
        this.upLoading = true;
        return true;
      }
    },
    onError(err, file, fileList) {
      this.$message.error('上传失败')
      this.$refs.upload.clearFiles()
    },
    // end
  },
  watch: {
@@ -590,23 +293,6 @@
    clickNodeVal(newVal) {
      if (newVal.value) {
        this.getTableList(newVal.value);
      }
    },
    dialogVisible1(newVal) {
      if (newVal === false) {
        this.calibrateParams = []
        this.calibrationRecord = {
          unitOfMeasure: '', // è®¡é‡å•位
          calibrationDate: null, // æ ¡å‡†æ—¥æœŸ
          nextCalibrationDate: null, // ä¸‹æ¬¡æ ¡å‡†æ—¥æœŸ
          calculatingApparatus: '', // è®¡ç®—器具
          standardRange: '', // è®¡ç®—标准量程
          calibrationStandardUncertainty: '', // è®¡é‡æ ‡å‡†ä¸ç¡®å®šåº¦
          byDocument: '', // ä¾æ®æ–‡ä»¶
          certificateSerialNumber: '', // è¯ä¹¦ç¼–号
          status: '', // çŠ¶æ€
          remark: '', // å¤‡æ³¨
        }
      }
    }
  }
src/views/CNAS/resourceDemand/device/component/calibrationRecordDia.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,448 @@
<!-- è®¾å¤‡æ ¡å‡†è®°å½•弹窗(添加/查看),设备校准页与设备校准计划页共用 -->
<template>
  <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="visible" title="添加校准记录" top="5vh"
    width="80%" @close="resetCalibrationRecord">
    <div style="height: 70vh;overflow-y: auto;overflow-x: hidden;">
      <h4>
        <div style="display: flex;align-items: center;">
          <span class="line"></span>
          <span>添加设备校准记录</span>
        </div>
      </h4>
      <el-form ref="calibrationRecord" :model="calibrationRecord" :rules="formRules" label-position="right"
        label-width="120px">
        <el-row>
          <el-col :span="6">
            <el-form-item label="校准服务机构:" prop="unitOfMeasure">
              <el-select v-model="calibrationRecord.unitOfMeasure" :disabled="operationType === 'view'" clearable filterable
                size="small" style="width: 100%">
                <el-option v-for="name in calibrationServiceOptions" :key="name" :label="name" :value="name"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="校准日期:" prop="calibrationDate">
              <el-date-picker v-model="calibrationRecord.calibrationDate" :disabled="operationType === 'view'"
                format="YYYY-MM-DD" placeholder="选择日期" size="small" style="width: 90%" type="date"
                value-format="YYYY-MM-DD" @change="getNextCalibrationDate">
              </el-date-picker>
            </el-form-item>
          </el-col>
          <el-col :span="10">
            <el-form-item label="下次校准日期:" label-width="140px">
              <el-date-picker v-model="calibrationRecord.nextCalibrationDate" disabled format="YYYY-MM-DD"
                placeholder="选择日期" size="small" style="width: 90%" type="date" value-format="YYYY-MM-DD">
              </el-date-picker>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="计量器具:" prop="calculatingApparatus">
              <el-input v-model="calibrationRecord.calculatingApparatus" :disabled="operationType === 'view'"
                size="small"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="计量标准量程:" prop="standardRange">
              <el-input v-model="calibrationRecord.standardRange" :disabled="operationType === 'view'" size="small"
                style="width: 90%"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="10">
            <el-form-item label="计量标准不确定度:" label-width="140px" prop="calibrationStandardUncertainty">
              <el-input v-model="calibrationRecord.calibrationStandardUncertainty"
                :disabled="operationType === 'view'" size="small" style="width: 90%"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="所依据文件:" prop="byDocument">
              <el-input v-model="calibrationRecord.byDocument" :disabled="operationType === 'view'"
                size="small"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="证书编号:" prop="certificateSerialNumber">
              <el-input v-model="calibrationRecord.certificateSerialNumber" :disabled="operationType === 'view'"
                size="small" style="width: 90%"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="10">
            <el-form-item label="状态:" label-width="140px" prop="status" required>
              <el-radio-group v-model="calibrationRecord.status" :disabled="operationType === 'view'">
                <el-radio value="0yes">合格</el-radio>
                <el-radio value="1no">不合格</el-radio>
                <el-radio value="2other">其他</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="确认日期:">
              <el-date-picker v-model="calibrationRecord.confirmDate" :disabled="operationType === 'view'"
                format="YYYY-MM-DD HH:mm:ss" placeholder="选择日期" size="small" style="width: 100%" type="datetime"
                value-format="YYYY-MM-DD HH:mm:ss">
              </el-date-picker>
            </el-form-item>
          </el-col>
          <el-col :span="17">
            <el-form-item label="附件:" prop="fileName">
              <el-input v-model="calibrationRecord.fileName"
                :style="`width: ${operationType === 'add' ? '85%' : '100%'}`" disabled size="small">
                <template #append><el-button v-if="operationType === 'add'" :icon="$icon('el-icon-delete-solid')"
                  @click="deleteFile"></el-button></template>
              </el-input>
              <el-upload v-if="operationType === 'add'" ref="upload" :action="action" :before-upload="beforeUpload"
                :headers="uploadHeader" :limit="1" :on-error="onError" :on-success="handleSuccessUp"
                :show-file-list="false" style="float: right;">
                <el-button :loading="upLoading" size="small" style="position: relative; top: -4px;"
                  type="primary">附件上传
                </el-button>
              </el-upload>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="备注:">
              <el-input v-model="calibrationRecord.remark" :disabled="operationType === 'view'" :rows="3" size="small"
                style="width: 96%" type="textarea"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <h4>
        <span style="display: flex;align-items: center;">
          <span class="line"></span><span>校准条目确认结果</span>
        </span>
      </h4>
      <el-table ref="calibrateTable" :data="calibrateParams" border>
        <el-table-column label="编号" type="index" width="60"></el-table-column>
        <el-table-column label="计量参数" prop="measurementParameter"></el-table-column>
        <el-table-column label="量程范围" prop="rangeOfMeasurement"></el-table-column>
        <el-table-column label="最大允许误差" prop="maxPermissibleError"></el-table-column>
        <el-table-column label="判定标准" prop="judgmentCriteria"></el-table-column>
        <el-table-column label="是否校准" prop="isCalibration">
          <template #header="scope">
            <span class="required-span">* </span>是否校准
          </template>
          <template #default="scope">
            <el-radio-group v-model="scope.row.isCalibration" :disabled="operationType === 'view'">
              <el-radio value="0yes">是</el-radio>
              <el-radio value="1no">否</el-radio>
            </el-radio-group>
          </template>
        </el-table-column>
        <el-table-column label="判定结果" min-width="140" prop="result">
          <template #header="scope">
            <span class="required-span">* </span>判定结果
          </template>
          <template #default="scope">
            <el-radio-group v-model="scope.row.result" :disabled="operationType === 'view'" @change="checkRadio()">
              <el-radio value="0yes">合格</el-radio>
              <el-radio value="1no">不合格</el-radio>
              <el-radio value="2other">其他</el-radio>
            </el-radio-group>
          </template>
        </el-table-column>
        <el-table-column label="单项结果说明" prop="singleResultStatement">
          <template #default="scope">
            <el-input v-model="scope.row.singleResultStatement" :disabled="operationType === 'view'"
              size="small"></el-input>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <template #footer><span class="dialog-footer">
        <el-button v-if="operationType === 'add'" @click="visible = false">取 æ¶ˆ</el-button>
        <el-button v-if="operationType === 'view'" @click="visible = false">关 é—­</el-button>
        <el-button v-if="operationType === 'add'" :loading="addRecordLoading" type="primary" @click="addRecord">ç¡®
          å®š</el-button>
      </span></template>
  </el-dialog>
</template>
<script>
import {
  showDeviceMetricsCopy,
  deleteCNASFile,
  selectDeviceMetric,
  addOrUpdateDeviceMetricRecord,
  getDeviceById
} from '@/api/cnas/resourceDemand/device.js'
import dayjs from 'dayjs'
import { selectQualifiedSupplierManagementPage } from '@/api/cnas/externalService/supplierManage/supplierManage'
import { mapGetters } from "@/utils/store-compat";
export default {
  name: "calibration-record-dia",
  data() {
    return {
      visible: false,
      deviceId: null,
      operationType: '',
      calibrationCycle: 12,
      calibrateParams: [],
      calibrateParamsLoading: false,
      addRecordLoading: false,
      upLoading: false,
      qualifiedSupplierNames: [],
      calibrationRecord: {
        unitOfMeasure: '', // è®¡é‡å•位
        calibrationDate: null, // æ ¡å‡†æ—¥æœŸ
        nextCalibrationDate: null, // ä¸‹æ¬¡æ ¡å‡†æ—¥æœŸ
        calculatingApparatus: '', // è®¡é‡å™¨å…·
        confirmDate: null, // ç¡®è®¤æ—¥æœŸ
        standardRange: '', // è®¡é‡æ ‡å‡†é‡ç¨‹
        calibrationStandardUncertainty: '', // è®¡é‡æ ‡å‡†ä¸ç¡®å®šåº¦
        byDocument: '', // ä¾æ®æ–‡ä»¶
        certificateSerialNumber: '', // è¯ä¹¦ç¼–号
        status: '', // çŠ¶æ€
        remark: '', // å¤‡æ³¨
        systemFileName: '', //
        fileName: '', //
      },
      formRules: {
        unitOfMeasure: [{ required: true, message: '请选择校准服务机构', trigger: 'change' }],
        calibrationDate: [{ required: true, message: '请选择校准日期', trigger: 'change' }],
        calculatingApparatus: [{ required: true, message: '请输入计量器具', trigger: 'blur' }],
        standardRange: [{ required: true, message: '请输入计量标准量程', trigger: 'blur' }],
        calibrationStandardUncertainty: [{ required: true, message: '请输入计量标准不确定度', trigger: 'blur' }],
        byDocument: [{ required: true, message: '请输入所依据文件', trigger: 'blur' }],
        status: [{ required: true, message: '请选择状态', trigger: 'change' }],
      },
    }
  },
  computed: {
    // æ ¡å‡†æœåŠ¡æœºæž„ä¸‹æ‹‰é€‰é¡¹ï¼ˆåˆæ ¼ä¾›åº”å•† + å½“前值兜底)
    calibrationServiceOptions() {
      const list = this.qualifiedSupplierNames.slice();
      const value = this.calibrationRecord.unitOfMeasure;
      if (value && list.indexOf(value) === -1) list.push(value);
      return list;
    },
    ...mapGetters(["nickName"]),
    action() {
      return this.javaApi + '/personBasicInfo/saveCNASFile'
    }
  },
  mounted() {
    this.obtainQualifiedSupplierList()
  },
  methods: {
    // æ‰“开弹窗:deviceId è®¾å¤‡id;type add新增/view查看;row æŸ¥çœ‹æ—¶çš„记录行
    open(deviceId, type, row) {
      this.deviceId = deviceId
      this.operationType = type
      if (type === 'view' && row) {
        showDeviceMetricsCopy({ id: row.id, type: 'calibrate' }).then(res => {
          this.calibrateParams = res.data
        })
        this.calibrationRecord = { ...row }
      } else {
        this.getDeviceCycle()
        this.getXmsg()
      }
      this.visible = true
    },
    // æ‹‰å–合格供应商列表(校准服务机构下拉选项)
    obtainQualifiedSupplierList() {
      selectQualifiedSupplierManagementPage({ current: 1, size: 999 }).then(res => {
        if (res.code === 200) {
          const rows = (res.data && res.data.records) || [];
          this.qualifiedSupplierNames = [...new Set(rows.map(r => r.supplierName).filter(Boolean))];
        }
      });
    },
    //状态判定
    checkRadio() {
      let resultList = this.calibrateParams.map(ele => ele.result)
      if (resultList && resultList.filter(ele => ele == '1no').length > 0) {
        this.calibrationRecord.status = '1no'
      } else if (resultList && resultList.filter(ele => ele == '2other').length == resultList.length) {
        this.calibrationRecord.status = '2other'
      } else if (resultList && resultList.filter(ele => ele == '0yes').length == resultList.length) {
        this.calibrationRecord.status = '0yes'
      }
    },
    // æŸ¥è¯¢è®¾å¤‡æ ¡å‡†å‘¨æœŸï¼ˆæœˆï¼‰ï¼Œä¸ŽåŽç«¯æ»šåŠ¨è®¾å¤‡æ¡£æ¡ˆæ—¥æœŸçš„è§„åˆ™ä¿æŒä¸€è‡´
    getDeviceCycle() {
      if (!this.deviceId) {
        return
      }
      getDeviceById({ deviceId: this.deviceId }).then(res => {
        const cycle = parseInt(res.data && res.data.calibrationDate)
        this.calibrationCycle = cycle > 0 ? cycle : 12
      }).catch(() => {
        this.calibrationCycle = 12
      })
    },
    // ä¸‹æ¬¡æ ¡å‡†æ—¥æœŸ = æ ¡å‡†æ—¥æœŸ + æ ¡å‡†å‘¨æœŸï¼ˆæœˆï¼‰
    getNextCalibrationDate(val) {
      if (!val) {
        this.calibrationRecord.nextCalibrationDate = null
        return
      }
      const cycle = parseInt(this.calibrationCycle)
      const months = cycle > 0 ? cycle : 12
      this.calibrationRecord.nextCalibrationDate = dayjs(val).add(months, 'month').format('YYYY-MM-DD')
    },
    // èŽ·å–è®¾å¤‡æ ¡å‡†å‚æ•°ï¼ˆæ ¡å‡†æ¡ç›®ï¼‰
    async getXmsg() {
      this.calibrateParamsLoading = true
      try {
        await selectDeviceMetric({ deviceId: this.deviceId, type: 'calibrate' }).then(res => {
          if (res.code == 200) {
            this.calibrateParams = res.data
          }
          this.calibrateParamsLoading = false
        })
      } catch (e) {
        console.log('getXmsg---', e)
        this.calibrateParamsLoading = false
      }
    },
    addRecord() {
      this.$refs['calibrationRecord'].validate((valid) => {
        if (valid) {
          try {
            if (this.calibrateParams.some(m => !m.isCalibration)) {
              this.$message.error('请选择是否校准')
              return
            }
            if (!this.calibrateParams.every(m => m.result)) {
              this.$message.error('请选择判定结果')
              return
            }
            this.addRecordLoading = true
            // åªå›žä¼ æ˜Žç»†éœ€è¦çš„字段:源行带主键 id/deviceId ä¼šè¦†ç›–历史条目,creationTime æ ¼å¼ä¹Ÿä¸Žæ˜Žç»†è¡¨ä¸å…¼å®¹
            const deviceMetricsCopyList = this.calibrateParams.map(item => ({
              measurementParameter: item.measurementParameter,
              rangeOfMeasurement: item.rangeOfMeasurement,
              maxPermissibleError: item.maxPermissibleError,
              judgmentCriteria: item.judgmentCriteria,
              createdBy: item.createdBy,
              isCalibration: item.isCalibration,
              result: item.result,
              singleResultStatement: item.singleResultStatement,
              type: item.type
            }))
            // åŽç«¯æ—¥æœŸå­—段要求 yyyy-MM-dd HH:mm:ss,日期控件只给到 yyyy-MM-dd
            const payload = {
              ...this.calibrationRecord,
              deviceId: this.deviceId,
              createUser: this.nickName,
              type: 'calibrate',
              deviceMetricsCopyList
            }
            if (payload.calibrationDate && payload.calibrationDate.length === 10) {
              payload.calibrationDate += ' 00:00:00'
            }
            if (payload.nextCalibrationDate && payload.nextCalibrationDate.length === 10) {
              payload.nextCalibrationDate += ' 00:00:00'
            }
            addOrUpdateDeviceMetricRecord(payload).then(res => {
              if (res.code == 200) {
                this.$message.success('添加成功')
                this.visible = false
                this.$emit('success')
              }
              this.addRecordLoading = false
            }).catch(() => {
              this.addRecordLoading = false
            })
          } catch (e) {
            console.log('addRecord---', e)
            this.addRecordLoading = false
          }
        } else {
          this.$message.warning('有必填项未填');
        }
      })
    },
    resetCalibrationRecord() {
      this.$refs.calibrationRecord.resetFields()
    },
    // ä¸Šä¼ é™„ä»¶
    handleSuccessUp(response, file) {
      if (response.code == 200) {
        // åœ¨ä¿å­˜èµ‹å€¼æ–°æ–‡ä»¶
        this.calibrationRecord.fileName = file.name
        this.calibrationRecord.systemFileName = response.data
        this.upLoading = false;
      } else {
        this.upLoading = false;
        this.$message.error(response.message)
      }
    },
    beforeUpload(file) {
      if (file.size > 1024 * 1024 * 10) {
        this.$message.error('上传文件不超过10M');
        this.$refs.upload.clearFiles()
        return false;
      } else {
        this.upLoading = true;
        return true;
      }
    },
    onError(err, file, fileList) {
      this.upLoading = false
      this.$message.error('上传失败')
      this.$refs.upload.clearFiles()
    },
    deleteFile() {
      this.$confirm('此操作将永久删除文件, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteCNASFile({ fileName: this.calibrationRecord.systemFileName }).then(res => {
          if (res.code == 200) {
            this.calibrationRecord.fileName = ''
            this.calibrationRecord.systemFileName = ''
            this.$refs.upload.clearFiles()
            this.$message.success('删除成功!')
          }
        })
      }).catch((err) => {
        console.log('err----', err)
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
  },
  watch: {
    visible(newVal) {
      if (newVal === false) {
        this.calibrateParams = []
        this.calibrationRecord = {
          unitOfMeasure: '', // è®¡é‡å•位
          calibrationDate: null, // æ ¡å‡†æ—¥æœŸ
          nextCalibrationDate: null, // ä¸‹æ¬¡æ ¡å‡†æ—¥æœŸ
          calculatingApparatus: '', // è®¡é‡å™¨å…·
          standardRange: '', // è®¡é‡æ ‡å‡†é‡ç¨‹
          calibrationStandardUncertainty: '', // è®¡é‡æ ‡å‡†ä¸ç¡®å®šåº¦
          byDocument: '', // ä¾æ®æ–‡ä»¶
          certificateSerialNumber: '', // è¯ä¹¦ç¼–号
          status: '', // çŠ¶æ€
          remark: '', // å¤‡æ³¨
        }
      }
    }
  }
}
</script>
<style scoped>
h4 {
  font-weight: 400;
  font-size: 16px;
  display: flex;
  justify-content: space-between;
  margin: 10px 0;
}
h4 .line {
  display: inline-block;
  width: 3px;
  height: 16px;
  background: var(--el-color-primary);
  margin-right: 4px;
}
</style>
src/views/CNAS/resourceDemand/device/component/check.vue
@@ -23,10 +23,13 @@
        </el-table-column>
        <el-table-column label="核查证书编号" min-width="150" prop="certificateSerialNumber"></el-table-column>
        <el-table-column label="说明" min-width="150" prop="remark" show-overflow-tooltip></el-table-column>
        <el-table-column label="核查日期" min-width="150" prop="calibrationDate"></el-table-column>
        <el-table-column label="下次核查日期" min-width="150" prop="nextCalibrationDate"></el-table-column>
        <el-table-column label="核查日期" min-width="150" prop="calibrationDate"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="下次核查日期" min-width="150" prop="nextCalibrationDate"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="登记人" min-width="150" prop="createUser"></el-table-column>
        <el-table-column label="登记日期" min-width="150" prop="createTime"></el-table-column>
        <el-table-column label="登记日期" min-width="150" prop="createTime"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column fixed="right" label="操作" min-width="150">
          <template #default="{ row }">
            <el-button size="small" link type="primary" @click="handleAttachmentClick(row)">附件</el-button>
@@ -87,7 +90,7 @@
        <el-table-column label="最大允许误差" prop="maxPermissibleError"></el-table-column>
        <el-table-column label="判定标准" prop="judgmentCriteria"></el-table-column>
        <el-table-column label="创建人" prop="createdBy"></el-table-column>
        <el-table-column label="创建时间" prop="creationTime"></el-table-column>
        <el-table-column label="创建时间" prop="creationTime" :formatter="formatDateCell"></el-table-column>
        <el-table-column fixed="right" label="操作">
          <template #default="scope">
            <el-button size="small" link type="primary" @click="handleDelete(scope.row)">删除</el-button>
@@ -250,6 +253,7 @@
<script>
import file from '@/utils/file';
import { mapGetters } from "@/utils/store-compat";
import { formatListDate } from './dateFormat';
export default {
  components: {},
  props: {
@@ -340,6 +344,9 @@
    this.getTableList(this.clickNodeVal.value) // èŽ·å–è®¾å¤‡æ ¸æŸ¥åˆ—è¡¨æ•°æ®
  },
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    //状态判定
    checkRadio() {
      let resultList = this.calibrateParams.map(ele => ele.result)
src/views/CNAS/resourceDemand/device/component/checkRecord.vue
@@ -1,7 +1,7 @@
<template>
  <div>
    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible"
      title="仪器设备期间核查比对记录表" width="80%" @close="resetForm">
      title="仪器设备期间核查记录表" width="80%" @close="resetForm">
      <el-steps :active="currentStep" align-center finish-status="success">
        <el-step title="填写设备核查对比记录"></el-step>
        <el-step title="审核"></el-step>
@@ -10,9 +10,9 @@
        <el-col :span="8">
          <div class="form-item">
            <span style="width: 110px">仪器名称:</span>
            <el-select v-model="form.deviceName" :disabled="currentStep !== 0" class="table_input" clearable filterable
              placeholder="设备名称" size="small" style="width:200px" @change="(val) => changeMachineName(val)">
              <el-option v-for="item in equipOptions" :key="item.value" :label="item.label" :value="item.label">
            <el-select v-model="selectedDeviceId" :disabled="currentStep !== 0" class="table_input" clearable filterable
              placeholder="设备名称" size="small" style="width:200px" @change="changeMachineName">
              <el-option v-for="item in equipOptions" :key="item.id" :label="item.label" :value="item.id">
                {{ item.label + '-' + item.value }}
              </el-option>
            </el-select>
@@ -84,11 +84,11 @@
          </div>
        </el-col>
      </el-row>
      <el-button size="small" style="margin: 10px 0" type="primary" @click="addRow">添加</el-button>
      <el-button v-if="currentStep === 0" size="small" style="margin: 10px 0" type="primary" @click="addRow">添加</el-button>
      <el-table :data="recordDetailList" height="300" style="width: 100%" border>
        <el-table-column label="测试点" min-width="130" prop="testPoint">
          <template #default="scope">
            <el-input v-model="scope.row.testPoint" clearable size="small"></el-input>
            <el-input v-model="scope.row.testPoint" :disabled="currentStep !== 0" clearable size="small"></el-input>
          </template>
        </el-table-column>
        <el-table-column min-width="180">
@@ -283,6 +283,7 @@
        { label: '相对偏差', value: 2 },
      ],
      equipOptions: [],
      selectedDeviceId: '',
      submitFormLoading: false,
      userList: [],
      reviewUserId: '',
@@ -299,6 +300,7 @@
  methods: {
    openDialog(row) {
      this.dialogVisible = true
      this.selectedDeviceId = ''
      this.form.planDetailsId = row.planDetailsId
      this.checkChargerUserId = row.checkChargerUserId
      this.getEquipOptions()
@@ -321,19 +323,38 @@
            this.currentStep = 2
          }
          this.reviewUserId = this.form.reviewUserId
          this.matchDeviceOption()
          this.$nextTick(() => {
            this.draftRestore('checkRecordForm', 'form', this.form.planDetailsId, 'dialogVisible')
            this.draftRestore('checkRecordRows', 'recordDetailList', this.form.planDetailsId, 'dialogVisible')
            // è‰ç¨¿é‡Œå¯èƒ½æ”¹è¿‡è®¾å¤‡ï¼Œæ¢å¤åŽé‡æ–°åŒ¹é…ä¸‹æ‹‰é€‰ä¸­é¡¹
            this.matchDeviceOption()
          })
        }
      }).catch(error => {
        console.error(error)
      })
    },
    // èµ‹å€¼ä»ªå™¨ç¼–号
    // æŒ‰è®¾å¤‡ id å›žå¡«åç§°å’Œç¼–号,避免同名设备选错
    changeMachineName(value) {
      const index = this.equipOptions.findIndex(item => item.deviceName === value)
      this.form.deviceNumber = this.equipOptions[index].managementNumber
      const item = this.equipOptions.find(device => device.id === value)
      if (item) {
        this.form.deviceName = item.deviceName
        this.form.deviceNumber = item.managementNumber
      } else {
        this.form.deviceName = ''
        this.form.deviceNumber = ''
      }
    },
    // åŽ†å²è®°å½•æ²¡æœ‰ deviceId,按名称+编号反查下拉选项
    matchDeviceOption() {
      if (!this.equipOptions.length || !this.form.deviceName) {
        return
      }
      const match = this.form.deviceNumber
        ? this.equipOptions.find(item => item.deviceName === this.form.deviceName && item.managementNumber === this.form.deviceNumber)
        : this.equipOptions.find(item => item.deviceName === this.form.deviceName)
      this.selectedDeviceId = match ? match.id : ''
    },
    addRow() {
      this.recordDetailList.push({ testPoint: '' })
@@ -390,6 +411,7 @@
            m.id = m.id
            return m
          })
          this.matchDeviceOption()
        }
      }).catch(error => {
        console.error(error)
src/views/CNAS/resourceDemand/device/component/dateFormat.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
import dayjs from 'dayjs'
// åˆ—表日期统一显示:纯日期只显示年月日,时间去掉 ISO çš„ T,只保留到分钟
export function formatListDate(value) {
  if (value === null || value === undefined || value === '') {
    return value
  }
  const str = String(value)
  if (/^\d{4}-\d{2}-\d{2}$/.test(str)) {
    return str
  }
  if (/T00:00:00(\.\d+)?$/.test(str) || / 00:00:00$/.test(str)) {
    return str.slice(0, 10)
  }
  const date = dayjs(str)
  return date.isValid() ? date.format('YYYY-MM-DD HH:mm') : str
}
// çº¯æ—¥æœŸç»Ÿä¸€æ˜¾ç¤º yyyy-MM-dd,忽略可能带出的时间部分
export function formatDateOnly(value) {
  if (value === null || value === undefined || value === '') {
    return value
  }
  const date = dayjs(String(value).replace(/\//g, '-'))
  return date.isValid() ? date.format('YYYY-MM-DD') : formatListDate(value)
}
src/views/CNAS/resourceDemand/device/component/deviceOverview.vue
@@ -29,7 +29,7 @@
        v-if="list.length > 0 || loading">
        <ul class="card">
          <li v-for="(m, i) in list" :key="i">
            <el-image class="img" :src="javaApi + '/img/' + m.imageUpload">
            <el-image v-if="m.imageUpload" class="img" :src="javaApi + '/img/' + m.imageUpload">
              <template #error><div  class="image-error" style="width: 88px;
            height: 88px;
            border-radius: 16px;
@@ -40,6 +40,15 @@
                <lims-icon name="el-icon-picture-outline" style="font-size:20px;color:var(--lims-text-2);"></lims-icon>
              </div></template>
            </el-image>
            <div v-else class="image-error" style="width: 88px;
            height: 88px;
            border-radius: 16px;
            display: flex;
            align-items: center;
            justify-content: center;
            border: 1px solid var(--lims-divider);margin-right: 10px;">
              <lims-icon name="el-icon-picture-outline" style="font-size:20px;color:var(--lims-text-2);"></lims-icon>
            </div>
            <div class="list-left">
              <div class="list-left-info">
                <span class="label" style="white-space: nowrap;">设备名称:</span>
@@ -99,6 +108,7 @@
  selectDeviceParameter,
  downloadDeviceImportTemplate,
} from '@/api/cnas/resourceDemand/device.js'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  props: {
    clickNodeVal: {
@@ -146,8 +156,8 @@
  methods: {
    downloadTemplate() {
      downloadDeviceImportTemplate().then(res => {
        this.$download.saveAs(new Blob([res]), '设备导入模板.xlsx')
      })
        saveBlobOrShowError(res, '设备导入模板.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
      }).catch(() => { })
    },
    submitImport() {
      if (!this.$refs.deviceUpload.uploadFiles.length) {
@@ -252,6 +262,11 @@
          }
        }
        this.loading = false
      }).catch(() => {
        // æ¸…掉本页占位,失败后可用查询/重置重新加载
        delete this.keyMap[key]
        this.loading = false
        this.finishLoding = true
      })
    },
    refresh() {
src/views/CNAS/resourceDemand/device/component/equipmentAcceptance.vue
@@ -26,7 +26,7 @@
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
        <el-pagination :current-page="pagination1.current" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
@@ -45,7 +45,7 @@
      </div>
      <div>
        <limsTable ref="yearTable" :column="columnData" :height="'calc(100vh - 30em)'" :highlightCurrentRow="true"
          :table-data="tableData" :table-loading="tableLoading" style="margin-top: 0.5em;" :page="pagination1">
          :table-data="tableData" :table-loading="tableLoading" style="margin-top: 0.5em;" :page="filePage">
        </limsTable>
      </div>
    </el-dialog>
@@ -67,6 +67,7 @@
  exportDeviceAcceptance,
  delDeviceAcceptance,
} from '@/api/cnas/resourceDemand/device.js'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "equipment-acceptance",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -82,6 +83,11 @@
    // è¿™é‡Œå­˜æ”¾æ•°æ®
    return {
      pagination1: {
        size: 10,
        current: 1,
        total: 0,
      },
      filePage: {
        size: 10,
        current: 1,
        total: 0,
@@ -171,6 +177,7 @@
    record(row) {
      this.filesDialogVisible = true
      this.acceptanceId = row.acceptanceId
      this.filePage.current = 1
      this.searchTableList()
    },
    // æŸ¥è¯¢é™„件列表
@@ -178,7 +185,8 @@
      this.tableLoading = true
      getDeviceAcceptanceFileList({ acceptanceId: this.acceptanceId }).then(res => {
        this.tableLoading = false
        this.tableData = res.data
        this.tableData = res.data || []
        this.filePage.total = this.tableData.length
      }).catch(err => {
        this.tableLoading = false
        console.log('err---', err);
@@ -197,7 +205,14 @@
    },
    // ä¸‹è½½
    upload(row) {
      this.$download.saveAs(row.fileUrl, row.fileName)
      if (!row.fileUrl) {
        this.$message.warning('未上传文件!')
        return
      }
      // å›¾ç‰‡å­˜ /img/,其他文档存 /word/
      const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(row.fileUrl)
      const url = this.javaApi + (isImage ? '/img/' : '/word/') + row.fileUrl
      this.$download.saveAs(url, row.fileName || row.fileUrl)
    },
    // åˆ é™¤
    delete(row) {
@@ -239,10 +254,11 @@
      this.$refs.upload.clearFiles()
    },
    handleSuccessUp(response,) {
      this.upLoading = false;
      if (response.code == 200) {
        this.$message.success('上传成功');
        this.searchTableList()
      } else {
        this.$message.error(response.message || response.msg || '上传失败')
      }
    },
    closeFilesLook() {
@@ -263,8 +279,9 @@
      this.outLoading = true
      exportDeviceAcceptance({ acceptanceId: id }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备验收.doc')
        saveBlobOrShowError(res, '设备验收.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // åˆ é™¤
src/views/CNAS/resourceDemand/device/component/equipmentAccident.vue
@@ -15,13 +15,14 @@
          <!--          <el-table-column label="仪器名称" min-width="150" prop="unitName"></el-table-column>-->
          <!--          <el-table-column label="型号" min-width="100" prop="model"></el-table-column>-->
          <el-table-column label="地点" min-width="150" prop="address"></el-table-column>
          <el-table-column label="日期" min-width="180" prop="accidentDate"></el-table-column>
          <el-table-column label="日期" min-width="180" prop="accidentDate"
            :formatter="formatDateCell"></el-table-column>
          <el-table-column label="事故情况" min-width="180" prop="descriptionOfAccident"
            show-overflow-tooltip></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="120">
            <template #default="scope">
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="primary"
                @click="handleForm(scope.row.accidentReportId)">操作</el-button>
              <el-button size="small" link type="primary" @click="handleDownOne(scope.row.accidentReportId)">导出</el-button>
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="danger"
@@ -29,7 +30,7 @@
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
        <el-pagination :current-page="pagination1.current" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
@@ -46,6 +47,8 @@
  exportDeviceAccidentReport,
  delDeviceAccidentReport,
} from '@/api/cnas/resourceDemand/device.js'
import { formatListDate } from './dateFormat'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "equipment-accident",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -75,6 +78,9 @@
  },
  // æ–¹æ³•集合
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    // æŸ¥è¯¢
    getYearTableDetailData(deviceId) {
      this.yearTableDetailDataLoading = true
@@ -117,8 +123,9 @@
      this.outLoading = true
      exportDeviceAccidentReport({ accidentReportId: id }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '仪器设备事故报告单.doc')
        saveBlobOrShowError(res, '仪器设备事故报告单.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // åˆ é™¤
src/views/CNAS/resourceDemand/device/component/equipmentCalibrationPlan.vue
@@ -1,114 +1,84 @@
<template>
  <!--  è®¾å¤‡æ ¡å‡†è®¡åˆ’-->
  <div>
    <div>
      <div style="margin: 10px 0;display: flex;align-items: center;justify-content: space-between;">
        <div class="title">
          <span style="font-weight: bold">年度计划表</span>
    <div style="margin: 10px 0 14px;">
      <div class="plan-top">
        <div class="plan-top-left">
          <span class="title" style="margin-bottom: 0;">{{ planInfo.planName || (planYear + '年度设备校准计划') }}</span>
          <el-select v-model="planYear" size="small" style="width: 110px; margin-left: 16px;" @change="handleYearChange">
            <el-option v-for="y in yearOptions" :key="y" :label="y" :value="y"></el-option>
          </el-select>
        </div>
        <div>
          <el-button size="small" type="primary" @click="getYearTableData">刷新</el-button>
          <el-button size="small" type="primary" @click="addYearPlan('add')">新增</el-button>
          <!--          <el-button size="small" type="primary" @click="record">导入</el-button>-->
          <el-button size="small" type="primary" @click="loadPlan">刷新</el-button>
          <el-button size="small" type="primary" :disabled="planInfo.ratifyStatus === 1"
            @click="tellApprove">批准通知</el-button>
          <el-button size="small" type="primary"
            :disabled="planInfo.ratifyStatus === 1 || userId != planInfo.ratifyUserId" @click="handleApprove">批准</el-button>
          <el-button size="small" type="primary" @click="downLoadPost">导出</el-button>
        </div>
      </div>
      <div class="plan-info-bar">
        <span>编制人:{{ planInfo.writeName || '—' }}</span>
        <span>编制日期:{{ planInfo.writeTimeStr || '—' }}</span>
        <span v-if="planInfo.ratifyStatus === 1">批准状态:<el-tag type="success">批准</el-tag></span>
        <span v-else-if="planInfo.ratifyStatus === 0">批准状态:<el-tag type="danger">不批准</el-tag></span>
        <span v-if="planInfo.ratifyRemark">批准内容:{{ planInfo.ratifyRemark }}</span>
        <span v-if="isRatified && planInfo.ratifyName">批准人:{{ planInfo.ratifyName }}</span>
        <span v-if="isRatified && planInfo.ratifyTimeStr">批准时间:{{ planInfo.ratifyTimeStr }}</span>
      </div>
    </div>
    <div class="search">
      <div>
        <el-table ref="yearTable" v-loading="yearTableDataLoading"
                  :data="yearTableData" height="calc(60vh - 16em)"
 border
                  highlight-current-row @current-change="currentChange">
          <!-- è¡¨æ ¼åˆ— -->
          <el-table-column align="center" header-align="center" label="序号" prop="prop" type="index"
            width="70"></el-table-column>
          <el-table-column label="年份" min-width="80" prop="planYear"></el-table-column>
          <el-table-column label="计划名称" min-width="180" prop="planName" show-overflow-tooltip></el-table-column>
          <el-table-column label="编制人" min-width="100" prop="writeName"></el-table-column>
          <el-table-column label="编制日期" min-width="160" prop="writeTime"></el-table-column>
          <el-table-column label="批准状态" min-width="100" prop="ratifyStatus">
            <template #default="scope">
              <el-tag v-if="scope.row.ratifyStatus === 1" type="success">批准</el-tag>
              <el-tag v-if="scope.row.ratifyStatus === 0" type="danger">不批准</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="批准内容" min-width="150" prop="ratifyRemark"></el-table-column>
          <el-table-column label="批准人" min-width="100" prop="ratifyName"></el-table-column>
          <el-table-column label="批准时间" min-width="150" prop="ratifyTime"></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="240">
            <template #default="scope">
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
                @click="addYearPlan('edit', scope.row)">编辑</el-button>
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
                @click="tellApprove(scope.row.planId)">批准通知</el-button>
              <el-button :disabled="scope.row.ratifyStatus === 1 || userId != scope.row.ratifyUserId" size="small"
                link type="primary" @click="handleApprove(scope.row.planId)">批准</el-button>
              <el-button size="small" link type="primary" @click="downLoadPost(scope.row.planId)">导出</el-button>
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="danger"
                @click="deleteFun(scope.row.planId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :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>
        <el-form :model="searchForm" ref="searchForm" size="small" :inline="true">
          <el-form-item label="设备名称及型号" prop="deviceName">
            <el-input v-model="searchForm.deviceName" clearable @keyup.enter="handleQuery"
              size="small"></el-input>
          </el-form-item>
          <el-form-item label="仪器编号" prop="deviceNumber">
            <el-input v-model="searchForm.deviceNumber" @keyup.enter="handleQuery" clearable
              size="small"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" size="small" @click="handleQuery">查询</el-button>
            <el-button size="small" @click="reset">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
    <div>
      <div class="title">
        <span style="font-weight: bold">年度计划明细表</span>
      </div>
      <div class="search">
        <div>
          <el-form :model="searchForm" ref="searchForm" size="small" :inline="true">
            <el-form-item label="设备名称及型号" prop="deviceName">
              <el-input v-model="searchForm.deviceName" clearable
                        @keyup.enter="getYearTableDetailData(currentRow)" size="small"></el-input>
            </el-form-item>
            <el-form-item label="仪器编号" prop="deviceNumber">
              <el-input v-model="searchForm.deviceNumber"
                        @keyup.enter="getYearTableDetailData(currentRow)" clearable size="small"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" size="small" @click="getYearTableDetailData(currentRow)">查询</el-button>
              <el-button size="small" @click="reset">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div>
          <el-button size="small" type="primary" @click="handleForm('add')">新增</el-button>
        </div>
      </div>
      <div>
        <el-table ref="yearTableDetailData" v-loading="yearTableDetailDataLoading" :data="yearTableDetailData"
 border
                  :height="'calc(100vh - 34em)'" 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" prop="deviceName" show-overflow-tooltip></el-table-column>
          <el-table-column label="设备数量" min-width="180" prop="deviceAmount"></el-table-column>
          <el-table-column label="仪器编号" min-width="150" prop="deviceNumber"></el-table-column>
          <el-table-column label="检定单位" min-width="150" prop="verificationUnit"> </el-table-column>
          <el-table-column label="检定周期" min-width="150" prop="verificationCycles"></el-table-column>
          <el-table-column label="最近检定时间" min-width="150" prop="lastDate"></el-table-column>
          <el-table-column label="本年计划校准时间" min-width="150" prop="planDate"></el-table-column>
          <el-table-column label="备注" min-width="150" prop="remark"></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="140">
            <template #default="scope">
              <el-button size="small" link type="primary" @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="deleteFun1(scope.row.planDetailId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
                       background :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper"
                       @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
      </div>
      <el-table ref="yearTableDetailData" v-loading="yearTableDetailDataLoading" :data="yearTableDetailData" border
        :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" prop="deviceName" show-overflow-tooltip></el-table-column>
        <el-table-column label="设备数量" min-width="90" prop="deviceAmount"></el-table-column>
        <el-table-column label="仪器编号" min-width="150" prop="deviceNumber"></el-table-column>
        <el-table-column label="检定单位" min-width="150" prop="verificationUnit"> </el-table-column>
        <el-table-column label="检定周期" min-width="100" prop="verificationCycles"></el-table-column>
        <el-table-column label="最近检定时间" min-width="130" prop="lastDate"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="本年计划校准时间" min-width="130" prop="planDate"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="备注" min-width="130" prop="remark"></el-table-column>
        <!-- æ“ä½œæŒ‰é’® -->
        <el-table-column align="center" fixed="right" label="操作" min-width="210">
          <template #default="scope">
            <el-button size="small" link type="primary" :disabled="!scope.row.deviceId"
              @click="handleExecute(scope.row)">执行</el-button>
            <el-button size="small" link type="primary" :disabled="planInfo.ratifyStatus === 1"
              @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" :disabled="planInfo.ratifyStatus === 1"
              @click="deleteFun1(scope.row.planDetailId)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination :current-page="pagination1.current" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
        background :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
      </el-pagination>
    </div>
    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible" title="设备校准计划"
      width="80%" @close="resetForm">
@@ -162,7 +132,7 @@
          </el-form-item>
        </el-col>
      </el-form>
      <template #footer><span  class="dialog-footer">
      <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>
@@ -173,7 +143,7 @@
        æ‰¹å‡†å¤‡æ³¨ï¼š
        <el-input v-model="ratifyRemark" type="textarea"></el-input>
      </span>
      <template #footer><span  class="dialog-footer">
      <template #footer><span class="dialog-footer">
        <el-button :loading="approvalLoading" @click="handleApproval(0)">不批准</el-button>
        <el-button :loading="approvalLoading" type="primary" @click="handleApproval(1)">批 å‡†</el-button>
      </span></template>
@@ -186,53 +156,36 @@
          </el-option>
        </el-select>
      </span>
      <template #footer><span  class="dialog-footer">
      <template #footer><span class="dialog-footer">
        <el-button :loading="notificationLoading" @click="closeNotificationDia">取 æ¶ˆ</el-button>
        <el-button :loading="notificationLoading" type="primary" @click="notification">提 äº¤</el-button>
      </span></template>
    </el-dialog>
    <!--上传报告-->
    <el-dialog v-model="uploadDia" title="数据导入" width="500px">
      å¹´ä»½ï¼š
      <el-date-picker v-model="planYear" type="year" value-format="YYYY" clearable format="YYYY" placeholder="选择年">
      </el-date-picker>
      <div style="margin: 0 auto;">
        <el-upload ref="upload1" :action="action" :auto-upload="false" :file-list="fileList" :headers="uploadHeader"
          :limit="1" accept='.doc,.docx' :on-change="beforeUpload" :on-error="onError" :on-success="handleSuccessUp"
          drag name="file">
          <lims-icon name="el-icon-upload"></lims-icon>
          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        </el-upload>
      </div>
      <template #footer><span  class="dialog-footer">
        <el-button @click="uploadDia = false">取 æ¶ˆ</el-button>
        <el-button :loading="uploading" type="primary" @click="submitUpload()">上 ä¼ </el-button>
      </span></template>
    </el-dialog>
    <add-year-plan-dia v-if="addYearPlanDia" ref="addYearPlanDia" @closeDia="closeDia"></add-year-plan-dia>
    <!-- æ·»åŠ /查看校准记录弹窗 -->
    <calibration-record-dia ref="calibrationRecordDia" @success="getYearTableDetailData"></calibration-record-dia>
  </div>
</template>
<script>
import AddYearPlanDia from "./addYearPlanDia.vue";
import AddVerificationYearPlanDia from "./addVerificationYearPlanDia.vue";
import CalibrationRecordDia from "./calibrationRecordDia.vue";
import {
  pageDeviceCalibrationPlan,
  getCalibrationPlanByYear,
  submiatRatifyDeviceCalibrationPlan,
  exportDeviceCalibrationPlanDetail,
  delDeviceCalibrationPlan,
  delDeviceCalibrationPlanDetail,
  pageDeviceCalibrationPlanDetail,
  addDeviceCalibrationPlanDetail,
  updateDeviceCalibrationPlanDetail,
  ratifyDeviceCalibrationPlan,
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/performance/class";
import { mapGetters } from "@/utils/store-compat";
import { formatDateOnly } from './dateFormat'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "equipment-calibration-plan",
  // import å¼•入的组件需要注入到对象中才能使用
  components: { AddVerificationYearPlanDia, AddYearPlanDia },
  components: { CalibrationRecordDia },
  props: {
    clickNodeVal: {
      type: Object,
@@ -244,18 +197,15 @@
  data() {
    // è¿™é‡Œå­˜æ”¾æ•°æ®
    return {
      planYear: '',
      yearOptions: [],
      planInfo: {},
      dialogVisible: false,
      searchForm: {
        deviceName: '',
        deviceNumber: '',
      },
      yearTableData: [],
      yearTableDetailData: [],
      pagination: {
        size: 10,
        current: 1,
        total: 0,
      },
      pagination1: {
        size: 10,
        current: 1,
@@ -278,66 +228,165 @@
        deviceNumber: [{ required: true, message: '请填写仪器编号', trigger: 'blur' }],
        planDate: [{ required: true, message: '请选择日期', trigger: 'change' }],
      },
      yearTableDataLoading: false,
      yearTableDetailDataLoading: false,
      currentRow: {},
      approvalDialog: false,
      approvalLoading: false,
      submitFormLoading: false,
      ratifyRemark: '',
      currentRowId: '',
      uploadDia: false,
      uploading: false,
      addYearPlanDia: false,
      fileList: [],
      planYear: '',
      responsibleOptions: [],
      notificationDia: false,
      notificationLoading: false,
      ratifyUserId: '',
      planId: ''
    }
  },
  mounted() {
    this.getYearTableData()
    this.loadYearOptions()
  },
  // æ–¹æ³•集合
  methods: {
    // æŸ¥è¯¢å¹´åº¦è®¡åˆ’表
    getYearTableData() {
      this.yearTableDataLoading = true
    // å¹´ä»½ä¸‹æ‹‰é€‰é¡¹ï¼šå·²æœ‰è®¡åˆ’年份 + å½“前年份
    loadYearOptions() {
      pageDeviceCalibrationPlan({
        current: 1,
        size: 99,
      }).then(res => {
        let years = []
        if (res.code == 200) {
          this.yearTableData = res.data.records
          this.pagination.total = res.data.total
          if (this.yearTableData.length > 0) {
            this.currentRow = this.yearTableData[0]
            this.$refs.yearTable.setCurrentRow(this.currentRow)
          }
          years = (res.data.records || []).map(r => r.planYear).filter(Boolean)
        }
        this.yearTableDataLoading = false
      }).catch(err => {
        this.yearTableDataLoading = false
        const currentYear = String(new Date().getFullYear())
        if (years.indexOf(currentYear) === -1) {
          years.push(currentYear)
        }
        this.yearOptions = [...new Set(years)].sort((a, b) => b.localeCompare(a))
        this.planYear = currentYear
        this.loadPlan()
      })
    },
    // åˆ†é¡µ
    handleSizeChange(val) {
      this.pagination.size = val
      this.getYearTableData()
    // åˆ‡æ¢å¹´ä»½
    handleYearChange() {
      this.pagination1.current = 1
      this.loadPlan()
    },
    // æŸ¥è¯¢å¹´ä»½è®¡åˆ’(不存在自动创建并补全到点明细),随后刷新明细
    loadPlan() {
      getCalibrationPlanByYear({ planYear: this.planYear }).then(res => {
        if (res.code == 200) {
          this.planInfo = res.data || {}
        }
        this.getYearTableDetailData()
      }).catch(() => {
        this.planInfo = {}
        this.yearTableDetailData = []
        this.pagination1.total = 0
        this.yearTableDetailDataLoading = false
      })
    },
    // æŸ¥è¯¢æ¡ä»¶å˜åŒ–后从第一页开始查
    handleQuery() {
      this.pagination1.current = 1
      this.getYearTableDetailData()
    },
    // æ˜Žç»†-查询
    getYearTableDetailData() {
      if (!this.planInfo.planId) {
        return
      }
      this.yearTableDetailDataLoading = true
      pageDeviceCalibrationPlanDetail({
        current: this.pagination1.current,
        size: this.pagination1.size,
        planId: this.planInfo.planId,
        deviceName: this.searchForm.deviceName,
        deviceNumber: this.searchForm.deviceNumber,
      }).then(res => {
        if (res.code == 200) {
          this.yearTableDetailData = res.data.records
          this.pagination1.total = res.data.total
        }
        this.yearTableDetailDataLoading = false
      }).catch(err => {
        this.yearTableDetailDataLoading = false
      })
    },
    formatDateCell(row, column, cellValue) {
      return formatDateOnly(cellValue)
    },
    // åˆ°ç‚¹éœ€æ ¡å‡†çš„行标红
    tableRowClassName({ row }) {
      return row.redFlag === 1 ? 'red-row' : ''
    },
    reset() {
      this.searchForm = {
        deviceName: '',
        deviceNumber: '',
      }
      this.pagination1.current = 1
      this.getYearTableDetailData()
    },
    // åˆ†é¡µ
    handleCurrentChange(val) {
      this.pagination.current = val
      this.getYearTableData()
    handleSizeChange1(val) {
      this.pagination1.size = val
      this.getYearTableDetailData()
    },
    // åˆ†é¡µ
    handleCurrentChange1(val) {
      this.pagination1.current = val
      this.getYearTableDetailData()
    },
    // æ‰§è¡Œï¼šæ‰“开校准记录弹窗录入
    handleExecute(row) {
      this.$refs.calibrationRecordDia.open(row.deviceId, 'add')
    },
    // æ‰“开明细弹框
    handleForm(type, row) {
      this.operationType = type
      this.dialogVisible = true
      this.$nextTick(() => {
        this.form = this.HaveJson(row)
      })
    },
    // æäº¤è¡¨å•
    submitForm() {
      this.$refs.modelForm.validate(valid => {
        if (valid) {
          this.submitFormLoading = true
          updateDeviceCalibrationPlanDetail(this.form).then(res => {
            if (res.code == 200) {
              this.$message.success('修改成功')
              this.dialogVisible = false
              this.getYearTableDetailData()
            }
            this.submitFormLoading = false
          }).catch(err => {
            this.submitFormLoading = false
          })
        }
      })
    },
    // æ˜Žç»†-删除
    deleteFun1(id) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delDeviceCalibrationPlanDetail({ planDetailsId: id }).then(res => {
          this.$message.success('删除成功!');
          this.getYearTableDetailData()
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    // æ‰“开提交批准弹框
    tellApprove(planId) {
    tellApprove() {
      this.getUserList()
      this.notificationDia = true
      this.planId = planId
    },
    // å…³é—­æäº¤æ‰¹å‡†å¼¹æ¡†
    closeNotificationDia() {
@@ -353,184 +402,23 @@
      this.notificationLoading = true
      submiatRatifyDeviceCalibrationPlan({
        ratifyUserId: this.ratifyUserId,
        planId: this.planId,
        planId: this.planInfo.planId,
      }).then(res => {
        this.notificationLoading = false
        if (res.code == 200) {
          this.closeNotificationDia()
          this.getYearTableData()
          this.loadPlan()
        }
      }).catch(err => {
        this.notificationLoading = false
      })
    },
    // å¹´åº¦è®¡åˆ’表-批准
    handleApprove(id) {
      this.currentRowId = id
    // æ‰¹å‡†
    handleApprove() {
      this.currentRowId = this.planInfo.planId
      this.approvalDialog = true
    },
    // å¹´åº¦è®¡åˆ’表-导出
    downLoadPost(planId) {
      exportDeviceCalibrationPlanDetail({ planId }).then(res => {
        const blob = new Blob([res], { type: 'application/msword' });
        this.$download.saveAs(blob, '设备校准计划.docx')
      })
    },
    // å¹´åº¦è®¡åˆ’表-删除
    deleteFun(id) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delDeviceCalibrationPlan({ planId: id }).then(res => {
          this.$message.success('删除成功!');
          this.getYearTableData();
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    // å¹´åº¦è®¡åˆ’详情表-删除
    deleteFun1(id) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delDeviceCalibrationPlanDetail({ planDetailsId: id }).then(res => {
          this.$message.success('删除成功!');
          this.getYearTableDetailData(this.currentRow)
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    currentChange(row) {
      this.currentRow = row
      this.getYearTableDetailData(this.currentRow)
    },
    getYearTableDetailData(row) {
      this.yearTableDetailDataLoading = true
      pageDeviceCalibrationPlanDetail({
        current: this.pagination1.current,
        size: this.pagination1.size,
        planId: row.planId,
        deviceName: this.searchForm.deviceName,
        deviceNumber: this.searchForm.deviceNumber,
      }).then(res => {
        if (res.code == 200) {
          this.yearTableDetailData = res.data.records
          this.pagination1.total = res.data.total
        }
        this.yearTableDetailDataLoading = false
      }).catch(err => {
        this.yearTableDetailDataLoading = false
      })
    },
    reset() {
      this.searchForm = {
        deviceName: '',
        deviceNumber: '',
      }
      this.getYearTableDetailData(this.currentRow)
    },
    // åˆ†é¡µ
    handleSizeChange1(val) {
      this.pagination1.size = val
      this.getYearTableDetailData(this.currentRow)
    },
    // åˆ†é¡µ
    handleCurrentChange1(val) {
      this.pagination1.current = val
      this.getYearTableDetailData(this.currentRow)
    },
    // æ‰“开弹框
    handleForm(type, row) {
      this.operationType = type
      this.dialogVisible = true
      this.form.planId = this.currentRow.planId
      if (this.operationType !== 'add') {
        this.$nextTick(() => {
          this.form = this.HaveJson(row)
        })
      } else {
        this.form = {
          deviceName: '',
          deviceAmount: '',
          deviceNumber: '',
          verificationUnit: '',
          verificationCycles: '',
          lastDate: '',
          planDate: '',
          remark: '',
          planId: this.currentRow.planId,
          planDetailId: '',
        }
      }
    },
    // æäº¤è¡¨å•
    submitForm() {
      this.$refs.modelForm.validate(valid => {
        if (valid) {
          if (this.operationType === 'add') {
            this.submitFormLoading = true
            addDeviceCalibrationPlanDetail(this.form).then(res => {
              if (res.code == 200) {
                this.$message.success('新增成功')
                this.dialogVisible = false
                this.getYearTableData()
              }
              this.submitFormLoading = false
            }).catch(err => {
              this.submitFormLoading = false
            })
          } else {
            this.submitFormLoading = true
            updateDeviceCalibrationPlanDetail(this.form).then(res => {
              if (res.code == 200) {
                this.$message.success('新增成功')
                this.dialogVisible = false
                this.getYearTableData()
              }
              this.submitFormLoading = false
            }).catch(err => {
              this.submitFormLoading = false
            })
          }
        }
      })
    },
    // æ‰“开新增弹框
    addYearPlan(type, row) {
      this.addYearPlanDia = true
      this.$nextTick(() => {
        this.$refs.addYearPlanDia.openDialog(type, row)
      })
    },
    closeDia() {
      this.addYearPlanDia = false
      this.getYearTableData()
    },
    submitUpload() {
      if (!this.planYear) {
        this.$message.warning('请选择年份')
        return;
      }
      if (this.$refs.upload1.uploadFiles.length === 0) {
        this.$message.error('未选择文件')
        return
      }
      this.uploading = true
      this.$refs.upload1.submit();
    },
    // æäº¤æ‰¹å‡†
    // æäº¤æ‰¹å‡†ç»“æžœ
    handleApproval(status) {
      const personTrainingUpdateDto = {
        planId: this.currentRowId,
@@ -542,43 +430,22 @@
        if (res.code === 200) {
          this.$message.success('提交成功!');
          this.approvalDialog = false
          this.getYearTableData();
          this.loadPlan()
        }
        this.approvalLoading = false
      }).catch(() => {
        this.approvalLoading = false
      })
    },
    // å¯¼å‡º
    downLoadPost() {
      exportDeviceCalibrationPlanDetail({ planId: this.planInfo.planId }).then(res => {
        saveBlobOrShowError(res, '设备校准计划.docx', 'application/msword')
      }).catch(() => { })
    },
    resetForm() {
      this.$refs.modelForm.resetFields();
      this.dialogVisible = false
    },
    // æ‰“开报告弹框
    record(row) {
      this.uploadDia = true
    },
    // å¯¼å…¥æµç¨‹
    beforeUpload(file) {
      if (file.size > 1024 * 1024 * 10) {
        this.$message.error('上传文件不超过10M');
        this.$refs.upload.clearFiles()
        return false;
      } else {
        return true;
      }
    },
    onError(err, file, fileList) {
      this.$message.error('上传失败')
      this.$refs.upload.clearFiles()
    },
    handleSuccessUp(response) {
      this.uploading = false;
      if (response.code == 200) {
        this.$message.success('上传成功');
        this.getYearTableData()
      } else {
        this.$message.error('上传失败')
      }
    },
    // èŽ·å–è´Ÿè´£äººä¿¡æ¯æŽ¥å£
    getUserList() {
@@ -596,12 +463,12 @@
      });
    }
  },
  // ç”¨äºŽä¸Šä¼ æ–‡ä»¶çš„信息
  computed: {
    action() {
      return this.javaApi + '/deviceCalibrationPlan/importDeviceCalibrationPlan' + '?planYear=' + this.planYear
    },
    ...mapGetters(["userId"]),
    // æ˜¯å¦å·²å®Œæˆå®¡æ‰¹ï¼ˆæ‰¹å‡†/不批准)
    isRatified() {
      return this.planInfo.ratifyStatus === 0 || this.planInfo.ratifyStatus === 1;
    },
  },
}
</script>
@@ -626,9 +493,39 @@
  background-color: var(--el-color-primary);
  border-radius: 2px;
}
.plan-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}
.plan-top-left {
  display: flex;
  align-items: center;
}
.plan-info-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 32px;
  background: #f5f7fa;
  border-radius: 4px;
  padding: 10px 16px;
  margin-top: 14px;
  font-size: 14px;
  color: #606266;
}
.search {
  height: 46px;
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
:deep(.red-row td) {
  background: #ffcccc !important;
}
</style>
src/views/CNAS/resourceDemand/device/component/equipmentCheck.vue
@@ -17,7 +17,7 @@
          <span style="width: 80px">A仪器名称:</span>
          <el-select v-model="form.adeviceId" :disabled="currentStep !== 0" class="table_input" clearable filterable
            placeholder="设备名称" size="small" style="width:200px" @change="(val) => changeMachineName(val, 'A')">
            <el-option v-for="item in equipOptions" :key="item.value" :label="item.label" :value="item.id">
            <el-option v-for="item in equipOptions" :key="item.id" :label="item.label" :value="item.id">
              {{ item.label + '-' + item.value }}
            </el-option>
          </el-select>
@@ -36,7 +36,7 @@
          <span style="width: 80px">B仪器名称:</span>
          <el-select v-model="form.bdeviceId" :disabled="currentStep !== 0" class="table_input" clearable filterable
            placeholder="设备名称" size="small" style="width:200px" @change="(val) => changeMachineName(val, 'B')">
            <el-option v-for="item in equipOptions" :key="item.value" :label="item.label" :value="item.id">
            <el-option v-for="item in equipOptions" :key="item.id" :label="item.label" :value="item.id">
              {{ item.label + '-' + item.value }}
            </el-option>
          </el-select>
@@ -55,7 +55,7 @@
          <span style="width: 80px">C仪器名称:</span>
          <el-select v-model="form.cdeviceId" :disabled="currentStep !== 0" class="table_input" clearable filterable
            placeholder="设备名称" size="small" style="width:200px" @change="(val) => changeMachineName(val, 'C')">
            <el-option v-for="item in equipOptions" :key="item.value" :label="item.label" :value="item.id">
            <el-option v-for="item in equipOptions" :key="item.id" :label="item.label" :value="item.id">
              {{ item.label + '-' + item.value }}
            </el-option>
          </el-select>
@@ -73,7 +73,7 @@
        <el-button v-if="currentStep === 0" size="small" type="primary" @click="addTableRow">添加</el-button>
      </div>
      <div style="margin: 10px 0">
        <el-table ref="yearTable" :data="recordContrastDetailsList" height="300px" style="width: 100% ;"
        <el-table ref="yearTable" :data="form.recordContrastDetailsList" height="300px" style="width: 100% ;"
 border>
          <el-table-column align="center" header-align="center" label="序号" type="index" width="60"></el-table-column>
          <el-table-column label="核查项目" min-width="170" prop="checkItems">
@@ -127,7 +127,7 @@
        </div>
      </div>
      <template #footer><span  class="dialog-footer">
        <el-button @click="resetForm">取 æ¶ˆ</el-button>
        <el-button @click="handleCancel">取 æ¶ˆ</el-button>
        <el-button v-if="currentStep === 0 && userId == checkChargerUserId" :loading="submitFormLoading" type="primary" @click="submitCheck">ç¡®
          å®š</el-button>
        <el-button v-if="currentStep === 1 && userId == reviewUserId" :loading="submitFormLoading" @click="examine(0)">不通过</el-button>
@@ -179,7 +179,6 @@
        planDetailsId: '',
      },
      equipOptions: [],
      recordContrastDetailsList: [],
      userList: [],
      checkChargerUserId: '',
      reviewUserId: ''
@@ -202,10 +201,12 @@
      this.searchInfo()
    },
    searchInfo() {
      getExamineRecordContrast({ planDetailsId: this.form.planDetailsId }).then(res => {
      const planDetailsId = this.form.planDetailsId
      getExamineRecordContrast({ planDetailsId }).then(res => {
        if (res.code === 200) {
          this.form = { ...res.data }
          this.recordContrastDetailsList = this.form.recordContrastDetailsList || []
          // æ— åŽ†å²è®°å½•æ—¶æŽ¥å£å¯èƒ½è¿”å›žç©ºï¼ŒplanDetailsId å¿…须保留,否则无法提交
          this.form = { ...(res.data || {}), planDetailsId }
          this.form.recordContrastDetailsList = this.form.recordContrastDetailsList || []
          if (!this.form.reviewUserId) {
            this.currentStep = 0
          } else {
@@ -217,7 +218,6 @@
          this.reviewUserId = this.form.reviewUserId
          if (this.currentStep === 0) {
            this.draftRestore('equipmentCheck', 'form', this.form.planDetailsId, 'dialogVisible')
            this.recordContrastDetailsList = this.form.recordContrastDetailsList || []
          }
        }
      }).catch(error => {
@@ -226,25 +226,31 @@
    },
    // èµ‹å€¼ä»ªå™¨ç¼–号
    changeMachineName(value, type) {
      const index = this.equipOptions.findIndex(item => item.id === value)
      if (index > -1) {
        if (type === 'A') {
          this.form['adeviceNumber'] = this.equipOptions[index].value
        }
        if (type === 'B') {
          this.form['bdeviceNumber'] = this.equipOptions[index].value
        }
        if (type === 'C') {
          this.form['cdeviceNumber'] = this.equipOptions[index].value
        }
      const item = this.equipOptions.find(device => device.id === value)
      if (type === 'A') {
        this.form['adeviceNumber'] = item ? item.value : ''
      }
      if (type === 'B') {
        this.form['bdeviceNumber'] = item ? item.value : ''
      }
      if (type === 'C') {
        this.form['cdeviceNumber'] = item ? item.value : ''
      }
    },
    // æ·»åŠ è¡¨æ ¼æ•°æ®
    addTableRow() {
      this.recordContrastDetailsList.push({ checkItems: '' })
      if (!this.form.recordContrastDetailsList) {
        this.form.recordContrastDetailsList = []
      }
      this.form.recordContrastDetailsList.push({ checkItems: '' })
    },
    submitCheck() {
      this.form.recordContrastDetailsList = this.HaveJson(this.recordContrastDetailsList)
      const deviceIds = [this.form.adeviceId, this.form.bdeviceId, this.form.cdeviceId].filter(Boolean)
      if (new Set(deviceIds).size !== deviceIds.length) {
        this.$message.error('A/B/C ä»ªå™¨ä¸èƒ½é€‰æ‹©åŒä¸€å°è®¾å¤‡')
        return
      }
      this.form.recordContrastDetailsList = this.HaveJson(this.form.recordContrastDetailsList || [])
      this.submitFormLoading = true
      addExamineRecordContrast(this.form).then(res => {
        if (res.code == 200) {
@@ -273,6 +279,21 @@
        this.submitFormLoading = false
      })
    },
    // å–消按钮:确认后整体清空本次草稿;右上角关闭/意外退出则保留草稿
    handleCancel() {
      if (this.currentStep !== 0) {
        this.resetForm()
        return
      }
      this.$confirm('取消后本次填写的数据将被清空,且无法恢复,是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '继续填写',
        type: 'warning'
      }).then(() => {
        this.draftClear('equipmentCheck')
        this.resetForm()
      }).catch(() => {})
    },
    resetForm() {
      this.draftStop('equipmentCheck')
      this.dialogVisible = false
src/views/CNAS/resourceDemand/device/component/equipmentFailure.vue
@@ -19,15 +19,15 @@
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="140">
            <template #default="scope">
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="primary"
                @click="handleForm(scope.row.maintenanceId)">操作</el-button>
              <el-button size="small" link type="primary" @click="handleDownOne(scope.row.maintenanceId)">导出</el-button>
              <el-button size="small" link type="danger"
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="danger"
                @click="deleteFun(scope.row.maintenanceId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
        <el-pagination :current-page="pagination1.current" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
@@ -44,6 +44,7 @@
  exportDeviceBreakdownMaintenance,
  delDeviceBreakdownMaintenance,
} from '@/api/cnas/resourceDemand/device.js'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "equipment-failure",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -117,8 +118,9 @@
        maintenanceId: id
      }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '仪器设备修理申请表.doc')
        saveBlobOrShowError(res, '仪器设备修理申请表.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // åˆ é™¤
src/views/CNAS/resourceDemand/device/component/equipmentMaintenance.vue
@@ -25,10 +25,13 @@
        <el-row>
          <el-col :span="24">
            <el-form-item label="维护内容:" prop="maintenanceContentArr">
              <el-checkbox-group v-model="form.maintenanceContentArr" :disabled="operationType === 'view'">
              <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>
@@ -67,6 +70,7 @@
} from "@/api/cnas/resourceDemand/device";
import limsTable from "@/components/Table/lims-table.vue";
import {selectUserCondition} from "@/api/system/user";
import {saveBlobOrShowError} from '@/utils/saveBlob'
export default {
  name: '',
@@ -127,6 +131,7 @@
        maintenanceDate: '',
        maintenanceContentArr: [],
        maintenanceContent: '',
        maintenanceContentText: '',
        maintenanceUserId: '',
        remark: '',
      },
@@ -135,7 +140,19 @@
      qualificationList: [],
      rules: {
        maintenanceDate: [{ required: true, message: '请选择维护日期', trigger: 'change' }],
        maintenanceContentArr: [{ 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: [],
@@ -153,6 +170,7 @@
    },
    // åˆ†é¡µåˆ‡æ¢
    pagination(page) {
      this.page.current = page.page
      this.page.size = page.limit
      this.getTableList()
    },
@@ -178,7 +196,8 @@
        this.form.id = ''
        if (this.operationType === 'edit') {
          this.form = {...row}
          this.form['maintenanceContentArr'] = this.form.maintenanceContent.split(',')
          this.form['maintenanceContentArr'] = this.form.maintenanceContent ? this.form.maintenanceContent.split(',') : []
          this.form['maintenanceContentText'] = this.form.maintenanceContent || ''
        }
      })
      this.getDictS()
@@ -224,13 +243,14 @@
        deviceId: this.clickNodeVal.value
      }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备维护保养.doc')
        saveBlobOrShowError(res, '设备维护保养.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    handleDeleteClick(row) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
      this.$confirm('此操作将永久删除该条保养记录, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
@@ -254,7 +274,9 @@
      this.$refs.form.validate((valid) => {
        if (valid) {
          this.buttonLoading = true;
          this.form.maintenanceContent = this.form.maintenanceContentArr.join(',')
          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;
src/views/CNAS/resourceDemand/device/component/equipmentMaintenancePlan.vue
@@ -1,150 +1,156 @@
<template>
  <!--  è®¾å¤‡ä¿å…»è®¡åˆ’-->
  <div>
    <div>
      <div style="margin: 10px 0;text-align: right">
        <el-button size="small" type="primary" @click="getYearTableDetailData">刷新</el-button>
        <el-button size="small" type="primary" @click="handleForm('add')">新增</el-button>
    <div style="margin: 10px 0 14px;">
      <div class="plan-top">
        <div class="plan-top-left">
          <span class="title" style="margin-bottom: 0;">{{ planInfo.planName || (planYear + '年度设备保养计划') }}</span>
          <el-select v-model="planYear" size="small" style="width: 110px; margin-left: 16px;" @change="handleYearChange">
            <el-option v-for="y in yearOptions" :key="y" :label="y" :value="y"></el-option>
          </el-select>
        </div>
        <div>
          <el-button size="small" type="primary" @click="loadPlan">刷新</el-button>
          <el-button size="small" type="primary" :disabled="planInfo.status === 1"
            @click="tellApprove">审核通知</el-button>
          <el-button size="small" type="primary"
            :disabled="planInfo.status === 1 || userId != planInfo.auditId" @click="handleApprove">审核</el-button>
          <el-button size="small" type="primary" :loading="outLoading" @click="handleDownOne">导出</el-button>
        </div>
      </div>
      <div>
        <el-table ref="yearTable" v-loading="yearTableDetailDataLoading" :data="yearTableDetailData"
 border
          height="calc(100vh - 18em)" 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="80" prop="planYear"></el-table-column>
          <el-table-column label="编制人" min-width="120" prop="compiler"></el-table-column>
          <el-table-column label="编制时间" min-width="160" prop="datePreparation"></el-table-column>
          <el-table-column label="审核人" min-width="150" prop="audit"></el-table-column>
          <el-table-column label="审核时间" min-width="180" prop="auditDate"></el-table-column>
          <el-table-column label="审核状态" min-width="180" prop="status">
            <template #default="scope">
              <el-tag v-if="scope.row.status === 1" type="success">通 è¿‡</el-tag>
              <el-tag v-if="scope.row.status === 0" type="danger">不通过</el-tag>
            </template>
          </el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="260">
            <template #default="scope">
              <el-button :disabled="scope.row.status === 1" size="small" link type="primary"
                @click="handleForm('edit', scope.row)">编辑</el-button>
              <el-button size="small" link type="primary" @click="handleForm('view', scope.row)">查看</el-button>
              <el-button :disabled="scope.row.status === 1" size="small" link type="primary"
                @click="tellApprove(scope.row.maintenancePlanId)">审核通知</el-button>
              <el-button :disabled="scope.row.status === 1 || userId != scope.row.auditId" size="small" link type="primary"
                @click="handleForm('check', scope.row)">审核</el-button>
              <el-button size="small" link type="primary" @click="handleDownOne(scope.row.maintenancePlanId)">导出</el-button>
              <el-button :disabled="scope.row.status === 1" size="small" link type="danger"
                @click="deleteFun(scope.row.maintenancePlanId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
      <div class="plan-info-bar">
        <span>编制人:{{ planInfo.compiler || '—' }}</span>
        <span>编制日期:{{ planInfo.datePreparationStr || '—' }}</span>
        <span v-if="planInfo.status === 1">审核状态:<el-tag type="success">通 è¿‡</el-tag></span>
        <span v-else-if="planInfo.status === 0">审核状态:<el-tag type="danger">不通过</el-tag></span>
        <span v-else>审核状态:<el-tag type="info">未审核</el-tag></span>
        <span v-if="planInfo.auditRemark">审核信息:{{ planInfo.auditRemark }}</span>
        <span v-if="isAudited && planInfo.audit">审核人:{{ planInfo.audit }}</span>
        <span v-if="isAudited && planInfo.auditDateStr">审核时间:{{ planInfo.auditDateStr }}</span>
      </div>
    </div>
    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="applicationForm"
      title="设备保养计划表" width="80%" @close="closeDialog">
      <div style="display: flex;align-items: center;">
        <el-button v-if="operationType === 'edit' || operationType === 'add'" size="small" type="primary" @click="addTableRow">添加</el-button>
        <span style="width: 60px;margin-left: 10px">年份:</span>
        <el-date-picker v-model="form.planYear" type="year" value-format="YYYY" clearable size="small" format="YYYY"
          placeholder="选择年" :disabled="operationType !== 'edit' && operationType !== 'add'">
        </el-date-picker>
    <div class="search">
      <div>
        <el-form :model="searchForm" ref="searchForm" size="small" :inline="true">
          <el-form-item label="设备名称" prop="deviceName">
            <el-input v-model="searchForm.deviceName" clearable @keyup.enter="handleQuery"
              size="small"></el-input>
          </el-form-item>
          <el-form-item label="设备编号" prop="deviceNumber">
            <el-input v-model="searchForm.deviceNumber" @keyup.enter="handleQuery" clearable
              size="small"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" size="small" @click="handleQuery">查询</el-button>
            <el-button size="small" @click="reset">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
      <div style="margin: 10px 0">
        <el-table ref="yearTable" :data="deviceMaintenancePlanDetails" id="templateParamTable" row-key="deviceId"
 border
          height="560px" style="width: 100% ;">
          <el-table-column align="center" header-align="center" label="序号" type="index" width="60"></el-table-column>
          <el-table-column label="设备名称" min-width="170" prop="deviceName">
            <template #default="scope">
              <el-input v-model="scope.row.deviceName" :disabled="operationType !== 'edit' && operationType !== 'add'" clearable
    </div>
    <div>
      <el-table ref="yearTable" v-loading="tableLoading" :data="tableData" border
        :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>
          <template #default="scope">
            {{ scope.row.deviceName }}{{ scope.row.specificationModel ? ' ' + scope.row.specificationModel : '' }}
          </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">
          <template #default="scope">
            <el-button size="small" link type="primary" :disabled="planInfo.status === 1"
              @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" :disabled="planInfo.status === 1"
              @click="deleteRow(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination :current-page="pagination1.current" :page-size="pagination1.size"
        :page-sizes="[10, 20, 30, 50, 100]" background :total="pagination1.total"
        layout="->,total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange1"
        @current-change="handleCurrentChange1">
      </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">
        <el-row>
          <el-col :span="12">
            <el-form-item label="设备名称:">
              <el-input v-model="form.deviceName" disabled size="small"></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-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>
          </el-col>
          <el-col :span="12">
            <el-form-item label="保养周期:">
              <el-input v-model="form.maintenanceIntervals" :disabled="operationType === 'view'" clearable
                size="small"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="设备编号" min-width="140" prop="deviceNumber">
            <template #default="scope">
              <el-input v-model="scope.row.deviceNumber" :disabled="operationType !== 'edit' && operationType !== 'add'" clearable
                size="small"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="归属实验室" min-width="120" prop="storagePoint">
            <template #default="scope">
              <el-input v-model="scope.row.storagePoint" :disabled="operationType !== 'edit' && operationType !== 'add'" clearable
                size="small"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="保养关键部位" min-width="120" prop="maintenanceSite">
            <template #default="scope">
              <el-input v-model="scope.row.maintenanceSite" :disabled="operationType !== 'edit' && operationType !== 'add'" clearable size="small"
            </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>
            </template>
          </el-table-column>
          <el-table-column label="保养内容" min-width="120" prop="maintenanceContent">
            <template #default="scope">
              <el-input v-model="scope.row.maintenanceContent" :disabled="operationType !== 'edit' && operationType !== 'add'" clearable
                size="small" type="textarea"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="保养周期" min-width="90" prop="maintenanceIntervals">
            <template #default="scope">
              <el-input v-model="scope.row.maintenanceIntervals" :disabled="operationType !== 'edit' && operationType !== 'add'" clearable
                size="small"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="计划保养时间" min-width="140" prop="maintenanceDate">
            <template #default="scope">
              <el-date-picker v-model="scope.row.maintenanceDate" :disabled="operationType !== 'edit' && operationType !== 'add'" clearable
                size="small" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD" style="width:100%"></el-date-picker>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="80" align="center" v-if="operationType === 'edit' || operationType === 'add'">
            <template #default="scope">
              <el-button link type="danger" @click="deleteRow(scope.$index)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <template #footer><span  class="dialog-footer">
        <el-button @click="closeDialog">取 æ¶ˆ</el-button>
        <el-button v-if="operationType === 'edit' || operationType === 'add'" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
          è®¤</el-button>
        <el-button v-if="operationType === 'check'" :loading="submitFormLoading" type="primary"
          @click="checkStatus(0)">不通过</el-button>
        <el-button v-if="operationType === 'check'" :loading="submitFormLoading" type="primary"
          @click="checkStatus(1)">通
          è¿‡</el-button>
            </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"
                value-format="YYYY-MM-DD"></el-date-picker>
            </el-form-item>
          </el-col>
        </el-row>
      </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>
      </span></template>
    </el-dialog>
    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="addEquipDia" title="添加设备"
      width="50%">
      <el-table ref="multipleTable" :data="equipOptions" tooltip-effect="dark" height="500" style="width: 100%"
 border
        @selection-change="handleSelectionChange">
        <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="managementNumber" label="归属实验室"></el-table-column>
      </el-table>
      <template #footer><span  class="dialog-footer">
        <el-button @click="addEquipDia = false">取 æ¶ˆ</el-button>
        <el-button v-if="operationType === 'edit' || operationType === 'add'" :loading="submitFormLoading" type="primary"
          @click="changeMachineName">ç¡®
          è®¤</el-button>
    <el-dialog v-model="approvalDialog" title="审核" width="30%" @close="approvalDialog = false">
      <span>
        å®¡æ ¸ä¿¡æ¯ï¼š
        <el-input v-model="approvalRemark" type="textarea"></el-input>
      </span>
      <template #footer><span class="dialog-footer">
        <el-button :loading="approvalLoading" @click="handleApproval(0)">不通过</el-button>
        <el-button :loading="approvalLoading" type="primary" @click="handleApproval(1)">通 è¿‡</el-button>
      </span></template>
    </el-dialog>
    <el-dialog v-model="notificationDia" title="提交审核" width="30%" @close="closeNotificationDia">
      <span style="margin-top: 10px;display: inline-block">
        è¯·é€‰æ‹©å®¡æ ¸äººï¼š
        <el-select v-model="auditId" clearable filterable size="small" style="width: 90%;">
          <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id">
        <el-select v-model="auditUserId" clearable filterable size="small" style="width: 90%;">
          <el-option v-for="item in responsibleOptions" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </span>
      <template #footer><span  class="dialog-footer">
      <template #footer><span class="dialog-footer">
        <el-button :loading="notificationLoading" @click="closeNotificationDia">取 æ¶ˆ</el-button>
        <el-button :loading="notificationLoading" type="primary" @click="notification">提 äº¤</el-button>
      </span></template>
@@ -153,253 +159,213 @@
</template>
<script>
import Sortable from "sortablejs";
import {
  selectDeviceMaintenancePlanByPage,
  submitReviewMaintenancePlanStatus,
  getMaintenancePlanDetail,
  addMaintenancePlan,
  updateMaintenancePlan,
  getMaintenancePlanByYear,
  pageMaintenancePlanDetail,
  updateMaintenancePlanDetail,
  deleteMaintenancePlanDetail,
  exportDeviceMaintenancePlan,
  deleteMaintenancePlan,
  deviceScopeSearch,
  reviewMaintenancePlanStatus,
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { mapGetters } from "@/utils/store-compat";
import { formatDateOnly } from './dateFormat'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "equipment-maintenance-plan",
  // import å¼•入的组件需要注入到对象中才能使用
  components: {},
  props: {
    clickNodeVal: {
      type: Object,
      default: () => {
        return {};
      }
    }
  },
  data() {
    // è¿™é‡Œå­˜æ”¾æ•°æ®
    return {
      planYear: '',
      yearOptions: [],
      planInfo: {},
      searchForm: {
        deviceName: '',
        deviceNumber: '',
      },
      tableData: [],
      tableLoading: false,
      pagination1: {
        size: 10,
        current: 1,
        total: 0,
      },
      yearTableDetailDataLoading: false,
      yearTableDetailData: [],
      deviceMaintenancePlanDetails: [],
      selectionRows: [],
      deviceIds: [],
      applicationForm: false,
      submitFormLoading: false,
      dialogVisible: false,
      operationType: '',
      equipOptions: [],
      form: {
        planYear: '',
        deviceMaintenancePlanDetails: []
      form: {},
      rules: {
        maintenanceDate: [{ required: true, message: '请选择计划保养时间', trigger: 'change' }],
      },
      addEquipDia: false,
      submitFormLoading: false,
      outLoading: false,
      responsibleOptions: [],
      notificationDia: false,
      notificationLoading: false,
      auditId: '',
      maintenancePlanId: ''
      auditUserId: '',
      approvalDialog: false,
      approvalLoading: false,
      approvalRemark: '',
    }
  },
  mounted() {
    this.getYearTableDetailData()
    this.loadYearOptions()
  },
  // æ–¹æ³•集合
  methods: {
    // æŸ¥è¯¢
    getYearTableDetailData() {
      this.yearTableDetailDataLoading = true
      selectDeviceMaintenancePlanByPage({
        current: this.pagination1.current,
        size: this.pagination1.size,
      }).then(res => {
        if (res.code == 200) {
          this.yearTableDetailData = res.data.records
          this.pagination1.total = res.data.total
    // å¹´ä»½ä¸‹æ‹‰é€‰é¡¹ï¼šå·²æœ‰è®¡åˆ’年份 + å½“前年份
    loadYearOptions() {
      const currentYear = String(new Date().getFullYear())
      const finish = (years) => {
        if (years.indexOf(currentYear) === -1) {
          years.push(currentYear)
        }
        this.yearTableDetailDataLoading = false
      }).catch(err => {
        this.yearTableDetailDataLoading = false
        this.yearOptions = [...new Set(years)].sort((a, b) => b.localeCompare(a))
        this.planYear = currentYear
        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)
      }).catch(() => {
        finish([])
      })
    },
    // æ‰“开提交批准弹框
    tellApprove(maintenancePlanId) {
      this.getUserList()
      this.notificationDia = true
      this.maintenancePlanId = maintenancePlanId
    // åˆ‡æ¢å¹´ä»½
    handleYearChange() {
      this.pagination1.current = 1
      this.loadPlan()
    },
    // å…³é—­æäº¤æ‰¹å‡†å¼¹æ¡†
    closeNotificationDia() {
      this.notificationDia = false
      this.auditId = ''
    // æŸ¥è¯¢å¹´ä»½è®¡åˆ’(不存在自动创建并补全到点明细),随后刷新明细
    loadPlan() {
      getMaintenancePlanByYear({ planYear: this.planYear }).then(res => {
        if (res.code == 200) {
          this.planInfo = res.data || {}
        }
        this.getTableList()
      }).catch(() => {
        this.planInfo = {}
        this.tableData = []
        this.pagination1.total = 0
        this.tableLoading = false
      })
    },
    // æäº¤æ‰¹å‡†é€šçŸ¥
    notification() {
      if (!this.auditId) {
        this.$message.warning('请选择审核人')
    // æŸ¥è¯¢æ¡ä»¶å˜åŒ–后从第一页开始查
    handleQuery() {
      this.pagination1.current = 1
      this.getTableList()
    },
    // æ˜Žç»†-查询
    getTableList() {
      if (!this.planInfo.maintenancePlanId) {
        return
      }
      this.notificationLoading = true
      submitReviewMaintenancePlanStatus({
        auditId: this.auditId,
        maintenancePlanId: this.maintenancePlanId,
      this.tableLoading = true
      pageMaintenancePlanDetail({
        current: this.pagination1.current,
        size: this.pagination1.size,
        planId: this.planInfo.maintenancePlanId,
        deviceName: this.searchForm.deviceName,
        deviceNumber: this.searchForm.deviceNumber,
      }).then(res => {
        this.notificationLoading = false
        if (res.code == 200) {
          this.closeNotificationDia()
          this.getYearTableDetailData()
          this.tableData = res.data.records
          this.pagination1.total = res.data.total
        }
      }).catch(err => {
        this.notificationLoading = false
        this.tableLoading = false
      }).catch(() => {
        this.tableLoading = false
      })
    },
    // æ‰“开新增和编辑弹框
    handleForm(type, row) {
      this.operationType = type
      this.applicationForm = true
      this.form = {
        planYear: '',
        deviceMaintenancePlanDetails: [],
    // åˆ°ç‚¹éœ€ä¿å…»çš„行标红
    formatDateCell(row, column, cellValue) {
      return formatDateOnly(cellValue)
    },
    tableRowClassName({ row }) {
      return row.redFlag === 1 ? 'red-row' : ''
    },
    reset() {
      this.searchForm = {
        deviceName: '',
        deviceNumber: '',
      }
      this.deviceMaintenancePlanDetails = []
      if (row) {
        this.maintenancePlanId = row.maintenancePlanId
        getMaintenancePlanDetail({ maintenancePlanId: this.maintenancePlanId }).then(res => {
          if (res.code === 200) {
            this.form = res.data
            this.deviceMaintenancePlanDetails = this.form.deviceMaintenancePlanDetails
          }
        }).catch(error => {
          console.error(error)
        })
      }
      this.getEquipOptions()
    },
    // æ·»åŠ è®¾å¤‡
    addTableRow() {
      this.addEquipDia = true
      this.getEquipOptions()
    },
    handleSelectionChange(selection) {
      this.selectionRows = selection
    },
    // èµ‹å€¼ä»ªå™¨ç¼–号
    changeMachineName() {
      this.deviceMaintenancePlanDetails = []
      this.selectionRows.map(val => {
        this.deviceMaintenancePlanDetails.push({ deviceId: val.id, deviceName: val.label, deviceNumber: val.value, storagePoint: val.storagePoint })
      })
      this.addEquipDia = false
      this.rowDrop()
    },
    rowDrop() {
      const that = this
      const tbody = document.querySelector(
        '#templateParamTable .el-table__body-wrapper tbody'
      )
      if (!this.sortTable) {
        this.sortTable = Sortable.create(tbody, {
          animation: 200, //动画时长
          handle: ".el-table__row", //可拖拽区域class
          //拖拽中事件
          onMove: ({ dragged, related }) => {
            const oldRow = that.deviceMaintenancePlanDetails[dragged.rowIndex] //旧位置数据
            const newRow = that.deviceMaintenancePlanDetails[related.rowIndex] //被拖拽的新数据
          },
          //拖拽结束事件
          onEnd: evt => {
            const curRow = that.deviceMaintenancePlanDetails.splice(evt.oldIndex, 1)[0];
            that.deviceMaintenancePlanDetails.splice(evt.newIndex, 0, curRow);
          }
        })
      }
    },
    // åˆ é™¤è¡¨æ ¼è¡Œ
    deleteRow(index) {
      this.deviceMaintenancePlanDetails.splice(index, 1)
    },
    // æäº¤æ–°å¢žå’Œä¿®æ”¹
    submitForm() {
      this.form.deviceMaintenancePlanDetails = this.HaveJson(this.deviceMaintenancePlanDetails)
      this.submitFormLoading = true
      if (this.operationType === 'add') {
        addMaintenancePlan(this.form).then(res => {
          if (res.code == 200) {
            this.$message.success('新增成功')
            this.applicationForm = false
            this.getYearTableDetailData()
          }
          this.submitFormLoading = false
        }).catch(err => {
          this.submitFormLoading = false
        })
      } else {
        updateMaintenancePlan(this.form).then(res => {
          if (res.code == 200) {
            this.$message.success('修改成功')
            this.applicationForm = false
            this.getYearTableDetailData()
          }
          this.submitFormLoading = false
        }).catch(err => {
          this.submitFormLoading = false
        })
      }
    },
    // æäº¤å®¡æ ¸
    checkStatus(status) {
      const params = {
        status: status,
        maintenancePlanId: this.maintenancePlanId
      }
      addMaintenancePlan(params).then(res => {
        if (res.code == 200) {
          this.$message.success('审核成功')
          this.applicationForm = false
          this.getYearTableDetailData()
        }
        this.submitFormLoading = false
      }).catch(err => {
        this.submitFormLoading = false
      })
    },
    closeDialog() {
      this.applicationForm = false
      this.getYearTableDetailData()
      this.pagination1.current = 1
      this.getTableList()
    },
    // åˆ†é¡µ
    handleSizeChange1(val) {
      this.pagination1.size = val
      this.getYearTableDetailData()
      this.getTableList()
    },
    // åˆ†é¡µ
    handleCurrentChange1(val) {
      this.pagination1.current = val
      this.getYearTableDetailData()
      this.getTableList()
    },
    handleDownOne(id) {
      this.outLoading = true
      exportDeviceMaintenancePlan({ maintenancePlanId: id }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备维护保养记录.doc')
    // æ‰“开明细弹框
    handleForm(type, row) {
      this.operationType = type
      this.form = this.HaveJson(row)
      this.dialogVisible = true
      this.$nextTick(() => {
        if (this.$refs.modelForm) {
          this.$refs.modelForm.clearValidate()
        }
      })
    },
    // åˆ é™¤
    deleteFun(id) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
    // æäº¤è¡¨å•(只回传明细表字段)
    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
          })
        }
      })
    },
    resetForm() {
      this.dialogVisible = false
    },
    // æ˜Žç»†-删除
    deleteRow(row) {
      this.$confirm('此操作将永久删除该条明细, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteMaintenancePlan({ maintenancePlanId: id }).then(res => {
        deleteMaintenancePlanDetail({ maintenancePlanDetailId: row.maintenancePlanDetailId }).then(() => {
          this.$message.success('删除成功!');
          this.getYearTableDetailData();
          this.getTableList()
        });
      }).catch(() => {
        this.$message({
@@ -408,54 +374,144 @@
        });
      });
    },
    // èŽ·å–æ‰€æœ‰è®¾å¤‡
    getEquipOptions() {
      this.equipOptions = []
      deviceScopeSearch({ status: 0 }).then(res => {
        if (res.code === 200 && res.data) {
          this.equipOptions = res.data.map(m => {
            m.value = m.managementNumber
            m.label = m.deviceName
            return m
          })
    // æ‰“开提交审核弹框
    tellApprove() {
      this.getUserList()
      this.notificationDia = true
    },
    // å…³é—­æäº¤å®¡æ ¸å¼¹æ¡†
    closeNotificationDia() {
      this.notificationDia = false
      this.auditUserId = ''
    },
    // æäº¤å®¡æ ¸é€šçŸ¥
    notification() {
      if (!this.auditUserId) {
        this.$message.warning('请选择审核人')
        return
      }
      this.notificationLoading = true
      submitReviewMaintenancePlanStatus({
        auditId: this.auditUserId,
        maintenancePlanId: this.planInfo.maintenancePlanId,
      }).then(res => {
        this.notificationLoading = false
        if (res.code == 200) {
          this.closeNotificationDia()
          this.loadPlan()
        }
      }).catch(error => {
        console.error(error)
      }).catch(() => {
        this.notificationLoading = false
      })
    },
    // æ‰“开审核弹框
    handleApprove() {
      this.approvalRemark = ''
      this.approvalDialog = true
    },
    // æäº¤å®¡æ ¸ç»“æžœ
    handleApproval(status) {
      this.approvalLoading = true
      reviewMaintenancePlanStatus({
        maintenancePlanId: this.planInfo.maintenancePlanId,
        status: status,
        auditRemark: this.approvalRemark,
      }).then(res => {
        if (res.code == 200) {
          this.$message.success('审核成功!');
          this.approvalDialog = false
          this.loadPlan()
        }
        this.approvalLoading = false
      }).catch(() => {
        this.approvalLoading = false
      })
    },
    // å¯¼å‡º
    handleDownOne() {
      this.outLoading = true
      exportDeviceMaintenancePlan({ maintenancePlanId: this.planInfo.maintenancePlanId }).then(res => {
        this.outLoading = false
        saveBlobOrShowError(res, '设备保养计划表.docx', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // èŽ·å–è´Ÿè´£äººä¿¡æ¯æŽ¥å£
    getUserList() {
      selectUserCondition().then(res => {
        if (res.code == 200) {
          this.responsibleOptions = res.data
          this.responsibleOptions = (res.data || []).map(item => ({
            label: item.name,
            value: item.id,
          }))
        }
      });
    }
  },
  watch: {
    // ç›‘听点击el-tree的数据,进行数据刷新
    clickNodeVal(newVal) {
      if (newVal.value) {
        this.getYearTableDetailData();
      }
    },
  },
  computed: {
    ...mapGetters(["userId"]),
    // æ˜¯å¦å·²å®Œæˆå®¡æ ¸ï¼ˆé€šè¿‡/不通过)
    isAudited() {
      return this.planInfo.status === 0 || this.planInfo.status === 1;
    },
  },
}
</script>
<style scoped>
.title {
  position: relative;
  font-size: 16px;
  color: var(--lims-text);
  font-weight: 400;
  padding-left: 10px;
  margin-bottom: 10px;
}
.title::before {
  position: absolute;
  left: 0;
  top: 4px;
  content: '';
  width: 4px;
  height: 16px;
  background-color: var(--el-color-primary);
  border-radius: 2px;
}
.plan-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}
.plan-top-left {
  display: flex;
  align-items: center;
}
.title-search {
.plan-info-bar {
  display: flex;
  align-items: center;
  margin: 10px 0;
  flex-wrap: wrap;
  gap: 32px;
  background: #f5f7fa;
  border-radius: 4px;
  padding: 10px 16px;
  margin-top: 14px;
  font-size: 14px;
  color: #606266;
}
.search {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
:deep(.red-row td) {
  background: #ffcccc !important;
}
</style>
src/views/CNAS/resourceDemand/device/component/equipmentScrap.vue
@@ -15,20 +15,22 @@
          <!--          <el-table-column label="仪器名称" min-width="150" prop="unitName"></el-table-column>-->
          <!--          <el-table-column label="型号" min-width="100" prop="address"></el-table-column>-->
          <el-table-column label="配件" min-width="150" prop="parts"></el-table-column>
          <el-table-column label="编号" min-width="100" prop="number"></el-table-column>
          <el-table-column label="编号" min-width="100">
            <template v-slot="scope">{{ scope.row.number || clickNodeVal.managementNumber || '-' }}</template>
          </el-table-column>
          <el-table-column label="报废理由" min-width="150" prop="reasonsForScrap"></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="120">
            <template #default="scope">
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="primary"
                @click="handleForm(scope.row.scrappedId)">操作</el-button>
              <el-button size="small" link type="primary" @click="handleDownOne(scope.row.scrappedId)">导出</el-button>
              <el-button size="small" link type="danger"
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="danger"
                @click="deleteFun(scope.row.scrappedId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
        <el-pagination :current-page="pagination1.current" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1" background>
        </el-pagination>
@@ -46,6 +48,7 @@
  exportDeviceScrapped,
  delDeviceScrapped,
} from '@/api/cnas/resourceDemand/device.js'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "equipment-scrap",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -117,8 +120,9 @@
      this.outLoading = true
      exportDeviceScrapped({ scrappedId: id }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '仪器设备报废申请表.doc')
        saveBlobOrShowError(res, '仪器设备报废申请表.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // åˆ é™¤
src/views/CNAS/resourceDemand/device/component/equipmentVerificationPlan.vue
@@ -1,137 +1,101 @@
<template>
  <!--  è®¾å¤‡æ ¸æŸ¥è®¡åˆ’-->
  <div>
    <div>
      <div style="margin: 10px 0;display: flex;align-items: center;justify-content: space-between;">
        <div class="title">
          <span style="font-weight: bold">年度计划表</span>
    <div style="margin: 10px 0 14px;">
      <div class="plan-top">
        <div class="plan-top-left">
          <span class="title" style="margin-bottom: 0;">{{ planInfo.planName || (planYear + '年度设备核查计划') }}</span>
          <el-select v-model="planYear" size="small" style="width: 110px; margin-left: 16px;" @change="handleYearChange">
            <el-option v-for="y in yearOptions" :key="y" :label="y" :value="y"></el-option>
          </el-select>
        </div>
        <div style="display: flex;align-items: center;">
          <el-button size="small" type="primary" @click="getYearTableData">刷新</el-button>
          <el-button size="small" type="primary" @click="addYearPlan('add')">新增</el-button>
          <!--          <el-upload ref="upload" :action="action"-->
          <!--                     :before-upload="beforeUpload" :headers="uploadHeader" :on-error="onError"-->
          <!--                     :on-success="handleSuccessUp" :show-file-list="false" accept='.xls,.xlsx'>-->
          <!--            <el-button :loading="upLoading" size="small" type="primary">导入</el-button>-->
          <!--          </el-upload>-->
        <div>
          <el-button size="small" type="primary" @click="loadPlan">刷新</el-button>
          <el-button size="small" type="primary" :disabled="planInfo.ratifyStatus === 1"
            @click="tellApprove">批准通知</el-button>
          <el-button size="small" type="primary"
            :disabled="planInfo.ratifyStatus === 1 || userId != planInfo.ratifyUserId" @click="handleApprove">批准</el-button>
          <el-button size="small" type="primary" @click="downLoadPost">导出</el-button>
        </div>
      </div>
      <div class="plan-info-bar">
        <span>编制人:{{ planInfo.writeName || '—' }}</span>
        <span>编制日期:{{ planInfo.writeTimeStr || '—' }}</span>
        <span v-if="planInfo.ratifyStatus === 1">批准状态:<el-tag type="success">批准</el-tag></span>
        <span v-else-if="planInfo.ratifyStatus === 0">批准状态:<el-tag type="danger">不批准</el-tag></span>
        <span v-if="planInfo.ratifyRemark">批准内容:{{ planInfo.ratifyRemark }}</span>
        <span v-if="isRatified && planInfo.ratifyName">批准人:{{ planInfo.ratifyName }}</span>
        <span v-if="isRatified && planInfo.ratifyTimeStr">批准时间:{{ planInfo.ratifyTimeStr }}</span>
      </div>
    </div>
    <div class="search">
      <div>
        <el-table ref="yearTable" v-loading="yearTableDataLoading" :data="yearTableData"
                  height="calc(60vh - 16em)"
 border
                  highlight-current-row @current-change="currentChange">
          <!-- è¡¨æ ¼åˆ— -->
          <el-table-column align="center" header-align="center" label="序号" prop="prop" type="index"
            width="70"></el-table-column>
          <el-table-column label="年份" min-width="80" prop="planYear"></el-table-column>
          <el-table-column label="计划名称" min-width="180" prop="planName" show-overflow-tooltip></el-table-column>
          <el-table-column label="编制人" min-width="100" prop="writeName"></el-table-column>
          <el-table-column label="编制日期" min-width="160" prop="writeTime"></el-table-column>
          <el-table-column label="批准状态" min-width="100" prop="ratifyStatus">
            <template #default="scope">
              <el-tag v-if="scope.row.ratifyStatus === 1" type="success">批准</el-tag>
              <el-tag v-if="scope.row.ratifyStatus === 0" type="danger">不批准</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="批准内容" min-width="150" prop="ratifyRemark"></el-table-column>
          <el-table-column label="批准人" min-width="100" prop="ratifyName"></el-table-column>
          <el-table-column label="批准时间" min-width="150" prop="ratifyTime"></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="240">
            <template #default="scope">
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
                @click="addYearPlan('edit', scope.row)">编辑</el-button>
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
                @click="tellApprove(scope.row.planId)">批准通知</el-button>
              <el-button :disabled="scope.row.ratifyStatus === 1 || userId != scope.row.ratifyUserId" size="small"
                link type="primary" @click="handleApprove(scope.row.planId)">批准</el-button>
              <el-button size="small" link type="primary" @click="downLoadPost(scope.row.planId)">导出</el-button>
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="danger"
                @click="deleteFun(scope.row.planId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :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>
        <el-form :model="searchForm" ref="searchForm" size="small" :inline="true">
          <el-form-item label="设备编号" prop="deviceNumber">
            <el-input v-model="searchForm.deviceNumber" clearable size="small"
              @keyup.enter="handleQuery"></el-input>
          </el-form-item>
          <el-form-item label="设备名称" prop="deviceName">
            <el-input v-model="searchForm.deviceName" clearable size="small"
              @keyup.enter="handleQuery"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" size="small" @click="handleQuery">查询</el-button>
            <el-button size="small" @click="reset">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
    <div>
      <div class="title">
        <span style="font-weight: bold">年度计划明细表</span>
      </div>
      <div class="search">
        <div>
          <el-form :model="searchForm" ref="searchForm" size="small" :inline="true">
            <el-form-item label="设备编号" prop="deviceNumber">
              <el-input v-model="searchForm.deviceNumber" clearable size="small"
                        @keyup.enter="getYearTableDetailData(currentRow)"></el-input>
            </el-form-item>
            <el-form-item label="设备名称" prop="deviceName">
              <el-input v-model="searchForm.deviceName" clearable size="small"
                        @keyup.enter="getYearTableDetailData(currentRow)"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" size="small" @click="getYearTableDetailData(currentRow)">查询</el-button>
              <el-button size="small" @click="reset">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div>
          <el-button size="small" type="primary" @click="handleForm('add')">新增</el-button>
        </div>
      </div>
      <div>
        <el-table ref="yearTableDetailData" v-loading="yearTableDetailDataLoading" :data="yearTableDetailData"
 border
                  :height="'calc(100vh - 34em)'" 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" 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="150" prop="checkTime"></el-table-column>
          <el-table-column label="核查指标" min-width="150" prop="checkIndex"> </el-table-column>
          <el-table-column label="核查方法" min-width="150" prop="checkMethod"></el-table-column>
          <el-table-column label="结果如何判定" min-width="150" prop="howResults"></el-table-column>
          <el-table-column label="核查负责人" min-width="150" prop="checkChargerUser"></el-table-column>
          <el-table-column label="记录状态" min-width="100" prop="recordStatus">
            <template #default="scope">
              <el-tag type="" v-if="scope.row.recordStatus === 0" disable-transitions>未开始</el-tag>
              <el-tag type="warning" v-if="scope.row.recordStatus === 1" disable-transitions>待批准</el-tag>
              <el-tag type="success" v-if="scope.row.recordStatus === 2" disable-transitions>通过</el-tag>
              <el-tag type="danger" v-if="scope.row.recordStatus === 3" disable-transitions>不通过</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="对比状态" min-width="100" prop="recordContrastStatus">
            <template #default="scope">
              <el-tag type="" v-if="scope.row.recordContrastStatus === 0" disable-transitions>未开始</el-tag>
              <el-tag type="warning" v-if="scope.row.recordContrastStatus === 1" disable-transitions>待批准</el-tag>
              <el-tag type="success" v-if="scope.row.recordContrastStatus === 2" disable-transitions>通过</el-tag>
              <el-tag type="danger" v-if="scope.row.recordContrastStatus === 3" disable-transitions>不通过</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="备注" min-width="150" prop="remark"></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="260">
            <template #default="scope">
              <el-button size="small" link type="primary" @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="primary" @click="handleRecord(scope.row)">记录</el-button>
              <el-button size="small" link type="primary" @click="handleCheck(scope.row)">对比</el-button>
              <el-button size="small" link type="primary" @click="handleDown(scope.row)">导出</el-button>
              <el-button size="small" link type="danger"
                @click="deleteFun1(scope.row.planDetailsId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
      </div>
      <el-table ref="yearTableDetailData" v-loading="yearTableDetailDataLoading" :data="yearTableDetailData" border
        :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="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="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>
        <el-table-column label="核查负责人" min-width="120" prop="checkChargerUser"></el-table-column>
        <el-table-column label="记录状态" min-width="100" prop="recordStatus">
          <template #default="scope">
            <el-tag type="" v-if="scope.row.recordStatus === 0" disable-transitions>未开始</el-tag>
            <el-tag type="warning" v-if="scope.row.recordStatus === 1" disable-transitions>待批准</el-tag>
            <el-tag type="success" v-if="scope.row.recordStatus === 2" disable-transitions>通过</el-tag>
            <el-tag type="danger" v-if="scope.row.recordStatus === 3" disable-transitions>不通过</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="对比状态" min-width="100" prop="recordContrastStatus">
          <template #default="scope">
            <el-tag type="" v-if="scope.row.recordContrastStatus === 0" disable-transitions>未开始</el-tag>
            <el-tag type="warning" v-if="scope.row.recordContrastStatus === 1" disable-transitions>待批准</el-tag>
            <el-tag type="success" v-if="scope.row.recordContrastStatus === 2" disable-transitions>通过</el-tag>
            <el-tag type="danger" v-if="scope.row.recordContrastStatus === 3" disable-transitions>不通过</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="备注" min-width="130" prop="remark"></el-table-column>
        <!-- æ“ä½œæŒ‰é’® -->
        <el-table-column align="center" fixed="right" label="操作" min-width="260">
          <template #default="scope">
            <el-button size="small" link type="primary" :disabled="planInfo.ratifyStatus === 1"
              @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="primary" @click="handleRecord(scope.row)">记录</el-button>
            <el-button size="small" link type="primary" @click="handleCheck(scope.row)">对比</el-button>
            <el-button size="small" link type="primary" @click="handleDown(scope.row)">导出</el-button>
            <el-button size="small" link type="danger" :disabled="planInfo.ratifyStatus === 1"
              @click="deleteFun1(scope.row.planDetailsId)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination :current-page="pagination1.current" :page-size="pagination1.size"
        :page-sizes="[10, 20, 30, 50, 100]" :total="pagination1.total"
        layout="->,total, sizes, prev, pager, next, jumper" background
        @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
      </el-pagination>
    </div>
    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="dialogVisible" title="设备核查计划"
      width="80%" @close="resetForm">
@@ -175,7 +139,7 @@
          <el-form-item label="核查责任人:" prop="checkChargerUserId">
            <el-select v-model="form.checkChargerUserId" @change="setCheckChargerUser"
              :disabled="operationType === 'view'" placeholder="请选择" size="small" style="width: 100%">
              <el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"></el-option>
              <el-option v-for="item in chargerOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
            </el-select>
          </el-form-item>
        </el-col>
@@ -185,10 +149,10 @@
          </el-form-item>
        </el-col>
      </el-form>
      <template #footer><span  class="dialog-footer">
      <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>
        <el-button :loading="submitFormLoading" type="primary" @click="submitForm"
          v-if="operationType !== 'view'">ç¡® è®¤</el-button>
      </span></template>
    </el-dialog>
    <el-dialog v-model="approvalDialog" title="批准" width="30%" @close="approvalDialog = false">
@@ -196,17 +160,19 @@
        æ‰¹å‡†å¤‡æ³¨ï¼š
        <el-input v-model="ratifyRemark" type="textarea"></el-input>
      </span>
      <template #footer><span  class="dialog-footer">
      <template #footer><span class="dialog-footer">
        <el-button :loading="approvalLoading" @click="handleApproval(0)">不批准</el-button>
        <el-button :loading="approvalLoading" type="primary" @click="handleApproval(1)">批 å‡†</el-button>
      </span></template>
    </el-dialog>
    <el-dialog v-model="downloadDialog" title="导出" width="600px">
      <span>
        <el-button :loading="outLoading" type="primary" :disabled="!downRow.recordStatus" @click="controlDown">核查记录</el-button>
        <el-button :loading="outLoading" type="primary" :disabled="!downRow.recordContrastStatus" @click="processingDown">核查比对记录</el-button>
        <el-button :loading="outLoading" type="primary" :disabled="!downRow.recordStatus"
          @click="controlDown">核查记录</el-button>
        <el-button :loading="outLoading" type="primary" :disabled="!downRow.recordContrastStatus"
          @click="processingDown">核查比对记录</el-button>
      </span>
      <template #footer><span  class="dialog-footer">
      <template #footer><span class="dialog-footer">
        <el-button @click="downloadDialog = false">取 æ¶ˆ</el-button>
      </span></template>
    </el-dialog>
@@ -218,30 +184,26 @@
          </el-option>
        </el-select>
      </span>
      <template #footer><span  class="dialog-footer">
      <template #footer><span class="dialog-footer">
        <el-button :loading="notificationLoading" @click="closeNotificationDia">取 æ¶ˆ</el-button>
        <el-button :loading="notificationLoading" type="primary" @click="notification">提 äº¤</el-button>
      </span></template>
    </el-dialog>
    <equipment-check v-if="equipmentCheck" ref="equipmentCheck" @closeDialog="closeDialog"></equipment-check>
    <check-record v-if="checkRecord" ref="checkRecord" @closeDialog1="closeDialog1"></check-record>
    <add-verification-year-plan-dia v-if="addYearPlanDia" ref="addYearPlanDia"
      @closeDia="closeDia"></add-verification-year-plan-dia>
  </div>
</template>
<script>
import EquipmentCheck from "./equipmentCheck.vue";
import CheckRecord from "./checkRecord.vue";
import AddVerificationYearPlanDia from "./addVerificationYearPlanDia.vue";
import {
  pageDeviceExaminePlan,
  getExaminePlanByYear,
  submitRatifyDeviceExaminePlan,
  exportDeviceExaminePlanDetail,
  delDeviceExaminePlan,
  delDeviceExaminePlanDetail,
  pageDeviceExaminePlanDetail,
  addDeviceExaminePlanDetail,
  updateDeviceExaminePlanDetail,
  ratifyDeviceExaminePlan,
  exportReviewExamineRecordDetail,
@@ -250,10 +212,11 @@
import { selectUserCondition } from "@/api/performance/class";
import { mapGetters } from "@/utils/store-compat";
import draftSave from '@/mixins/draftSave'
import { formatListDate } from './dateFormat'
export default {
  name: "equipment-verification-plan",
  // import å¼•入的组件需要注入到对象中才能使用
  components: { AddVerificationYearPlanDia, CheckRecord, EquipmentCheck },
  components: { CheckRecord, EquipmentCheck },
  mixins: [draftSave],
  props: {
    clickNodeVal: {
@@ -266,19 +229,15 @@
  data() {
    // è¿™é‡Œå­˜æ”¾æ•°æ®
    return {
      upLoading: false,
      planYear: '',
      yearOptions: [],
      planInfo: {},
      dialogVisible: false,
      searchForm: {
        deviceName: '',
        deviceNumber: '',
      },
      yearTableData: [],
      yearTableDetailData: [],
      pagination: {
        size: 10,
        current: 1,
        total: 0,
      },
      pagination1: {
        size: 10,
        current: 1,
@@ -302,9 +261,7 @@
        deviceNumber: [{ required: true, message: '请填写设备编号', trigger: 'blur' }],
        checkMethod: [{ required: true, message: '请填写核查方法', trigger: 'blur' }],
      },
      yearTableDataLoading: false,
      yearTableDetailDataLoading: false,
      currentRow: {},
      approvalDialog: false,
      approvalLoading: false,
      submitFormLoading: false,
@@ -313,7 +270,6 @@
      userList: [],
      equipmentCheck: false,
      checkRecord: false,
      addYearPlanDia: false,
      downloadDialog: false,
      outLoading: false,
      downRow: {},
@@ -321,60 +277,168 @@
      notificationDia: false,
      notificationLoading: false,
      ratifyUserId: '',
      planId: ''
    }
  },
  mounted() {
    this.getYearTableData()
    this.loadYearOptions()
  },
  // æ–¹æ³•集合
  methods: {
    // æŸ¥è¯¢å¹´åº¦è®¡åˆ’表
    getYearTableData() {
      this.yearTableDataLoading = true
    // å¹´ä»½ä¸‹æ‹‰é€‰é¡¹ï¼šå·²æœ‰è®¡åˆ’年份 + å½“前年份
    loadYearOptions() {
      pageDeviceExaminePlan({
        current: 1,
        size: 99,
      }).then(res => {
        let years = []
        if (res.code == 200) {
          this.yearTableData = res.data.records
          this.pagination.total = res.data.total
          if (this.yearTableData.length > 0) {
            this.currentRow = this.yearTableData[0]
            this.$refs.yearTable.setCurrentRow(this.currentRow)
          }
          years = (res.data.records || []).map(r => r.planYear).filter(Boolean)
        }
        this.yearTableDataLoading = false
        const currentYear = String(new Date().getFullYear())
        if (years.indexOf(currentYear) === -1) {
          years.push(currentYear)
        }
        this.yearOptions = [...new Set(years)].sort((a, b) => b.localeCompare(a))
        this.planYear = currentYear
        this.loadPlan()
      })
    },
    // åˆ‡æ¢å¹´ä»½
    handleYearChange() {
      this.pagination1.current = 1
      this.loadPlan()
    },
    // æŸ¥è¯¢å¹´ä»½è®¡åˆ’(不存在自动创建并补全到点明细),随后刷新明细
    loadPlan() {
      getExaminePlanByYear({ planYear: this.planYear }).then(res => {
        if (res.code == 200) {
          this.planInfo = res.data || {}
        }
        this.getYearTableDetailData()
      }).catch(() => {
        this.planInfo = {}
        this.yearTableDetailData = []
        this.pagination1.total = 0
        this.yearTableDetailDataLoading = false
      })
    },
    // æŸ¥è¯¢æ¡ä»¶å˜åŒ–后从第一页开始查
    handleQuery() {
      this.pagination1.current = 1
      this.getYearTableDetailData()
    },
    // æ˜Žç»†-查询
    getYearTableDetailData() {
      if (!this.planInfo.planId) {
        return
      }
      this.yearTableDetailDataLoading = true
      pageDeviceExaminePlanDetail({
        current: this.pagination1.current,
        size: this.pagination1.size,
        planId: this.planInfo.planId,
        deviceName: this.searchForm.deviceName,
        deviceNumber: this.searchForm.deviceNumber,
      }).then(res => {
        if (res.code == 200) {
          this.yearTableDetailData = res.data.records
          this.pagination1.total = res.data.total
        }
        this.yearTableDetailDataLoading = false
      }).catch(err => {
        this.yearTableDataLoading = false
        this.yearTableDetailDataLoading = false
      })
    },
    // åˆ†é¡µ
    handleSizeChange(val) {
      this.pagination.size = val
      this.getYearTableData()
    // åˆ°ç‚¹éœ€æ ¸æŸ¥çš„行标红
    // æ ¸æŸ¥æ—¶é—´æŒ‰æœˆä»½æ˜¾ç¤ºï¼ˆå…¼å®¹åŽ†å²æ•°æ®ä¸­çš„å®Œæ•´æ—¥æœŸï¼‰
    formatCheckMonth(row, column, cellValue) {
      if (cellValue === null || cellValue === undefined || cellValue === '') {
        return cellValue
      }
      const str = String(cellValue).trim().replace(/[./]/g, '-')
      const matched = str.match(/^(\d{4})-(\d{1,2})/)
      if (matched) {
        return `${matched[1]}-${matched[2].padStart(2, '0')}`
      }
      const formatted = formatListDate(str)
      const fallback = String(formatted).match(/^(\d{4})-(\d{1,2})/)
      return fallback ? `${fallback[1]}-${fallback[2].padStart(2, '0')}` : cellValue
    },
    tableRowClassName({ row }) {
      return row.redFlag === 1 ? 'red-row' : ''
    },
    reset() {
      this.searchForm = {
        deviceName: '',
        deviceNumber: '',
      }
      this.pagination1.current = 1
      this.getYearTableDetailData()
    },
    // åˆ†é¡µ
    handleCurrentChange(val) {
      this.pagination.current = val
      this.getYearTableData()
    handleSizeChange1(val) {
      this.pagination1.size = val
      this.getYearTableDetailData()
    },
    // æ‰“开新增弹框
    addYearPlan(type, row) {
      this.addYearPlanDia = true
    // åˆ†é¡µ
    handleCurrentChange1(val) {
      this.pagination1.current = val
      this.getYearTableDetailData()
    },
    // æ‰“开明细弹框
    handleForm(type, row) {
      this.getUserList()
      this.operationType = type
      this.dialogVisible = true
      this.form.planId = this.planInfo.planId
      this.$nextTick(() => {
        this.$refs.addYearPlanDia.openDialog(type, row)
        this.form = this.HaveJson(row)
        if (this.operationType !== 'view') {
          this.draftRestore('equipmentVerificationPlan', 'form', this.form.planDetailsId, 'dialogVisible')
        }
      })
    },
    closeDia() {
      this.addYearPlanDia = false
      this.getYearTableData()
    // æäº¤è¡¨å•
    submitForm() {
      this.$refs.modelForm.validate(valid => {
        if (valid) {
          this.submitFormLoading = true
          updateDeviceExaminePlanDetail(this.form).then(res => {
            if (res.code == 200) {
              this.$message.success('修改成功')
              this.draftClear('equipmentVerificationPlan')
              this.dialogVisible = false
              this.getYearTableDetailData()
            }
            this.submitFormLoading = false
          }).catch(err => {
            this.submitFormLoading = false
          })
        }
      })
    },
    // æ˜Žç»†-删除
    deleteFun1(id) {
      this.$confirm('此操作将永久删除该条明细, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delDeviceExaminePlanDetail({ planDetailsId: id }).then(res => {
          this.$message.success('删除成功!');
          this.getYearTableDetailData()
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    // æ‰“开提交批准弹框
    tellApprove(planId) {
    tellApprove() {
      this.getUserList1()
      this.notificationDia = true
      this.planId = planId
    },
    // å…³é—­æäº¤æ‰¹å‡†å¼¹æ¡†
    closeNotificationDia() {
@@ -390,169 +454,23 @@
      this.notificationLoading = true
      submitRatifyDeviceExaminePlan({
        ratifyUserId: this.ratifyUserId,
        planId: this.planId,
        planId: this.planInfo.planId,
      }).then(res => {
        this.notificationLoading = false
        if (res.code == 200) {
          this.closeNotificationDia()
          this.getYearTableData()
          this.loadPlan()
        }
      }).catch(err => {
        this.notificationLoading = false
      })
    },
    // å¹´åº¦è®¡åˆ’表-批准
    handleApprove(id) {
      this.currentRowId = id
    // æ‰¹å‡†
    handleApprove() {
      this.currentRowId = this.planInfo.planId
      this.approvalDialog = true
    },
    // å¹´åº¦è®¡åˆ’表-导出
    downLoadPost(planId) {
      exportDeviceExaminePlanDetail({ planId }).then(res => {
        const blob = new Blob([res], { type: 'application/msword' });
        this.$download.saveAs(blob, '仪器设备期间核查计划表.docx')
      })
    },
    // å¹´åº¦è®¡åˆ’表-删除
    deleteFun(id) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delDeviceExaminePlan({ planId: id }).then(res => {
          this.$message.success('删除成功!');
          this.getYearTableData();
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    // å¹´åº¦è®¡åˆ’详情表-删除
    deleteFun1(id) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delDeviceExaminePlanDetail({ planDetailsId: id }).then(res => {
          this.$message.success('删除成功!');
          this.getYearTableDetailData(this.currentRow)
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    currentChange(row) {
      this.currentRow = row
      this.getYearTableDetailData(this.currentRow)
    },
    getYearTableDetailData(row) {
      this.yearTableDetailDataLoading = true
      pageDeviceExaminePlanDetail({
        current: this.pagination1.current,
        size: this.pagination1.size,
        planId: row.planId,
        deviceName: this.searchForm.deviceName,
        deviceNumber: this.searchForm.deviceNumber,
      }).then(res => {
        if (res.code == 200) {
          this.yearTableDetailData = res.data.records
          this.pagination1.total = res.data.total
        }
        this.yearTableDetailDataLoading = false
      }).catch(err => {
        this.yearTableDetailDataLoading = false
      })
    },
    reset() {
      this.searchForm = {
        deviceName: '',
        deviceNumber: '',
      }
      this.getYearTableDetailData(this.currentRow)
    },
    // åˆ†é¡µ
    handleSizeChange1(val) {
      this.pagination1.size = val
      this.getYearTableDetailData(this.currentRow)
    },
    // åˆ†é¡µ
    handleCurrentChange1(val) {
      this.pagination1.current = val
      this.getYearTableDetailData(this.currentRow)
    },
    // æ‰“开弹框
    handleForm(type, row) {
      this.getUserList()
      this.operationType = type
      this.dialogVisible = true
      this.form.planId = this.currentRow.planId
      if (this.operationType !== 'add') {
        this.$nextTick(() => {
          this.form = this.HaveJson(row)
          if (this.operationType !== 'view') {
            this.draftRestore('equipmentVerificationPlan', 'form', this.form.planDetailsId, 'dialogVisible')
          }
        })
      } else {
        this.form = {
          deviceNumber: '',
          deviceName: '',
          checkTime: '',
          checkIndex: '',
          checkMethod: '',
          howResults: '',
          checkChargerUserId: '',
          checkChargerUser: '',
          remark: '',
          planId: this.currentRow.planId,
          planDetailsId: '',
        }
        this.draftRestore('equipmentVerificationPlan', 'form', this.form.planId, 'dialogVisible')
      }
    },
    // æäº¤è¡¨å•
    submitForm() {
      this.$refs.modelForm.validate(valid => {
        if (valid) {
          if (this.operationType === 'add') {
            this.submitFormLoading = true
            addDeviceExaminePlanDetail(this.form).then(res => {
              if (res.code == 200) {
                this.$message.success('新增成功')
                this.draftClear('equipmentVerificationPlan')
                this.dialogVisible = false
                this.getYearTableData()
              }
              this.submitFormLoading = false
            }).catch(err => {
              this.submitFormLoading = false
            })
          } else {
            this.submitFormLoading = true
            updateDeviceExaminePlanDetail(this.form).then(res => {
              if (res.code == 200) {
                this.$message.success('新增成功')
                this.draftClear('equipmentVerificationPlan')
                this.dialogVisible = false
                this.getYearTableData()
              }
              this.submitFormLoading = false
            }).catch(err => {
              this.submitFormLoading = false
            })
          }
        }
      })
    },
    // æäº¤æ‰¹å‡†
    // æäº¤æ‰¹å‡†ç»“æžœ
    handleApproval(status) {
      const personTrainingUpdateDto = {
        planId: this.currentRowId,
@@ -564,12 +482,18 @@
        if (res.code === 200) {
          this.$message.success('提交成功!');
          this.approvalDialog = false
          this.getYearTableData();
          this.loadPlan()
        }
        this.approvalLoading = false
      }).catch(() => {
        this.approvalLoading = false
      })
    },
    // å¯¼å‡ºå¹´åº¦è®¡åˆ’表
    downLoadPost() {
      exportDeviceExaminePlanDetail({ planId: this.planInfo.planId }).then(res => {
        this.saveDocx(res, '仪器设备期间核查计划表.docx')
      }).catch(() => { })
    },
    resetForm() {
      this.draftStop('equipmentVerificationPlan')
@@ -586,7 +510,7 @@
    // å…³é—­å¯¹æ¯”弹框
    closeDialog() {
      this.equipmentCheck = false
      this.getYearTableDetailData(this.currentRow)
      this.getYearTableDetailData()
    },
    // æ‰“开记录弹框
    handleRecord(row) {
@@ -598,7 +522,7 @@
    // å…³é—­è®°å½•弹框
    closeDialog1() {
      this.checkRecord = false
      this.getYearTableDetailData(this.currentRow)
      this.getYearTableDetailData()
    },
    // æ‰“开导出弹框
    handleDown(row) {
@@ -613,7 +537,7 @@
        const text = (reader.result || '').trim();
        if (text.startsWith('{') || text.startsWith('[')) {
          let msg = '导出失败';
          try { msg = JSON.parse(text).msg || msg; } catch (e) {}
          try { msg = JSON.parse(text).msg || msg; } catch (e) { }
          this.$message.error(msg);
        } else {
          this.$download.saveAs(new Blob([res], { type: 'application/msword' }), filename);
@@ -643,30 +567,6 @@
        this.outLoading = false
      })
    },
    // å¯¼å…¥æµç¨‹
    beforeUpload(file) {
      if (file.size > 1024 * 1024 * 10) {
        this.$message.error('上传文件不超过10M');
        this.$refs.upload.clearFiles()
        return false;
      } else {
        this.upLoading = true;
        return true;
      }
    },
    onError(err, file, fileList) {
      this.$message.error('上传失败')
      this.$refs.upload.clearFiles()
    },
    handleSuccessUp(response) {
      this.upLoading = false;
      if (response.code == 200) {
        this.$message.success('上传成功');
        this.getYearTableData()
      } else {
        this.$message.error(response.message)
      }
    },
    getUserList() {
      selectUserCondition().then(res => {
        this.userList = res.data
@@ -687,22 +587,32 @@
      });
    }
  },
  // ç”¨äºŽä¸Šä¼ æ–‡ä»¶çš„信息
  computed: {
    action() {
      return this.javaApi + '/deviceExaminePlan/importDeviceExaminePlan'
    },
    ...mapGetters(["userId"]),
    // æ˜¯å¦å·²å®Œæˆå®¡æ‰¹ï¼ˆæ‰¹å‡†/不批准)
    isRatified() {
      return this.planInfo.ratifyStatus === 0 || this.planInfo.ratifyStatus === 1;
    },
    // è´£ä»»äººä¸‹æ‹‰ï¼šå·²ä¿å­˜çš„责任人不在候选列表时补一条,避免回显成用户ID
    chargerOptions() {
      const list = this.userList || []
      const id = this.form.checkChargerUserId
      if (id && !list.some(item => String(item.id) === String(id))) {
        return [...list, { id, name: this.form.checkChargerUser || String(id) }]
      }
      return list
    },
  },
}
</script>
<style scoped>
.search {
  height: 46px;
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
.title {
  position: relative;
  font-size: 16px;
@@ -722,4 +632,33 @@
  background-color: var(--el-color-primary);
  border-radius: 2px;
}
.plan-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}
.plan-top-left {
  display: flex;
  align-items: center;
}
.plan-info-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 32px;
  background: #f5f7fa;
  border-radius: 4px;
  padding: 10px 16px;
  margin-top: 14px;
  font-size: 14px;
  color: #606266;
}
:deep(.red-row td) {
  background: #ffcccc !important;
}
</style>
src/views/CNAS/resourceDemand/device/component/failureForm.vue
@@ -7,7 +7,7 @@
        <el-step title="申请部门负责人意见" @click="setStep(1)"></el-step>
        <el-step title="维修记录" @click="setStep(2)"></el-step>
      </el-steps>
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px">
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px" :disabled="!canOperate">
        <el-col v-if="showStep === 0" :span="12">
          <el-form-item label="安装地点:" prop="location">
            <el-input v-model="form.location" :disabled="currentStep !== 0" clearable size="small"></el-input>
@@ -59,7 +59,7 @@
      </el-form>
      <template #footer><span  class="dialog-footer">
        <el-button @click="resetForm">取 æ¶ˆ</el-button>
        <el-button v-if="currentStep !== 3" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
        <el-button v-if="currentStep !== 3 && canOperate" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
          è®¤</el-button>
      </span></template>
    </el-dialog>
@@ -72,6 +72,7 @@
  addDeviceBreakdownMaintenance,
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { mapGetters } from "@/utils/store-compat";
export default {
  name: "failure-form",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -81,6 +82,7 @@
    return {
      dialogVisible: false,
      submitFormLoading: false,
      canOperate: true,
      form: {
        location: '',
        damageOrMalfunction: '',
@@ -111,6 +113,7 @@
    // æ‰“开弹框
    openDialog(id, deviceId) {
      this.dialogVisible = true
      this.canOperate = true
      this.form.maintenanceId = id
      this.form.deviceId = deviceId
      this.getUserList()
@@ -138,10 +141,23 @@
            this.currentStep = 3
            this.showStep = 2
          }
          this.applyPermission()
        }
      }).catch(error => {
        console.error(error)
      })
    },
    // éžå½“前环节责任人只允许查看
    applyPermission() {
      if (this.form.isFinish === 1) {
        this.canOperate = false
        return
      }
      const responsible = this.currentStep === 1 ? this.form.departmentHeadUser : this.form.applicantUser
      this.canOperate = !responsible || responsible === this.nickName
      if (!this.canOperate) {
        this.$message.warning('当前环节责任人为:' + responsible + ',您只能查看')
      }
    },
    setStep(step) {
      this.showStep = step
@@ -151,6 +167,7 @@
      this.form.flowType = this.currentStep
      this.$refs.modelForm.validate((valid) => {
        if (valid) {
          this.submitFormLoading = true
          addDeviceBreakdownMaintenance(this.form).then(res => {
            if (res.code == 200) {
              this.$message.success('新增成功')
@@ -174,6 +191,9 @@
      })
    },
  },
  computed: {
    ...mapGetters(["nickName"]),
  },
}
</script>
src/views/CNAS/resourceDemand/device/component/fault.vue
@@ -31,7 +31,8 @@
          <el-table-column prop="managementNumber" label="统一编号" min-width="150"></el-table-column>
          <el-table-column prop="faultSituation" label="故障情况" min-width="130"></el-table-column>
          <el-table-column prop="submitPerson" label="提交人" min-width="130"></el-table-column>
          <el-table-column prop="createTime" label="提交日期" min-width="150"></el-table-column>
          <el-table-column prop="createTime" label="提交日期" min-width="150"
            :formatter="formatDateCell"></el-table-column>
          <el-table-column prop="currentState" label="当前状态" min-width="130"></el-table-column>
          <el-table-column prop="currentResponsible" label="当前责任人" width="180"></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
@@ -279,6 +280,7 @@
<script>
import { dateFormat } from '@/utils/date'
import { mapGetters } from "@/utils/store-compat";
import { formatListDate } from './dateFormat'
export default {
  props: {
    clickNodeVal: {
@@ -318,6 +320,9 @@
    this.getTableList(this.clickNodeVal.value)
  },
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    //要求修复日期:禁用在故障日期前的日期
    disabledDate(time) {
      let selectDate = this.form.faultDate
src/views/CNAS/resourceDemand/device/component/files.vue
@@ -15,12 +15,16 @@
      <el-row :gutter="20">
        <el-col :span="6">
          <!-- åŠ æ—¶é—´æˆ³é¿å…æµè§ˆå™¨ç¼“å­˜é—®é¢˜ -->
          <el-image :src="`${javaApi}/img/${Mdata.imageUpload}`" fit="fill" :key="'personalPicture' + timeStamp"
          <el-image v-if="Mdata.imageUpload" :src="`${javaApi}/img/${Mdata.imageUpload}`" fit="fill" :key="'personalPicture' + timeStamp"
            style="width: 200px;height: 300px;border: 1px solid #000;border-radius: 10px;margin-left: 30px;margin-top: 20px;">
            <template #error><div  class="image-slot">
              <lims-icon name="el-icon-picture-outline" style="font-size: 40px;"></lims-icon>
            </div></template>
          </el-image>
          <div v-else class="image-slot"
            style="width: 198px;height: 298px;border: 1px solid #000;border-radius: 10px;margin-left: 30px;margin-top: 20px;display: flex;align-items: center;justify-content: center;">
            <lims-icon name="el-icon-picture-outline" style="font-size: 40px;"></lims-icon>
          </div>
        </el-col>
        <el-col :span="8">
          <div class="form-item">
@@ -52,10 +56,6 @@
          </div>
          <div class="form-item">
            <label>出厂日期</label>
            <p>{{ formaterDateTime(Mdata.acquisitionDate) }}</p>
          </div>
          <div class="form-item">
            <label>校准有效期</label>
            <p>{{ formaterDateTime(Mdata.activationDate) }}</p>
          </div>
@@ -65,19 +65,11 @@
          </div>
          <div class="form-item">
            <label>报废时间</label>
            <p>{{ handleData() }}</p>
          </div>
          <div class="form-item">
            <label>准确度量值</label>
            <el-tooltip class="item" :content="Mdata.technicalIndicators">
              <span class="text-ellipsis">{{ Mdata.technicalIndicators }}</span>
            </el-tooltip>
            <!-- <p>{{ Mdata.technicalIndicators }}</p> -->
          </div>
          <div class="form-item">
            <label>维修记录</label>
            <p>{{ handleData() }}</p>
          </div>
          <div class="form-item">
            <label>被授权人</label>
@@ -136,15 +128,11 @@
          </div>
          <div class="form-item">
            <label>采购费用(元)</label>
            <p>{{ Mdata.unitPrice }}</p>
            <p>{{ formatPurchasePrice(Mdata.unitPrice) }}</p>
          </div>
          <div class="form-item">
            <label>设备负责人</label>
            <p>{{ Mdata.equipmentManagerName }}</p>
          </div>
          <div class="form-item">
            <label>验收记录</label>
            <p>{{ handleData() }}</p>
          </div>
          <div class="form-item">
            <label>核准证书</label>
@@ -166,7 +154,7 @@
        <el-table-column prop="quantity" label="份数" min-width="80" />
        <el-table-column prop="pageCount" label="页码" min-width="80" />
        <el-table-column prop="provider" label="提供者" min-width="150" />
        <el-table-column prop="provideDate" label="归档日期" min-width="170" />
        <el-table-column prop="provideDate" label="归档日期" min-width="170" :formatter="formatDateCell" />
        <el-table-column prop="comments" label="备注" min-width="150" />
        <el-table-column fixed="right" label="操作" min-width="180" align="center">
          <template #default="scope">
@@ -185,7 +173,7 @@
      <el-row>
        <el-col :span="7" style="padding-right: 20px;">
          <!-- å›¾ç‰‡ -->
          <el-image class="img" style="width:100%;height: 320px;"
          <el-image v-if="editData.imageUpload" class="img" style="width:100%;height: 320px;"
            :src="javaApi + '/img/' + editData.imageUpload">
            <template #error><div  class="image-error" style="width: calc(100% - 2px);
            height: 318px;
@@ -197,11 +185,15 @@
              <lims-icon name="el-icon-picture-outline" style="font-size:60px;color:var(--lims-text-2);"></lims-icon>
            </div></template>
          </el-image>
          <div v-else class="image-error"
            style="width: calc(100% - 2px);height: 320px;border-radius: 16px;display: flex;align-items: center;justify-content: center;border: 1px solid var(--lims-divider);">
            <lims-icon name="el-icon-picture-outline" style="font-size:60px;color:var(--lims-text-2);"></lims-icon>
          </div>
          <!-- å›¾ç‰‡ä¸Šä¼  -->
          <div style="margin-top: 12px;text-align: center;">
            <div v-show="editData.imageName" class="picName">{{ editData.imageName }}</div>
            <el-upload :action="action" :on-success="handleSuccessUpImg2" :show-file-list="false"
              accept='image/jpg,image/jpeg,image/png' :headers="uploadHeader" :on-change="beforeUpload"
              accept='image/jpg,image/jpeg,image/png' :headers="uploadHeader" :before-upload="beforeUpload"
              :on-error="onError" ref='upload' class="avatar-uploader">
              <img v-if="editData.imageUpload" :src="javaApi + '/img/' + editData.imageUpload" class="avatar">
              <lims-icon name="el-icon-plus" v-else class="avatar-uploader-icon"></lims-icon>
@@ -276,7 +268,7 @@
              placeholder="请选择" size="small" style="width:100%;" :collapse-tags="true" separator="," filterable
              clearable></el-cascader>
          </el-form-item>
          <el-form-item label="设备类型:">
          <el-form-item label="设备/计量器具:">
            <el-select v-model="editData.largeCategory" placeholder="请选择" size="small" style="width:100%">
              <el-option v-for="item in equipmentList" :key="item.value" :label="item.label" :value="item.value">
              </el-option>
@@ -319,17 +311,17 @@
        <div class="cycle-row">
          <span class="cycle-title">校准信息</span>
          <el-form-item label="最近校准日期:" class="cycle-item">
            <el-date-picker style="width:100%" v-model="editData.lastCalibrationDate" format="YYYY-MM-DD"
              value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="选择日期">
            <el-date-picker style="width:100%" v-model="editData.lastCalibrationDate" @change="calcNextDate(editData)"
              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="选择日期">
            </el-date-picker>
          </el-form-item>
          <el-form-item label="下次校准日期:" class="cycle-item">
            <el-date-picker style="width:100%" v-model="editData.nextCalibrationDate" format="YYYY-MM-DD"
              value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="选择日期">
            <el-date-picker :disabled="true" style="width:100%" v-model="editData.nextCalibrationDate"
              format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" type="date" size="small" placeholder="选择日期">
            </el-date-picker>
          </el-form-item>
          <el-form-item label="校准周期(月):" prop="calibrationDate" class="cycle-item">
            <el-input v-model="editData.calibrationDate" size="small"></el-input>
            <el-input v-model="editData.calibrationDate" size="small" @change="calcNextDate(editData)"></el-input>
          </el-form-item>
        </div>
        <div class="cycle-row">
@@ -504,6 +496,8 @@
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { selectQualifiedSupplierManagementPage } from '@/api/cnas/externalService/supplierManage/supplierManage'
import { formatListDate } from './dateFormat'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  props: {
    clickNodeVal: {
@@ -544,7 +538,6 @@
      // },
      fileList: [], // æ·»åŠ é™„ä»¶ä¸Šä¼ æ–‡ä»¶åˆ—è¡¨
      timeStamp: '', // ç»™å›¾ç‰‡æ·»åŠ key,在每次加载页面的时候新建时间戳
      equipmentManager: [],
      formLabelWidth: '100px',
      dialogVisible1: false,
      recordNumber: '',
@@ -555,7 +548,7 @@
      num: 1,
      //添加附件数据收集
      addFile: {
        documentType: '', // ç»´æŠ¤ç±»åž‹
        documentType: 0, // ç»´æŠ¤ç±»åž‹
        provideDate: null, // å½’档日期
        name: '', // æ¡£æ¡ˆåç§°
        number: '', // åº“号/资产编号
@@ -577,7 +570,11 @@
      responsiblePersonList: [],
      inspectorList: [],
      options: [],
      equipmentList: [],
      // è®¾å¤‡ç±»åž‹ï¼šä¸Žå·¦ä¾§æ ‘“设备/计量器具”分类保持一致
      equipmentList: [
        { label: '设备', value: '设备' },
        { label: '计量器具', value: '计量器具' }
      ],
      deviceStatusList: [],
      props: { multiple: true, emitPath: false, value: 'id', label: 'name' },
      // æ”¶é›†è®¾å¤‡æ¡£æ¡ˆæ•°æ®
@@ -612,6 +609,9 @@
    this.obtainQualifiedSupplierList()
  },
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    // æ‹‰å–合格供应商列表(校准服务机构下拉选项)
    obtainQualifiedSupplierList() {
      selectQualifiedSupplierManagementPage({ current: 1, size: 999 }).then(res => {
@@ -662,12 +662,14 @@
    },
    //附件和相关文档事件
    handleAttachmentClick(row) {
      console.log(row)
      if (row.fileName) {
        this.$download.saveAs(row.fileName)
      } else {
      if (!row.systemFileName) {
        this.$message.warning('未上传文件!')
        return
      }
      // å›¾ç‰‡å­˜ /img/,其他文档存 /word/
      const isImage = /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(row.systemFileName)
      const url = this.javaApi + (isImage ? '/img/' : '/word/') + row.systemFileName
      this.$download.saveAs(url, row.fileName || row.systemFileName)
    },
    handleViewClick(row) {
      this.isAddFileUpdate = true
@@ -701,11 +703,23 @@
      })
    },
    saveRecord() {
      if (!this.addFile.name) {
        this.$message.warning('请输入档案名称')
        return
      }
      if (this.addFile.documentType !== 0 && this.addFile.documentType !== '0' &&
        this.addFile.documentType !== 1 && this.addFile.documentType !== '1') {
        this.$message.warning('请选择维护类型')
        return
      }
      //转换数据
      this.addFile.deviceId = this.clickNodeVal.value
      // æ–°ä¸Šä¼ æ—¶ systemFileName æ˜¯ {name: åŽŸå§‹æ–‡ä»¶å, url: å­˜å‚¨æ–‡ä»¶å};编辑旧记录时已是字符串
      let obj = this.addFile.systemFileName
      this.addFile.systemFileName = obj.name
      this.addFile.fileName = obj.url
      if (obj && typeof obj === 'object') {
        this.addFile.systemFileName = obj.url
        this.addFile.fileName = obj.name
      }
      // æ›´æ–°
      if (this.isAddFileUpdate) {
@@ -737,11 +751,17 @@
      }
    },
    handleRemove(file, fileList) {
      this.deleteFile(this.addFile.systemFileName)
      const obj = this.addFile.systemFileName
      const fileName = obj && typeof obj === 'object' ? obj.url : obj
      if (fileName) this.deleteFile(fileName)
      this.addFile.systemFileName = ''
      this.addFile.fileName = ''
    },
    deleteFile(fileName) {
      deleteCNASFile({ fileName }).then(res => {
        this.$message.success('删除成功!')
        if (res.code == 200) {
          this.$message.success('删除成功!')
        }
      })
    },
    handleExceed(files, fileList) {
@@ -784,7 +804,9 @@
        // å°†åˆ†ç±»åˆ—表的信息存起来
        if (res.code == 200) {
          this.Mdata = res.data;
          this.Mdata.insProductIds = this.Mdata.insProductIds.split(',')
          this.Mdata.insProductIds = this.Mdata.insProductIds
              ? String(this.Mdata.insProductIds).split(',')
              : []
          this.Mdata.authorizedPerson = this.normalizeAuthorizedPerson(this.Mdata.authorizedPerson)
        }
      });
@@ -802,6 +824,11 @@
    //打开修订档案弹框
    openEditForm() {
      this.editData = JSON.parse(JSON.stringify(this.Mdata))
      // è®¾å¤‡ç±»åž‹ä¸ºç©ºæ—¶ï¼Œé»˜è®¤å–左侧树当前所在分类
      const treeCategory = this.clickNodeVal && this.clickNodeVal.parent ? this.clickNodeVal.parent.label : ''
      if (!this.editData.largeCategory && (treeCategory === '设备' || treeCategory === '计量器具')) {
        this.editData.largeCategory = treeCategory
      }
      this.$nextTick(() => {
        this.dialogVisible = true
      })
@@ -832,55 +859,39 @@
    },
    //修订档案
    submitForm() {
      let flag = true
      this.$refs['rules1'].validate((valid) => {
        if (!valid) {
          flag = false;
          return false;
      // validate() è¿”回 Promise,统一等四个表单全部校验完再判断
      const formRefs = ['rules1', 'rules2', 'ruleForm', 'cycleForm']
      Promise.all(formRefs.map(ref => this.$refs[ref].validate().catch(() => false))).then(results => {
        if (results.some(valid => !valid)) {
          return
        }
      });
      this.$refs['rules2'].validate((valid) => {
        if (!valid) {
          flag = false;
          return false;
        }
      });
      this.$refs['ruleForm'].validate((valid) => {
        if (!valid) {
          flag = false;
          return false;
        }
      });
      this.$refs['cycleForm'].validate((valid) => {
        if (!valid) {
          flag = false;
          return false;
        }
      });
      if (!flag) {
        return;
      }
      delete this.editData.createTime
      delete this.editData.updateTime
      delete this.editData.createUser
      delete this.editData.updateUser
      delete this.editData.orderBy
      const formData = this.HaveJson(this.editData)
      formData.userAllow = this.equipmentManager.toString();
      formData.insProductIds = Array.isArray(formData.insProductIds) ? formData.insProductIds.join(',') : '';
      formData.authorizedPerson = Array.isArray(formData.authorizedPerson) && formData.authorizedPerson.length
        ? JSON.stringify(formData.authorizedPerson)
        : ''
      this.upLoad = true;
      upDeviceParameter(formData).then(res => {
        this.$message.success('修改成功')
        this.upLoad = false
        this.getList(this.clickNodeVal.value)
        this.dialogVisible = false
      }).catch(e => {
        this.$message.error('修改失败')
        this.dialogVisible = false
        this.upLoad = false
        delete this.editData.createTime
        delete this.editData.updateTime
        delete this.editData.createUser
        delete this.editData.updateUser
        delete this.editData.orderBy
        const formData = this.HaveJson(this.editData)
        formData.insProductIds = Array.isArray(formData.insProductIds) ? formData.insProductIds.join(',') : '';
        formData.authorizedPerson = Array.isArray(formData.authorizedPerson) && formData.authorizedPerson.length
          ? JSON.stringify(formData.authorizedPerson)
          : ''
        this.upLoad = true;
        upDeviceParameter(formData).then(res => {
          this.upLoad = false
          if (res.code == 200) {
            this.$message.success('修改成功')
            this.getList(this.clickNodeVal.value)
            // ç±»åž‹å¯èƒ½å˜æ›´ï¼Œåˆ·æ–°å·¦ä¾§æ ‘让设备归到新的分类下
            this.$emit('refresh-tree')
            this.dialogVisible = false
          } else {
            this.$message.error(res.message || res.msg || '修改失败')
          }
        }).catch(e => {
          // å¤±è´¥ä¿ç•™å¼¹çª—,避免已编辑内容丢失
          this.$message.error('修改失败')
          this.upLoad = false
        })
      })
    },
    // å¯¼å‡º
@@ -888,9 +899,18 @@
      this.outLoading = true
      exportDeviceFile({ deviceId: this.clickNodeVal.value }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备档案卡.doc')
        saveBlobOrShowError(res, '设备档案卡.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // ä¿®è®¢å¼¹çª—按万元录入,档案详情按元展示
    formatPurchasePrice(val) {
      if (val === null || val === undefined || val === '') {
        return '-'
      }
      const num = Number(val)
      return isNaN(num) ? val : num * 10000
    },
    handleSuccessUpImg2(response) {
      if (response.code == 200) {
@@ -960,10 +980,6 @@
            a.value = parseInt(a.value)
          }
        })
      });
      // è®¾å¤‡åˆ†ç±»
      this.getDicts("device_type").then((response) => {
        this.equipmentList = this.dictToValue(response.data);
      });
    },
  },
src/views/CNAS/resourceDemand/device/component/inspectionForm.vue
@@ -55,7 +55,7 @@
        </el-col>
      </el-row>
      <div>
        <el-button v-if="operationType === 'add'" size="small" type="primary" @click="addTableRow">添加</el-button>
        <el-button v-if="operationType !== 'check'" size="small" type="primary" @click="addTableRow">添加</el-button>
      </div>
      <div style="text-align: center">测试数据记录</div>
      <div style="margin: 10px 0">
@@ -220,7 +220,7 @@
      } else {
        updateDeviceInspectionRecord(this.form).then(res => {
          if (res.code == 200) {
            this.$message.success('新增成功')
            this.$message.success('修改成功')
            this.resetForm()
          }
          this.submitFormLoading = false
@@ -234,6 +234,7 @@
        inspectionRecordId: this.form.inspectionRecordId,
        status: status,
      }
      this.submitFormLoading = true
      reviewDeviceInspectionRecord(params).then(res => {
        if (res.code == 200) {
          this.$message.success('审核成功')
src/views/CNAS/resourceDemand/device/component/inspectionOfEquipment.vue
@@ -21,7 +21,8 @@
          <el-table-column label="复核状态" min-width="180" prop="status">
            <template #default="scope">
              <el-tag v-if="scope.row.status === 1" type="success">通 è¿‡</el-tag>
              <el-tag v-if="scope.row.status === 0" type="danger">不通过</el-tag>
              <el-tag v-else-if="scope.row.status === 0" type="danger">不通过</el-tag>
              <el-tag v-else type="info">待审核</el-tag>
            </template>
          </el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
@@ -37,7 +38,7 @@
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
        <el-pagination :current-page="pagination1.current" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
@@ -54,6 +55,7 @@
  exportDeviceInspectionRecord,
  deleteDeviceInspectionRecord,
} from '@/api/cnas/resourceDemand/device.js'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "inspection-of-equipment",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -127,8 +129,9 @@
        inspectionRecordId: id
      }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备点检记录表.doc')
        saveBlobOrShowError(res, '设备点检记录表.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // åˆ é™¤
src/views/CNAS/resourceDemand/device/component/management.vue
@@ -27,7 +27,7 @@
        </el-form>
      </div>
      <div>
        <el-button size="small" type="primary" @click="dialogVisible2 = true">新增</el-button>
        <el-button size="small" type="primary" @click="openAddDialog">新增</el-button>
        <el-button size="small" type="primary" @click="handleDownOne">导出</el-button>
      </div>
    </div>
@@ -132,7 +132,7 @@
                            :props="props" placeholder="请选择" size="small" style="width:100%;" :collapse-tags="!isUp" separator=","
                            filterable clearable></el-cascader>
                    </el-form-item>
                    <el-form-item label="设备类型:">
                    <el-form-item label="设备/计量器具:">
                        <el-select :disabled="isUp" v-model="formData.largeCategory" placeholder="请选择" size="small"
                            style="width:100%">
                            <el-option v-for="item in equipmentList" :key="item.value" :label="item.label" :value="item.value">
@@ -336,7 +336,7 @@
                            placeholder="请选择" size="small" style="width:100%" collapse-tags separator="," filterable
                            clearable></el-cascader>
                    </el-form-item>
                    <el-form-item label="设备类型:">
                    <el-form-item label="设备/计量器具:">
                        <el-select v-model="formData2.largeCategory" placeholder="请选择" size="small" style="width:100%">
                            <el-option v-for="item in equipmentList" :key="item.value" :label="item.label" :value="item.value">
                            </el-option>
@@ -425,7 +425,9 @@
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import dayjs from 'dayjs'
import { formatListDate } from './dateFormat'
import { selectQualifiedSupplierManagementPage } from '@/api/cnas/externalService/supplierManage/supplierManage'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
    props: {
        clickNodeVal: {
@@ -473,8 +475,11 @@
            showData: false, // æ•°é‡‡é…ç½®é¡µé¢
            tableList: [],
            addDia: true,
            //设备类型列表
            equipmentList: [],
            //设备类型列表:与左侧树“设备/计量器具”分类保持一致
            equipmentList: [
                { label: '设备', value: '设备' },
                { label: '计量器具', value: '计量器具' }
            ],
            // è´Ÿè´£äººåˆ—表
            responsiblePersonList: [],
            // æŽˆæƒäººåˆ—表
@@ -498,18 +503,18 @@
                { label: "出厂编号", prop: "factoryNo" },
                { label: "管理编号", prop: "managementNumber" },
                { label: "技术指标", prop: "technicalIndicators" },
                { label: "购置日期", prop: "acquisitionDate" },
                { label: "校准有效期", prop: "activationDate" },
                { label: "购置日期", prop: "acquisitionDate", formatData: (params) => formatListDate(params) },
                { label: "校准有效期", prop: "activationDate", formatData: (params) => formatListDate(params) },
                { label: "管理人", prop: "equipmentManagerUser" },
                { label: "存放点", prop: "storagePoint" },
                { label: "检验项目", prop: "insProductItem" },
                { label: "校准服务机构", prop: "calibrationServices" },
                { label: "最近校准日期", prop: "lastCalibrationDateTwo" },
                { label: "最近核查日期", prop: "lastExamineDate" },
                { label: "下次校准日期", prop: "nextCalibrationDateTwo" },
                { label: "下次核查日期", prop: "nextExamineDate" },
                { label: "最近保养日期", prop: "lastMaintenanceDate" },
                { label: "下次保养日期", prop: "nextMaintenanceDate" },
                { label: "最近校准日期", prop: "lastCalibrationDateTwo", formatData: (params) => formatListDate(params) },
                { label: "最近核查日期", prop: "lastExamineDate", formatData: (params) => formatListDate(params) },
                { label: "下次校准日期", prop: "nextCalibrationDateTwo", formatData: (params) => formatListDate(params) },
                { label: "下次核查日期", prop: "nextExamineDate", formatData: (params) => formatListDate(params) },
                { label: "最近保养日期", prop: "lastMaintenanceDate", formatData: (params) => formatListDate(params) },
                { label: "下次保养日期", prop: "nextMaintenanceDate", formatData: (params) => formatListDate(params) },
                {
                    label: "设备分类", prop: "largeCategory", dataType: "tag",
                    formatData: (params) => {
@@ -698,8 +703,9 @@
            this.outLoading = true
            exportEquipmentDetails({ ...this.queryParams }).then(res => {
                this.outLoading = false
                const blob = new Blob([res], { type: 'application/octet-stream' });
                this.$download.saveAs(blob, '设备仪器一览表.doc')
                saveBlobOrShowError(res, '设备仪器一览表.doc', 'application/msword')
            }).catch(() => {
                this.outLoading = false
            })
        },
        // èŽ·å–å­—å…¸
@@ -707,10 +713,6 @@
            // è®¾å¤‡çŠ¶æ€
            this.getDicts("device_status").then((response) => {
                this.deviceStatusList = this.dictToValue(response.data);
            });
            // è®¾å¤‡åˆ†ç±»
            this.getDicts("device_type").then((response) => {
                this.equipmentList = this.dictToValue(response.data);
            });
        },
        // èŽ·å–è´Ÿè´£äººåˆ—è¡¨
@@ -812,6 +814,11 @@
            //复制给formData
            this.formData = this.HaveJson(row);
            this.formData.authorizedPerson = this.normalizeAuthorizedPerson(row.authorizedPerson);
            // è®¾å¤‡ç±»åž‹ä¸ºç©ºæ—¶ï¼Œé»˜è®¤å–左侧树当前所在分类
            const treeCategory = this.clickNodeVal && this.clickNodeVal.label
            if (!this.formData.largeCategory && (treeCategory === '设备' || treeCategory === '计量器具')) {
                this.formData.largeCategory = treeCategory
            }
            if (typeof (row.insProductIds) === 'number') {
                row.insProductIds = row.insProductIds + ''
            }
@@ -918,6 +925,8 @@
                this.$message.success('修改成功')
                this.upLoad = false
                this.refreshTable('page')
                // ç±»åž‹å¯èƒ½å˜æ›´ï¼Œåˆ·æ–°å·¦ä¾§æ ‘让设备归到新的分类下
                this.$emit('refresh-tree')
                this.dialogVisible = false
            }).catch(e => {
                this.$message.error('修改失败')
@@ -937,6 +946,10 @@
            }
            if (!this.formData2.managementNumber) {
                this.$message.error('未输入管理编号')
                return
            }
            if (!this.formData2.largeCategory) {
                this.$message.error('请选择设备/计量器具')
                return
            }
            if (!this.formData2.activationDate) {
@@ -961,6 +974,7 @@
                this.$message.success('提交成功')
                this.upLoad2 = false
                this.refreshTable('page')
                this.$emit('refresh-tree')
                this.dialogVisible2 = false
                this.formData2 = {
                    imageUpload: '',
@@ -1006,6 +1020,14 @@
                this.refreshTable('page')
            }
        },
        // æ–°å¢žè®¾å¤‡ï¼šé»˜è®¤å–左侧树当前所在分类
        openAddDialog() {
            const treeCategory = this.clickNodeVal && this.clickNodeVal.label
            if (!this.formData2.largeCategory && (treeCategory === '设备' || treeCategory === '计量器具')) {
                this.formData2.largeCategory = treeCategory
            }
            this.dialogVisible2 = true
        },
        handleDelete(row) {
            this.$confirm("是否删除该条数据?", "提示", {
                confirmButtonText: "确定",
@@ -1015,7 +1037,9 @@
                .then(() => {
                    delDeviceParameter({ id: row.id }).then((res) => {
                        this.$message.success("删除成功");
                        this.refresh();
                        this.refreshTable()
                        // å·²åˆ é™¤çš„设备要从左侧树同步移除
                        this.$emit('refresh-tree')
                    });
                })
                .catch(() => { });
src/views/CNAS/resourceDemand/device/component/operationInstruction.vue
@@ -17,11 +17,12 @@
      <el-table-column label="设备编号" min-width="150" prop="deviceNumber"></el-table-column>
      <el-table-column label="设备型号" min-width="150" prop="deviceModel"></el-table-column>
      <el-table-column label="文件编号" min-width="150" prop="documentNumber"></el-table-column>
      <el-table-column label="文件名字" min-width="150" prop="fileName"></el-table-column>
      <el-table-column label="文件名称" min-width="150" prop="fileName"></el-table-column>
      <el-table-column label="文档说明" min-width="150" prop="documentNote"></el-table-column>
      <el-table-column label="上传人" min-width="150" prop="uploaderName"></el-table-column>
      <el-table-column label="上传时间" min-width="150" prop="updateTime"></el-table-column>
      <el-table-column label="生效时间" min-width="150" prop="entryIntoForceTime"></el-table-column>
      <el-table-column label="上传时间" min-width="150" prop="updateTime" :formatter="formatDateCell"></el-table-column>
      <el-table-column label="生效时间" min-width="150" prop="entryIntoForceTime"
        :formatter="formatDateCell"></el-table-column>
      <el-table-column label="审批人" min-width="150" prop="approverName"></el-table-column>
      <el-table-column label="审批状态" min-width="150" prop="status">
        <template v-slot="scope">
@@ -31,14 +32,16 @@
      <el-table-column label="操作" min-width="180" fixed="right" prop="name">
        <template v-slot="scope">
          <el-button link type="primary" size="small" @click="downloadFile(scope.row.fileSystemName)">下载</el-button>
          <el-button link type="primary" size="small" style="color: red;"
          <el-button link type="primary" size="small" style="color: red;" :disabled="scope.row.status === true"
            @click="deleteHomeworkGuidebook(scope.row)">删除</el-button>
          <el-button link type="primary" size="small" @click="instructionEditFun(scope.row)">编辑</el-button>
          <el-button link type="primary" size="small" @click="approval(scope.row)">审批</el-button>
          <el-button link type="primary" size="small" :disabled="scope.row.status === true"
            @click="instructionEditFun(scope.row)">编辑</el-button>
          <el-button link type="primary" size="small" :disabled="scope.row.status === true"
            @click="approval(scope.row)">审批</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="1"
    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="search.current"
      :page-sizes="[10, 20, 30, 50, 100]" :page-size="search.size" layout="->,total, sizes, prev, pager, next, jumper"
      :total="search.total" background>
    </el-pagination>
@@ -82,7 +85,7 @@
        <el-table :data="documentTableData" border style="width: 100%;" tooltip-effect="dark" :row-key="getRowKey"
          @selection-change="handleSelectionChange" height="29em">
          <el-table-column type="selection" width="55%">
          <el-table-column type="selection" width="55">
          </el-table-column>
          <el-table-column label="序号" prop="id" type="index" width="60"></el-table-column>
          <el-table-column label="设备名称" prop="deviceName" show-overflow-tooltip min-width="125"></el-table-column>
@@ -91,7 +94,8 @@
          <el-table-column label="文档编号" prop="documentNumber" show-overflow-tooltip min-width="125"></el-table-column>
          <el-table-column label="文件名称" prop="fileName" show-overflow-tooltip min-width="125"></el-table-column>
          <el-table-column label="上传人" prop="author" show-overflow-tooltip min-width="125"></el-table-column>
          <el-table-column label="上传时间" prop="updateTime" show-overflow-tooltip min-width="125"></el-table-column>
          <el-table-column label="上传时间" prop="updateTime" show-overflow-tooltip min-width="125"
            :formatter="formatDateCell"></el-table-column>
          <el-table-column min-width="100" label="操作" fixed="right">
            <template v-slot="scope">
              <el-button link type="primary" size="small" @click="downloadFile(scope.row.fileSystemName)">下载</el-button>
@@ -188,6 +192,7 @@
  pageByPageQueryOfHomeworkInstructions,
  selectDeviceParameter,
} from '@/api/cnas/resourceDemand/device.js'
import { formatListDate } from './dateFormat'
export default {
  props: {
    clickNodeVal: {
@@ -266,6 +271,9 @@
    }
  },
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    approval(row) {
      this.$confirm('是否审批通过!', '提示', {
        confirmButtonText: '通过',
@@ -273,8 +281,11 @@
        type: 'warning'
      }).then(() => {
        this.approvalFun(row.id, true)
      }).catch(() => {
        this.approvalFun(row.id, false)
      }).catch((action) => {
        // åªæœ‰ç‚¹å‡»â€œä¸é€šè¿‡â€æ‰æäº¤é©³å›žï¼Œç‚¹å³ä¸Šè§’关闭/Esc è§†ä¸ºæ”¾å¼ƒæ“ä½œ
        if (action === 'cancel') {
          this.approvalFun(row.id, false)
        }
      });
    },
    approvalFun(id, status) {
@@ -329,9 +340,9 @@
      homeworkGuidebookEditor({ instructionId: row.instructionId }).then(res => {
        if (res.code == 200) {
          this.instructionForm = res.data.instruction;
          if (this.instructionForm.fileSystemName) {
            this.fileList1.push({ name: this.instructionForm.fileName })
          }
          this.fileList1 = this.instructionForm.fileSystemName
            ? [{ name: this.instructionForm.fileName }]
            : []
          this.documentTableData = res.data.list;
          // åˆ é™¤ç”¨
          this.documentTableData.forEach((v, k) => {
@@ -402,6 +413,7 @@
            this.$message.success('修改成功');
            console.log('this.documentTableData---edit', this.documentTableData[this.tableDataIndex])
          } else {
            this.form.index = this.getNextRowIndex();
            this.documentTableData.push(this.form);
            this.dialogVisible1 = false;
            this.$message.success('添加成功');
@@ -423,12 +435,17 @@
    editFun(row, index) {
      this.form = { ...row }
      this.tableDataIndex = index;
      console.log('this.tableDataIndex', this.tableDataIndex)
      // å›žæ˜¾åˆ—表
      // å›žæ˜¾åˆ—表前先清空,避免重复显示上一次的附件
      this.fileList = []
      if (this.form.fileSystemName) {
        this.fileList.push({ name: this.form.fileName })
      }
      this.dialogVisible1 = true
    },
    getNextRowIndex() {
      return this.documentTableData.reduce((max, item) => {
        return typeof item.index === 'number' && item.index > max ? item.index : max
      }, -1) + 1
    },
    closeDia() {
      this.dialogVisible1 = false
@@ -443,22 +460,24 @@
        this.$message.error('请选择要删除的选项');
        return;
      }
      // åˆ é™¤ä¿å­˜å¥½çš„æ•°æ®
      let ids = this.selectedRow
      const selectedIndexes = this.selectedRow.map(item => item.index);
      // åˆ é™¤å·²ä¿å­˜çš„æ•°æ®ï¼›æœ¬æ¬¡æ–°åŠ ã€å°šæœªè½åº“çš„è¡Œæ²¡æœ‰ id,不调接口
      const ids = this.selectedRow
        .filter(item => item.id !== undefined)
        .map(item => item.id).join(',');
      //有错误
      const res = await deleteHomeworkGuidebook({ ids });
      if (res.code === 200) {
        // åˆ é™¤è§†å›¾çš„æ•°æ®
        for (const resKey in this.selectedRow) {
          this.documentTableData = this.documentTableData.filter(item => item.index === this.selectedRow[resKey].index)
      if (ids) {
        const res = await deleteHomeworkGuidebook({ ids });
        if (res.code !== 200) {
          return;
        }
        this.$message.success({
          message: '删除成功',
          type: 'success'
        });
      }
      // ä¸€æ¬¡æ€§è¿‡æ»¤æŽ‰æ‰€æœ‰é€‰ä¸­è¡Œï¼Œä¿ç•™å…¶ä½™æ•°æ®
      this.documentTableData = this.documentTableData.filter(item => !selectedIndexes.includes(item.index))
      this.selectedRow = []
      this.$message.success({
        message: '删除成功',
        type: 'success'
      });
    },
    onSuccess(response, file, fileList) {
      this.form.fileName = file.name;
@@ -476,8 +495,8 @@
      this.form.fileSystemName = ''
    },
    handleRemove1(file, fileList) {
      this.form.fileName = ''
      this.form.fileSystemName = ''
      this.instructionForm.fileName = ''
      this.instructionForm.fileSystemName = ''
    },
    beforeRemove(file) {
      return this.$confirm(`确定移除 ${file.name}?`)
@@ -486,7 +505,12 @@
      this.$message.warning(`当前限制选择 1 ä¸ªæ–‡ä»¶ï¼Œæœ¬æ¬¡é€‰æ‹©äº† ${files.length} ä¸ªæ–‡ä»¶ã€‚`);
    },
    getList() {
      pageByPageQueryOfHomeworkInstructions({ ...this.search }).then(res => {
      const params = { ...this.search }
      // é€‰ä¸­å…·ä½“设备时只查该设备的作业指导书
      if (this.clickNodeVal && this.clickNodeVal.value) {
        params.deviceId = this.clickNodeVal.value
      }
      pageByPageQueryOfHomeworkInstructions(params).then(res => {
        if (res.code == 200) {
          this.tableData = res.data.records;
          this.search.total = res.data.total
src/views/CNAS/resourceDemand/device/component/quantityValueTraceabilityPlan.vue
@@ -15,7 +15,8 @@
          <el-table-column label="年份" min-width="80" prop="planYear"></el-table-column>
          <el-table-column label="文件名称" min-width="120" prop="compiler"></el-table-column>
          <el-table-column label="编制人" min-width="150" prop="compiler"></el-table-column>
          <el-table-column label="编制时间" min-width="160" prop="datePreparation"></el-table-column>
          <el-table-column label="编制时间" min-width="160" prop="datePreparation"
            :formatter="formatDateCell"></el-table-column>
          <el-table-column label="批准人" min-width="180" prop="audit"></el-table-column>
          <el-table-column label="批准状态" min-width="180" prop="status">
            <template #default="scope">
@@ -23,7 +24,8 @@
              <el-tag v-if="scope.row.status === 0" type="danger">不批准</el-tag>
            </template>
          </el-table-column>
          <el-table-column label="批准时间" min-width="180" prop="auditDate"></el-table-column>
          <el-table-column label="批准时间" min-width="180" prop="auditDate"
            :formatter="formatDateCell"></el-table-column>
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="270">
            <template #default="scope">
@@ -174,6 +176,7 @@
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { mapGetters } from "@/utils/store-compat";
import { formatListDate } from './dateFormat'
export default {
  name: "quantity-value-traceability-plan",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -220,6 +223,9 @@
  },
  // æ–¹æ³•集合
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    // æŸ¥è¯¢
    getYearTableDetailData() {
      this.yearTableDetailDataLoading = true
src/views/CNAS/resourceDemand/device/component/record.vue
@@ -17,7 +17,7 @@
        </el-form-item>
      </el-form>
      <div>
        <el-button size="small" type="primary" @click="dialogVisible = true, openAdd()">新 å»º</el-button>
        <el-button v-if="isMenuList !== 1" size="small" type="primary" @click="dialogVisible = true, openAdd()">新 å»º</el-button>
        <el-button :loading="outLoading" size="small" type="primary" @click="openHandleOut">导 å‡º</el-button>
      </div>
    </div>
@@ -45,8 +45,8 @@
          </template>
        </el-table-column>
        <!--        <el-table-column label="异常情况" min-width="120" prop="abnormal" />-->
        <el-table-column label="使用开始日期" min-width="170" prop="useStartDate" />
        <el-table-column label="使用结束日期" min-width="170" prop="useEndDate" />
        <el-table-column label="使用开始日期" min-width="170" prop="useStartDate" :formatter="formatDateCell" />
        <el-table-column label="使用结束日期" min-width="170" prop="useEndDate" :formatter="formatDateCell" />
        <el-table-column label="使用人" min-width="120" prop="usePerson" />
        <el-table-column label="备注" min-width="120" prop="remark" />
        <!-- æ“ä½œæŒ‰é’® -->
@@ -58,7 +58,7 @@
          </template>
        </el-table-column>
      </el-table>
      <el-pagination :current-page="1" :page-size="search.size" :page-sizes="[10, 20, 30, 50, 100]"
      <el-pagination :current-page="search.current" :page-size="search.size" :page-sizes="[10, 20, 30, 50, 100]"
        :total="search.total" layout="->,total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
        @current-change="handleCurrentChange" background>
      </el-pagination>
@@ -157,6 +157,8 @@
  deleteDeviceRecord,
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { formatListDate } from './dateFormat';
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  props: {
    clickNodeVal: {
@@ -221,6 +223,9 @@
    this.getTableList(this.clickNodeVal.value);
  },
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    // element-plus çš„ el-date-picker æ²¡æœ‰ picker-options,改成 :disabled-date
    disabledDate(time) {
      return time.getTime() > Date.now();
@@ -275,8 +280,9 @@
        exportDate: this.exportDate
      }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备使用记录.doc')
        saveBlobOrShowError(res, '设备使用记录.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    //新建
@@ -312,7 +318,6 @@
                this.dialogVisible = false
              }
            })
            this.dialogVisible = false;
          } else {
            updateDeviceRecord(this.form).then(res => {
              if (res.code == 200) {
@@ -321,7 +326,6 @@
                this.dialogVisible = false
              }
            })
            this.dialogVisible = false;
          }
        }
      });
@@ -329,20 +333,17 @@
    //查看详情
    showDetailsDialog(type, row) {
      this.operationType = type;
      console.log(row)
      this.dialogVisible = true;
      this.getUserList()
      this.form = row;
      let list = []
      if (row.useStartDate === null) {
        row.useStartDate = ''
      // å¤åˆ¶ä¸€ä»½å†ç¼–辑,避免直接改动表格里的数据
      const useStartDate = row.useStartDate || ''
      const useEndDate = row.useEndDate || ''
      this.form = {
        ...row,
        useStartDate,
        useEndDate,
        useDateList: useStartDate && useEndDate ? [useStartDate, useEndDate] : []
      }
      if (row.useEndDate === null) {
        row.useEndDate = ''
      }
      list.push(row.useStartDate)
      list.push(row.useEndDate)
      this.form['useDateList'] = list
    },
    handleDeleteClick(index, row) {
      this.$confirm('此操作将永久删除该文件, æ˜¯å¦ç»§ç»­?', '提示', {
src/views/CNAS/resourceDemand/device/component/scrapApplicationForm.vue
@@ -8,7 +8,7 @@
        <el-step title="计量室意见" @click="setStep(2)"></el-step>
        <el-step title="批准人" @click="setStep(3)"></el-step>
      </el-steps>
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px">
      <el-form ref="modelForm" :model="form" :rules="rules" label-width="160px" :disabled="!canOperate">
        <el-col v-if="showStep === 0" :span="24">
          <el-form-item label="配件:" prop="parts">
            <el-input v-model="form.parts" :disabled="currentStep !== 0" clearable size="small"></el-input>
@@ -65,7 +65,7 @@
      </el-form>
      <template #footer><span  class="dialog-footer">
        <el-button @click="resetForm">取 æ¶ˆ</el-button>
        <el-button v-if="currentStep !== 4" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
        <el-button v-if="currentStep !== 4 && canOperate" :loading="submitFormLoading" type="primary" @click="submitForm">ç¡®
          è®¤</el-button>
      </span></template>
    </el-dialog>
@@ -78,6 +78,7 @@
  addDeviceScrapped,
} from '@/api/cnas/resourceDemand/device.js'
import { selectUserCondition } from "@/api/business/inspectionTask";
import { mapGetters } from "@/utils/store-compat";
export default {
  name: "scrapApplicationForm",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -87,6 +88,7 @@
    return {
      dialogVisible: false,
      submitFormLoading: false,
      canOperate: true,
      form: {
        parts: '',
        reasonsForScrap: '',
@@ -118,6 +120,7 @@
    // æ‰“开弹框
    openDialog(id, deviceId) {
      this.dialogVisible = true
      this.canOperate = true
      this.form.scrappedId = id
      this.form.deviceId = deviceId
      this.getUserList()
@@ -149,10 +152,29 @@
            this.currentStep = 4
            this.showStep = 3
          }
          this.applyPermission()
        }
      }).catch(error => {
        console.error(error)
      })
    },
    // éžå½“前环节责任人只允许查看
    applyPermission() {
      if (this.form.isFinish === 1 || this.currentStep >= 4) {
        this.canOperate = false
        return
      }
      const responsibleList = [
        this.form.applicantUser,
        this.form.departmentHeadUser,
        this.form.meteringRoomUser,
        this.form.approverUser,
      ]
      const responsible = responsibleList[this.currentStep]
      this.canOperate = !responsible || responsible === this.nickName
      if (!this.canOperate) {
        this.$message.warning('当前环节责任人为:' + responsible + ',您只能查看')
      }
    },
    setStep(step) {
      this.showStep = step
@@ -162,6 +184,7 @@
      this.form.flowType = this.currentStep
      this.$refs.modelForm.validate((valid) => {
        if (valid) {
          this.submitFormLoading = true
          addDeviceScrapped(this.form).then(res => {
            if (res.code == 200) {
              this.$message.success('新增成功')
@@ -185,6 +208,9 @@
      })
    },
  },
  computed: {
    ...mapGetters(["nickName"]),
  },
}
</script>
src/views/CNAS/resourceDemand/device/component/state.vue
@@ -13,7 +13,7 @@
        </el-form-item>
      </el-form>
      <div>
        <el-button size="small" type="primary" @click="dialogVisible = true">新建</el-button>
        <el-button size="small" type="primary" @click="handleAddClick">新建</el-button>
        <el-button :loading="outLoading" size="small" type="primary" @click="handleDown">导出Excel</el-button>
      </div>
    </div>
@@ -33,7 +33,8 @@
        </el-table-column>
        <el-table-column label="停用/启用理由" min-width="180" prop="reason"></el-table-column>
        <el-table-column label="提交人" min-width="130" prop="createUser"></el-table-column>
        <el-table-column label="提交日期" min-width="150" prop="createTime"></el-table-column>
        <el-table-column label="提交日期" min-width="150" prop="createTime"
          :formatter="formatDateCell"></el-table-column>
        <el-table-column label="当前状态" min-width="130" prop="currentState"></el-table-column>
        <el-table-column label="当前责任人" min-width="180" prop="currentResponsible"></el-table-column>
        <!-- æ“ä½œæŒ‰é’® -->
@@ -45,7 +46,7 @@
          </template>
        </el-table-column>
      </el-table>
      <el-pagination :current-page="1" :page-size="search.size" :page-sizes="[10, 20, 30, 50, 100]"
      <el-pagination :current-page="search.current" :page-size="search.size" :page-sizes="[10, 20, 30, 50, 100]"
        :total="search.total" layout="->,total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
        @current-change="handleCurrentChange" background>
      </el-pagination>
@@ -56,7 +57,7 @@
        <el-step v-for="(v, i) in steps" :key="i" :title="v" style="cursor:pointer"
          @click="choiceStep(i)"></el-step>
      </el-steps>
      <el-form ref="form" :model="form" :rules="rules" label-width="130px">
      <el-form ref="form" :model="form" :rules="rules" label-width="130px" :disabled="!canOperate">
        <div v-show="currentStepClick === 0">
          <el-card style="margin-top: 1em; height: 42vh; overflow-y: scroll;">
            <!-- å¡ç‰‡ -->
@@ -220,10 +221,10 @@
        </div>
      </el-form>
      <template #footer><span  class="dialog-footer">
        <el-button v-if="currentStep !== 0 && currentStep !== 4" :loading="sumbitLoading1"
        <el-button v-if="currentStep !== 0 && currentStep !== 4 && canOperate" :loading="sumbitLoading1"
          @click="submitForm('3reject')">驳回</el-button>
        <el-button v-if="currentStep === 0" :loading="sumbitLoading2" @click="submitForm('2save')">保存</el-button>
        <el-button v-if="currentStep !== 4" :loading="sumbitLoading3" type="primary" @click="submitForm('1submit')">
        <el-button v-if="currentStep === 0 && canOperate" :loading="sumbitLoading2" @click="submitForm('2save')">保存</el-button>
        <el-button v-if="currentStep !== 4 && canOperate" :loading="sumbitLoading3" type="primary" @click="submitForm('1submit')">
          {{ currentStep === 0 ? '提交' : '通过' }}
        </el-button>
      </span></template>
@@ -242,6 +243,8 @@
import { selectUserCondition } from "@/api/business/inspectionTask";
import { dateFormat } from '@/utils/date'
import { mapGetters } from "@/utils/store-compat";
import { formatListDate } from './dateFormat'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  props: {
    clickNodeVal: {
@@ -258,6 +261,7 @@
    return {
      outLoading: false, // å¯¼å‡ºloading
      dialogVisible: false,
      canOperate: true,
      form: {},
      currentStep: 0, // æ­¥éª¤æ¡æ˜¾ç¤ºç¬¬å‡ æ­¥
      currentStepClick: 0, // ç‚¹å‡»æ­¥éª¤æ¡å˜åŒ–
@@ -282,6 +286,9 @@
    this.getDeviceStatePage(this.clickNodeVal.value)
  },
  methods: {
    formatDateCell(row, column, cellValue) {
      return formatListDate(cellValue)
    },
    // åˆ†é¡µ
    handleSizeChange(val) {
      this.search.size = val
@@ -341,22 +348,40 @@
            default:
              break
          }
          // èŽ·å–å½“å‰çŽ¯èŠ‚è´Ÿè´£äºº
          switch (saveState === '3reject' ? this.currentStep - 1 : this.currentStep) {
            case 0:
              this.form.currentResponsible = this.form.submitOperatingPersonnel
              break
            case 1:
              this.form.currentResponsible = this.form.departmentOperatingPersonnel
              break
            case 2:
              this.form.currentResponsible = this.form.measuringRoomOperatingPersonnel
              break
            case 3:
              this.form.currentResponsible = this.form.approvalOperatingPersonnel
              break
            default:
              break
          // èŽ·å–å½“å‰çŽ¯èŠ‚è´Ÿè´£äººï¼šé©³å›žå›žåˆ°ä¸Šä¸€çŽ¯èŠ‚æ“ä½œäººï¼Œä¿å­˜ç•™ç»™è‡ªå·±ï¼Œæäº¤/通过进入下一环节责任人
          if (saveState === '3reject') {
            switch (this.currentStep - 1) {
              case 0:
                this.form.currentResponsible = this.form.submitOperatingPersonnel
                break
              case 1:
                this.form.currentResponsible = this.form.departmentOperatingPersonnel
                break
              case 2:
                this.form.currentResponsible = this.form.measuringRoomOperatingPersonnel
                break
              default:
                break
            }
          } else if (saveState === '2save') {
            this.form.currentResponsible = this.form.submitOperatingPersonnel
          } else {
            switch (this.currentStep) {
              case 0:
                this.form.currentResponsible = this.form.submitNextPesponsible
                break
              case 1:
                this.form.currentResponsible = this.form.departmentNextPesponsible
                break
              case 2:
                this.form.currentResponsible = this.form.measuringRoomNextPesponsible
                break
              case 3:
                this.form.currentResponsible = this.form.approvalNextPesponsible
                break
              default:
                break
            }
          }
          // èŽ·å–å½“å‰çŠ¶æ€
          this.form.currentState = currentStepAction === 4 ? '关闭' : this.steps[currentStepAction]
@@ -406,24 +431,43 @@
        }
      })
    },
    // æ–°å»º
    handleAddClick() {
      this.canOperate = true
      this.dialogVisible = true
    },
    // æŸ¥çœ‹
    handleViewClick(row) {
      this.form = { ...row }
      // å¦‚果索引为6表示全部通过
      this.currentStep = this.steps.indexOf(this.form.currentState) === -1 ? 4 : this.steps.indexOf(this.form.currentState)
      this.currentStepClick = this.currentStep === 4 ? 0 : this.currentStep
      this.$nextTick(() => {
        this.$refs['form'].clearValidate()
      })
      this.applyPermission()
      this.dialogVisible = true
      this.$nextTick(() => {
        this.$refs['form'] && this.$refs['form'].clearValidate()
      })
    },
    // éžå½“前环节责任人只允许查看
    applyPermission() {
      if (this.currentStep === 4) {
        this.canOperate = false
        return
      }
      const responsible = this.form.currentResponsible
      this.canOperate = !responsible || responsible === this.nickName
      if (!this.canOperate) {
        this.$message.warning('当前环节责任人为:' + responsible + ',您只能查看')
      }
    },
    // å¯¼å‡º
    handleDownOne(row) {
      this.outLoading = true
      exportDeviceStatus({ deviceId: row.deviceId, processNumber: row.processNumber }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备停/启用.doc')
        saveBlobOrShowError(res, '设备停/启用.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // åˆ é™¤
@@ -454,9 +498,8 @@
        processNumber: this.search.processNumber
      }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '设备停用/启用.xlsx')
      }).finally(() => {
        saveBlobOrShowError(res, '设备停用/启用.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
      }).catch(() => {
        this.outLoading = false
      })
    },
@@ -482,8 +525,6 @@
    // ç›‘听点击el-tree的数据,进行数据刷新
    clickNodeVal(newVal) {
      if (newVal.value) {
        this.componentData.entity.deviceId = this.clickNodeVal.value
        this.entityCopy = this.HaveJson(this.componentData.entity)
        this.getDeviceStatePage(newVal.value)
      }
    },
@@ -494,7 +535,7 @@
        this.closeLoading()
        this.currentStep = 0 // æ­¥éª¤æ¡æ˜¾ç¤ºç¬¬å‡ æ­¥
        this.currentStepClick = 0 // ç‚¹å‡»æ­¥éª¤æ¡å˜åŒ–
        this.$refs['form'].clearValidate()
        this.$refs['form'] && this.$refs['form'].clearValidate()
      }
    }
  },
src/views/CNAS/resourceDemand/device/component/usageAuthorization.vue
@@ -10,7 +10,7 @@
                  :page="page" :tableLoading="tableLoading"></lims-table>
    </div>
    <el-dialog :close-on-click-modal="false" :close-on-press-escape="false" v-model="usageTableDia"
               title="设备保养计划表" width="80%" @close="closeDialog">
               title="设备使用授权表" width="80%" @close="closeDialog">
      <div style="display: flex;align-items: center;">
        <el-button size="small" type="primary" @click="addTableRow" v-if="operationType !== 'check'">添加</el-button>
        <span style="width: 60px;margin-left: 10px">年份:</span>
@@ -53,7 +53,7 @@
                         clearable filterable multiple
                         :disabled="operationType === 'check'"
                         placeholder="请选择" size="small" style="width: 100%;">
                <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.id">
                <el-option v-for="item in responsibleOptions" :key="item.id" :label="item.name" :value="item.name">
                </el-option>
              </el-select>
            </template>
@@ -122,6 +122,8 @@
} from "@/api/cnas/resourceDemand/device";
import {selectUserCondition} from "@/api/system/user";
import {mapGetters} from "@/utils/store-compat";
import {formatListDate} from './dateFormat'
import {saveBlobOrShowError} from '@/utils/saveBlob'
export default {
  name: '',
@@ -148,9 +150,9 @@
      column: [
        { label: '计划年份', prop: 'impowerYear' },
        { label: '编制人', prop: 'compiler' },
        { label: '编制时间', prop: 'datePreparation' },
        { label: '编制时间', prop: 'datePreparation', formatData: val => formatListDate(val) },
        { label: '授权人', prop: 'audit' },
        { label: '授权日期', prop: 'auditDate' },
        { label: '授权日期', prop: 'auditDate', formatData: val => formatListDate(val) },
        {
          dataType: 'tag',
          label: '授权状态',
@@ -205,7 +207,7 @@
                this.openDia('check', row);
              },
              disabled: (row) => {
                return row.status === 1 || this.userId !== row.auditId;
                return row.status === 1 || this.userId != row.auditId;
              },
            },
            {
@@ -259,6 +261,7 @@
    },
    // åˆ†é¡µåˆ‡æ¢
    pagination(page) {
      this.page.current = page.page
      this.page.size = page.limit
      this.getTableList()
    },
@@ -319,9 +322,9 @@
        getImpowerDetail({ impowerId: this.impowerId }).then(res => {
          if (res.code === 200) {
            this.form = res.data
            this.deviceImpowerDetails = this.form.deviceImpowerDetails
            this.deviceImpowerDetails = this.form.deviceImpowerDetails || []
            this.deviceImpowerDetails.forEach(item => {
              item['delegatedUserArr'] = item.delegatedUser.split(',')
              item['delegatedUserArr'] = item.delegatedUser ? String(item.delegatedUser).split(',') : []
            })
          }
        }).catch(error => {
@@ -347,9 +350,24 @@
    },
    // æäº¤æ–°å¢žå’Œä¿®æ”¹
    submitForm() {
      if (!this.form.impowerYear) {
        this.$message.warning('请选择年份')
        return
      }
      if (!this.deviceImpowerDetails.length) {
        this.$message.warning('请添加设备')
        return
      }
      const noDelegatee = this.deviceImpowerDetails.find(item => {
        return !Array.isArray(item.delegatedUserArr) || item.delegatedUserArr.length === 0
      })
      if (noDelegatee) {
        this.$message.warning(`请为设备“${noDelegatee.deviceName || ''}”选择被授权人`)
        return
      }
      this.form.deviceImpowerDetails = this.HaveJson(this.deviceImpowerDetails)
      this.form.deviceImpowerDetails.forEach((item) => {
        item.delegatedUser = item.delegatedUserArr.join(',')
        item.delegatedUser = Array.isArray(item.delegatedUserArr) ? item.delegatedUserArr.join(',') : ''
      })
      this.submitFormLoading = true
      if (this.operationType === 'add') {
@@ -421,10 +439,12 @@
      })
    },
    openHandleOut (row) {
      this.outLoading = true
      exportDeviceImpower({ impowerId: row.impowerId }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/msword' });
        this.$download.saveAs(blob, '设备使用授权表' + '.docx')
        saveBlobOrShowError(res, '设备使用授权表.docx', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    handleDeleteClick(row) {
src/views/CNAS/resourceDemand/device/component/usingExternalInstruments.vue
@@ -36,15 +36,15 @@
          <!-- æ“ä½œæŒ‰é’® -->
          <el-table-column align="center" fixed="right" label="操作" min-width="150">
            <template #default="scope">
              <el-button :disabled="scope.row.ratifyStatus === 1" size="small" link type="primary"
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="primary"
                @click="handleForm(scope.row.externalApplyId)">操作</el-button>
              <el-button size="small" link type="primary" @click="handleDownOne(scope.row.externalApplyId)">导出</el-button>
              <el-button size="small" link type="danger"
              <el-button :disabled="scope.row.isFinish === 1" size="small" link type="danger"
                @click="deleteFun(scope.row.externalApplyId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination :current-page="1" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
        <el-pagination :current-page="pagination1.current" :page-size="pagination1.size" :page-sizes="[10, 20, 30, 50, 100]"
          :total="pagination1.total" layout="->,total, sizes, prev, pager, next, jumper" background
          @size-change="handleSizeChange1" @current-change="handleCurrentChange1">
        </el-pagination>
@@ -61,6 +61,7 @@
  exportDeviceExternalApply,
  delDeviceExternalApply,
} from '@/api/cnas/resourceDemand/device.js'
import { saveBlobOrShowError } from '@/utils/saveBlob'
export default {
  name: "using-external-instruments",
  // import å¼•入的组件需要注入到对象中才能使用
@@ -135,8 +136,9 @@
      this.outLoading = true
      exportDeviceExternalApply({ externalApplyId: id }).then(res => {
        this.outLoading = false
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '利用外部仪器设备申请表.doc')
        saveBlobOrShowError(res, '利用外部仪器设备申请表.doc', 'application/msword')
      }).catch(() => {
        this.outLoading = false
      })
    },
    // åˆ é™¤
src/views/CNAS/resourceDemand/device/index.vue
@@ -39,7 +39,8 @@
            <overview v-if="menuListActiveName == '设备总览'" :clickNodeVal="clickNodeVal" @refresh-tree="geList" />
          </el-tab-pane>
          <el-tab-pane label="设备工具明细" name="设备工具明细">
            <management v-if="menuListActiveName == '设备工具明细'" :clickNodeVal="clickNodeVal" />
            <management v-if="menuListActiveName == '设备工具明细'" :clickNodeVal="clickNodeVal"
              @refresh-tree="geList" />
          </el-tab-pane>
          <el-tab-pane label="设备校准计划" name="设备校准计划">
            <equipment-calibration-plan v-if="menuListActiveName == '设备校准计划'"
@@ -68,7 +69,8 @@
      <div v-if="!isShowAll" style="height: 100%;">
        <el-tabs v-model="tabListActiveName" class="main_right" type="border-card" @tab-click="handleClick">
          <el-tab-pane label="设备档案" name="设备档案">
            <files v-if="tabListActiveName == '设备档案'" :clickNodeVal="clickNodeVal" />
            <files v-if="tabListActiveName == '设备档案'" :clickNodeVal="clickNodeVal"
              @refresh-tree="geList" />
          </el-tab-pane>
          <el-tab-pane label="设备验收" name="设备验收">
            <equipment-acceptance v-if="tabListActiveName == '设备验收'" :clickNodeVal="clickNodeVal"></equipment-acceptance>
@@ -136,6 +138,7 @@
import {
  treeDevice,
} from '@/api/cnas/resourceDemand/device.js'
import dayjs from 'dayjs'
export default {
  name: 'Device',
  components: {
@@ -205,13 +208,10 @@
    // åˆ¤æ–­æ˜¯å¦éœ€è¦æ ‡çº¢
    shouldHighlight(data) {
      if (!data.activationDate) return false;
      const today = new Date();
      const targetDate = new Date(data.activationDate);
      const fiveDaysBeforeTarget = new Date(targetDate);
      // è®¡ç®—前五天的日期
      fiveDaysBeforeTarget.setDate(targetDate.getDate() - 5);
      return today > fiveDaysBeforeTarget;
      const targetDate = dayjs(data.activationDate);
      if (!targetDate.isValid()) return false;
      // æ ¡å‡†æœ‰æ•ˆæœŸå‰ 1 ä¸ªæœˆå¼€å§‹æ ‡çº¢
      return dayjs().isAfter(targetDate.subtract(1, 'month'));
    },
    handleNodeClick(val, node, el) {
      // ç‚¹å‡»ä¸´æ—¶ç¼“å­˜
src/views/CNAS/resourceDemand/facilitiesEnvironment/component/facilities-environmental-conditions.vue
@@ -2,44 +2,26 @@
  <el-row>
    <el-col :span="2">
      <el-menu @select="clickSelect" :default-active="activeName">
        <el-menu-item index="电源稳定性">
          <span>电源稳定性</span>
        </el-menu-item>
        <el-menu-item index="防雷检测">
          <span>防雷检测</span>
        </el-menu-item>
        <el-menu-item index="照度记录">
          <span>照度记录</span>
        </el-menu-item>
        <el-menu-item index="温湿度记录">
          <span>温湿度记录</span>
        </el-menu-item>
      </el-menu>
    </el-col>
    <el-col :span="22" style="padding: 10px">
      <power-supply-stability v-if="activeName === '电源稳定性'"/>
      <lightning-protection-detection v-if="activeName === '防雷检测'" />
      <illuminance-recording v-if="activeName === '照度记录'"/>
      <temperature-humidity-record v-if="activeName === '温湿度记录'"/>
    </el-col>
  </el-row>
</template>
<script>
// ç”µæºç¨³å®šæ€§
import PowerSupplyStability from "./facilities-environmental-conditions/power-supply-stability.vue";
// é˜²é›·æ£€æµ‹
import LightningProtectionDetection from "./facilities-environmental-conditions/lightning-protection-detection.vue";
// ç…§åº¦è®°å½•
import IlluminanceRecording from "./facilities-environmental-conditions/illuminance-recording.vue";
// æ¸©æ¹¿åº¦è®°å½•
import TemperatureHumidityRecord from "./facilities-environmental-conditions/temperature-humidity-record.vue";
export default {
  components: {TemperatureHumidityRecord, IlluminanceRecording, LightningProtectionDetection, PowerSupplyStability},
  components: {TemperatureHumidityRecord},
  data() {
    return {
      activeName: "电源稳定性"
      activeName: "温湿度记录"
    }
  },
  methods: {
src/views/CNAS/resourceDemand/standardMaterial/index.vue
@@ -109,9 +109,14 @@
          minWidth: '100'
        },
        {
          label: '数量',
          label: '原始数量',
          prop: 'quantity',
          minWidth: '100'
        },
        {
          label: '余量',
          prop: 'remainingQuantity',
          minWidth: '80'
        },
        {
          label: '单位',
@@ -167,6 +172,9 @@
              clickFun: (row) => {
                this.borrow(row);
              },
              disabled: (row) => {
                return Number(row.remainingQuantity) <= 0;
              },
            },
            {
              name: '删除',