| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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 === 'edit'" 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 === 'edit'" 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.$message.warning('请å
éæ©æ£æµäººå') |
| | | return |
| | | } |
| | | this.openChild('permitVisible', 'permit', 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> |