| src/api/cnas/process/method/methodVerification.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/CNAS/personnel/personnelInfo/components/mandateAdd.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/CNAS/process/method/methodVerification/component/viewWorkPermitDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/CNAS/process/method/methodVerification/component/wordFormDIa.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/CNAS/process/method/methodVerification/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| vite.config.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/cnas/process/method/methodVerification.js
@@ -38,6 +38,15 @@ }); } // æå½åæéæ£æµäººå宿¶è¯»åä»»èææè¯ä¹¦ export function getCurrentWorkFiles(query) { return request({ url: '/processMethodVerify/getCurrentWorkFiles', method: 'get', params: query, }) } // ä¿®æ¹æ åæ¹æ³éªè¯ export function updateMethodVerify(data) { return request({ src/views/CNAS/personnel/personnelInfo/components/mandateAdd.vue
@@ -17,10 +17,10 @@ </el-input> </el-form-item > <el-form-item label="被任è人å" prop="userId"> <el-select v-model="form.userId" placeholder="è¯·éæ©"> <el-select v-model="form.userId" filterable placeholder="è¯·éæ©"> <el-option v-for="(item, index) in userList" :key="index" v-for="item in userList" :key="item.id" :label="item.name" :value="item.id" ></el-option> @@ -141,9 +141,14 @@ * @desc è·åç¨æ·ä¿¡æ¯ */ async getUserList() { selectUserCondition({type: 2}).then((res) => { this.userList = res.data; }) try { const res = await selectUserCondition() if (res.code !== 200) throw new Error('人åå表æ¥å£è¿å失败') this.userList = Array.isArray(res.data) ? res.data : [] } catch (error) { this.userList = [] this.$message.error('人åå表å 载失败ï¼è¯·ç¨åéè¯') } }, /** * @desc æäº¤è¡¨å src/views/CNAS/process/method/methodVerification/component/viewWorkPermitDia.vue
@@ -2,23 +2,25 @@ <div> <el-dialog v-model="filesDialogVisible" title="æ¥çä¸å²è¯" width="80%" @closed="closeFilesLook"> <div> <el-alert v-if="!tableLoading && tableData.length === 0" type="info" :closable="false" title="æéæ£æµäººåææ ä»»èææè®°å½ï¼è¯·æ ¸å¯¹è¢«ä»»è人å䏿£æµäººåæ¯å¦ä¸ºåä¸äººã"/> <limsTable ref="yearTable" :column="columnData" :height="'calc(100vh - 400px)'" :highlightCurrentRow="true" :table-data="tableData" :table-loading="tableLoading" style="margin-top: 0.5em;"> ref="yearTable" :column="columnData" :height="'calc(100vh - 400px)'" :highlightCurrentRow="true" :table-data="tableData" :table-loading="tableLoading" style="margin-top: 0.5em;"> </limsTable> </div> </el-dialog> <el-dialog v-model="lookDialogVisible" fullscreen title="æ¥çéä»¶" top="5vh" width="800px"> v-model="lookDialogVisible" fullscreen title="æ¥çéä»¶" top="5vh" width="800px"> <filePreview v-if="lookDialogVisible" :currentFile="{}" :fileUrl="javaApi+'/img/'+currentInfo.fileUrl" style="max-height: 90vh;overflow-y: auto;"/> :fileUrl="fileUrl(currentInfo)" style="max-height: 90vh;overflow-y: auto;"/> </el-dialog> </div> </template> @@ -27,11 +29,12 @@ import file from '@/utils/file'; import filePreview from '@/components/Preview/filePreview.vue'; import limsTable from '@/components/Table/lims-table.vue' import {getCurrentWorkFiles} from '@/api/cnas/process/method/methodVerification' export default { name: 'viewWorkPermitDia', // import å¼å ¥çç»ä»¶éè¦æ³¨å ¥å°å¯¹è±¡ä¸æè½ä½¿ç¨ components: { filePreview, limsTable }, components: {filePreview, limsTable}, data() { // è¿éåæ¾æ°æ® return { @@ -74,7 +77,7 @@ ], tableData: [], info: {}, currentInfo:{}, currentInfo: {}, lookDialogVisible: false, }; }, @@ -83,27 +86,60 @@ }, // æ¹æ³éå methods: { openDia(row) { this.filesDialogVisible = true this.info = row this.tableData = this.info.workFileList fileUrl(row) { const image = /\.(png|jpe?g|gif|bmp|webp)$/i.test(row.fileUrl || '') return this.javaApi + (image ? '/img/' : '/word/') + row.fileUrl }, closeFilesLook () { // 两ç§ç¨æ³ï¼æ°ç»=æ£æµäººåidï¼å®æ¶æ¥è¯¢ï¼ï¼è¡å¯¹è±¡=ä¼å å±ç¤ºå·²ä¿åçä¸å²è¯ï¼å ¶æ¬¡æå·²éæ£æµäººå宿¶æ¥è¯¢ openDia(payload = {}) { this.filesDialogVisible = true this.tableData = [] if (Array.isArray(payload)) { this.loadCurrentFiles(payload) return } this.info = payload || {} if (Array.isArray(payload.workFileList) && payload.workFileList.length) { this.tableData = payload.workFileList return } this.loadCurrentFiles(Array.isArray(payload.confirmUser) ? payload.confirmUser : []) }, loadCurrentFiles(userIds) { if (!userIds.length) return this.tableLoading = true getCurrentWorkFiles({userIds: userIds.join(',')}).then(res => { if (res.code === 200) this.tableData = res.data || [] }).catch(() => { this.$message.error('ä¸å²è¯è¯»å失败ï¼è¯·ç¨åéè¯') }).finally(() => { this.tableLoading = false }) }, closeFilesLook() { this.filesDialogVisible = false }, // æ¥çæä»¶ handleLook(row){ handleLook(row) { if (!row.fileUrl) { this.$message.warning('该人åå·²æä»»èææè®°å½ï¼ä½å°æªä¸ä¼ ä¸å²è¯ä¹¦æä»¶') return } this.currentInfo = row this.lookDialogVisible = true }, // ä¸è½½ upload (row) { upload(row) { if (!row.fileUrl) { this.$message.warning('该人åå·²æä»»èææè®°å½ï¼ä½å°æªä¸ä¼ ä¸å²è¯ä¹¦æä»¶') return } let url = ''; if(row.type==1){ url = this.javaApi+'/img/'+row.fileUrl file.downloadIamge(url,row.fileName) }else{ url = this.javaApi+'/word/'+row.fileUrl if (/\.(png|jpe?g|gif|bmp|webp)$/i.test(row.fileUrl || '')) { url = this.javaApi + '/img/' + row.fileUrl file.downloadIamge(url, row.fileName) } else { url = this.javaApi + '/word/' + row.fileUrl const link = document.createElement('a'); link.href = url; link.download = row.fileName; 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 === '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> src/views/CNAS/process/method/methodVerification/index.vue
@@ -3,8 +3,8 @@ <div style="display: flex;justify-content: space-between"> <div style="display: flex;"> <div style="margin-bottom: 18px;margin-right: 10px;display: flex;align-items: center;line-height: 32px;"> <span style="width: 88px;font-size: 14px;font-weight: 700;color: var(--lims-text-2);">æ åæ¹æ³</span> <el-input size="small" placeholder="请è¾å ¥" clearable v-model="searchForm.methodName" <span style="width: 88px;font-size: 14px;font-weight: 700;color: var(--lims-text-2);">æ ååç§°</span> <el-input size="small" placeholder="请è¾å ¥" clearable v-model="searchForm.standardName" @keyup.enter="searchList"></el-input> </div> <div style="line-height: 30px;"> @@ -22,24 +22,26 @@ @pagination="pagination"> </limsTable> </div> <formDIa v-if="formDIa" ref="formDIa" :operationType="operationType" @closeDia="closeDia"></formDIa> <component :is="isWordForm ? 'wordFormDIa' : 'formDIa'" v-if="formDIa" ref="formDIa" :operationType="operationType" @closeDia="closeDia" /> </div> </template> <script> import limsTable from '@/components/Table/lims-table.vue' import formDIa from './component/formDIa.vue'; import wordFormDIa from './component/wordFormDIa.vue'; import { delMethodVerify, exportMethodVerify, pagesMethodVerify } from '@/api/cnas/process/method/methodVerification' export default { name: 'MethodVerification', // import å¼å ¥çç»ä»¶éè¦æ³¨å ¥å°å¯¹è±¡ä¸æè½ä½¿ç¨ components: { limsTable, formDIa }, components: { limsTable, formDIa, wordFormDIa }, data() { // è¿éåæ¾æ°æ® return { searchForm: { methodName: '', standardName: '', operationType: 1, }, options: [ @@ -48,18 +50,18 @@ ], tableColumn: [ { label: 'æ åæ¹æ³', prop: 'methodName', label: 'æ ååç§°', prop: 'standardName', minWidth: '100' }, { label: 'éªè¯åå ', prop: 'verifyReason', label: 'æ åç¼å·', prop: 'standardCode', minWidth: '100' }, { label: 'ä¸»è¦ææ¯åå', prop: 'technologyChange', label: 'éªè¯é¡¹ç®', prop: 'verifyItem', minWidth: '100' }, { @@ -110,6 +112,7 @@ total: 0, formDIa: false, operationType: '', isWordForm: true, }; }, mounted() { @@ -120,7 +123,7 @@ // æ¥è¯¢å表 searchList() { const entity = { methodName: this.searchForm.methodName, standardName: this.searchForm.standardName, operationType: this.searchForm.operationType, } const page = this.page @@ -158,12 +161,13 @@ }, // éç½®æ¥è¯¢æ¡ä»¶ resetSearchForm() { this.searchForm.methodName = ''; this.searchForm.standardName = ''; this.searchList() }, openFormDia(type, row) { this.formDIa = true this.operationType = type this.isWordForm = type === 'add' || !!row?.standardCode this.$nextTick(() => { this.$refs.formDIa.openDia(row) }) vite.config.js
@@ -7,7 +7,7 @@ const env = loadEnv(mode, process.cwd()) const { VITE_APP_ENV } = env // å端æ¥å£ï¼é»è®¤æå ç½å ±äº«æå¡ï¼æ¬å°èµ·å端æ¶ç¨ VITE_APP_PROXY_TARGET è¦ç const baseUrl = env.VITE_APP_PROXY_TARGET || 'http://192.168.0.24:9509/lims' const baseUrl = env.VITE_APP_PROXY_TARGET || 'http://127.0.0.1:9509' return { // é¨ç½²ç产ç¯å¢åå¼åç¯å¢ä¸çURLã // é»è®¤æ åµä¸ï¼vite ä¼åè®¾ä½ çåºç¨æ¯è¢«é¨ç½²å¨ä¸ä¸ªååçæ ¹è·¯å¾ä¸ @@ -61,6 +61,7 @@ server: { port: 80, host: true, allowedHosts: ['.trycloudflare.com'], open: true, proxy: { // https://cn.vitejs.dev/config/#server-proxy