liding
17 小时以前 5c78d79309e3a8e8e61cd1250dce60f9c99d0e03
src/views/CNAS/process/method/methodVerification/component/wordFormDIa.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,297 @@
<template>
  <div>
    <el-dialog v-model="visible" :title="dialogTitle"
               width="90%" :close-on-click-modal="false" @close="closeDia">
      <div class="form-body">
        <table class="verify-table">
          <colgroup>
            <col style="width: 16%"/>
            <col style="width: 36%"/>
            <col style="width: 16%"/>
            <col style="width: 32%"/>
          </colgroup>
          <tbody>
          <tr>
            <th>标准名称</th>
            <td>
              <el-input v-model="form.standardName"/>
            </td>
            <th>标准编号</th>
            <td>
              <el-input v-model="form.standardCode"/>
            </td>
          </tr>
          <tr>
            <th>验证项目</th>
            <td colspan="3">
              <el-input v-model="form.verifyItem"/>
            </td>
          </tr>
          </tbody>
        </table>
        <table class="verify-table content-table">
          <colgroup>
            <col style="width: 16%"/>
            <col style="width: 36%"/>
            <col style="width: 36%"/>
            <col style="width: 12%"/>
          </colgroup>
          <thead>
          <tr>
            <th>验证内容</th>
            <th>方法要求</th>
            <th>实验室能力</th>
            <th>是否满足</th>
          </tr>
          </thead>
          <tbody>
          <tr v-for="(item, index) in content.checks" :key="item.key">
            <th>{{ index < 7 ? `${index + 1}. ${item.label}` : item.label }}</th>
            <td>
              <el-input v-model="item.requirement" type="textarea" :rows="3"/>
            </td>
            <td>
              <el-input v-model="item.capability" type="textarea" :rows="3"/>
              <div v-if="item.key === 'personnel'" class="row-extra">
                <span>检测人员</span>
                <el-select v-model="form.confirmUser" multiple :multiple-limit="5" placeholder="请选择检测人员">
                  <el-option v-for="user in userList" :key="user.id" :label="user.name" :value="user.id"/>
                </el-select>
                <el-link v-if="operationType !== 'add'" type="primary" @click="viewWorkPermit">查看上岗证</el-link>
              </div>
              <div v-if="item.key === 'equipment'" class="row-extra">
                <el-link type="primary" @click="viewDevice">查看设备</el-link>
                <el-link v-if="operationType !== 'add'" type="primary" @click="viewCalibrationsFileDia">查看校准证书
                </el-link>
              </div>
            </td>
            <td class="choice-cell">
              <el-radio-group v-model="item.satisfied">
                <el-radio :value="1">是</el-radio>
                <el-radio :value="0">否</el-radio>
              </el-radio-group>
            </td>
          </tr>
          <tr>
            <th>验证结论</th>
            <td colspan="3">
              <el-input v-model="content.conclusion" type="textarea" :rows="4"/>
            </td>
          </tr>
          <tr v-for="decision in decisions" :key="decision.key">
            <th>{{ decision.label }}</th>
            <td colspan="3">
              <div class="decision-row">
                <el-radio-group v-model="content[decision.key]">
                  <el-radio value="同意使用">同意使用</el-radio>
                  <el-radio value="不能使用">不能使用</el-radio>
                  <el-radio value="限制使用">限制使用</el-radio>
                </el-radio-group>
                <span>{{ decision.personLabel }}</span>
                <el-input v-model="content[decision.personKey]" class="person-input"/>
                <span>日期</span>
                <el-date-picker v-model="content[decision.dateKey]" type="date" value-format="YYYY-MM-DD"
                                placeholder="选择日期"/>
              </div>
            </td>
          </tr>
          </tbody>
        </table>
        <div v-if="operationType === 'edit'" class="attachments">
          <span>附件1 åŽŸå§‹è®°å½•ã€é™„ä»¶2 éªŒè¯ç»“æžœ</span>
          <el-button size="small" @click="viewTestRecord">查看及上传附件</el-button>
        </div>
      </div>
      <template #footer>
        <el-button @click="closeDia">取消</el-button>
        <el-button v-if="operationType !== 'view'" :loading="loading" type="primary" @click="submit">提交</el-button>
      </template>
    </el-dialog>
    <ViewDeviceDialog v-if="deviceVisible" ref="device" @closDeviceDia="deviceVisible = false"
                      @handleDeviceInfo="setDevices"/>
    <ViewTestRecord v-if="recordVisible" ref="record"/>
    <ViewWorkPermitDia v-if="permitVisible" ref="permit"/>
    <CalibrationsFileDia v-if="calibrationVisible" ref="calibration"/>
  </div>
</template>
<script>
import ViewDeviceDialog from './ViewDeviceDialog.vue'
import ViewTestRecord from './ViewTestRecord.vue'
import ViewWorkPermitDia from './viewWorkPermitDia.vue'
import CalibrationsFileDia from './calibrationsFileDia.vue'
import {addMethodVerify, getMethodVerifyOne, updateMethodVerify} from '@/api/cnas/process/method/methodVerification'
import {selectUserCondition} from '@/api/cnas/process/method/methodVerification'
const labels = [
  ['personnel', '人员能力'], ['equipment', '检测设备'], ['reagents', '试剂要求'],
  ['conditions', '试验条件'], ['sample', '样品处置'], ['steps', '试验步骤'],
  ['processing', '数据处理'], ['qualityControl', '质量控制方法'], ['result', '方法验证结果']
]
const decisions = [
  {key: 'reviewDecision', label: '评审意见', personKey: 'reviewer', personLabel: '评审人员', dateKey: 'reviewDate'},
  {
    key: 'approvalDecision',
    label: '审批意见',
    personKey: 'approver',
    personLabel: '技术负责人',
    dateKey: 'approvalDate'
  }
]
function emptyContent() {
  return {
    checks: labels.map(([key, label]) => ({key, label, requirement: '', capability: '', satisfied: null})),
    conclusion: '',
    reviewDecision: '',
    reviewer: '',
    reviewDate: '',
    approvalDecision: '',
    approver: '',
    approvalDate: ''
  }
}
export default {
  name: 'MethodVerificationWordForm',
  components: {ViewDeviceDialog, ViewTestRecord, ViewWorkPermitDia, CalibrationsFileDia},
  props: {operationType: {type: String, default: 'add'}},
  computed: {
    dialogTitle() {
      if (this.operationType === 'view') return '查看方法验证'
      return this.operationType === 'edit' ? '编辑方法验证' : '新增方法验证'
    }
  },
  data() {
    return {
      visible: false, loading: false, decisions,
      form: {standardName: '', standardCode: '', verifyItem: '', confirmUser: [], machineAttachmentList: []},
      content: emptyContent(), info: {}, userList: [],
      deviceVisible: false, recordVisible: false, permitVisible: false, calibrationVisible: false
    }
  },
  methods: {
    openDia(row = {}) {
      this.visible = true
      this.info = row || {}
      selectUserCondition().then(res => {
        if (res.code === 200) this.userList = res.data || []
      })
      if (this.operationType !== 'add') this.load(row)
    },
    load(row) {
      getMethodVerifyOne({methodVerifyId: row.methodVerifyId}).then(res => {
        if (res.code !== 200) return
        this.form = {...res.data, confirmUser: res.data.confirmUser ? res.data.confirmUser.split(',').map(Number) : []}
        try {
          const saved = JSON.parse(res.data.verificationContent || '{}')
          const defaults = emptyContent()
          this.content = {
            ...defaults, ...saved, checks: defaults.checks.map(item => ({
              ...item, ...(saved.checks || []).find(check => check.key === item.key)
            }))
          }
        } catch (_) {
          this.content = emptyContent()
          this.$message.error('验证内容格式错误,请联系管理员')
        }
      })
    },
    submit() {
      if (!this.form.standardName?.trim() || !this.form.standardCode?.trim() || !this.form.verifyItem?.trim()) {
        this.$message.warning('请填写标准名称、标准编号和验证项目')
        return
      }
      this.loading = true
      const payload = {
        ...this.form, operationType: 1,
        confirmUser: (this.form.confirmUser || []).join(','),
        verificationContent: JSON.stringify(this.content)
      }
      const request = this.operationType === 'edit' ? updateMethodVerify : addMethodVerify
      request(payload).then(res => {
        if (res.code === 200) {
          this.$message.success('操作成功');
          this.closeDia()
        }
      }).finally(() => {
        this.loading = false
      })
    },
    openChild(flag, refName, data) {
      this[flag] = true
      this.$nextTick(() => this.$refs[refName]?.openDia(data))
    },
    viewWorkPermit() {
      if (!this.form.confirmUser?.length && !this.form.workFileList?.length) {
        this.$message.warning('请先选择检测人员')
        return
      }
      this.openChild('permitVisible', 'permit', this.operationType === 'view' ? this.form : this.form.confirmUser)
    },
    viewDevice() {
      this.openChild('deviceVisible', 'device', this.form)
    },
    viewCalibrationsFileDia() {
      this.openChild('calibrationVisible', 'calibration', this.form)
    },
    viewTestRecord() {
      this.openChild('recordVisible', 'record', this.info)
    },
    setDevices(list) {
      this.deviceVisible = false;
      this.form.machineAttachmentList = list
    },
    closeDia() {
      this.visible = false;
      this.$emit('closeDia')
    }
  }
}
</script>
<style scoped>
.form-body {
  max-height: 70vh;
  overflow: auto;
}
.verify-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 14px;
  table-layout: fixed;
}
.verify-table th, .verify-table td {
  border: 1px solid #c5cbd0;
  padding: 10px;
  vertical-align: middle;
}
.verify-table th {
  background: #f5f7f8;
  font-weight: 500;
  text-align: center;
}
.choice-cell {
  text-align: center;
}
.row-extra, .decision-row, .attachments {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.person-input {
  width: 140px;
}
.attachments {
  margin: 16px 0;
}
</style>