| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | title="实验方案详情" |
| | | :visible="dialogVisible" |
| | | width="80%" |
| | | :close-on-click-modal="false" |
| | | @close="handleClose" |
| | | > |
| | | <el-dialog title="实验方案详情" :visible="dialogVisible" width="90%" top="5vh" :close-on-click-modal="false" @close="handleClose"> |
| | | <div class="approval-dialog"> |
| | | <!-- 左侧审批内容 --> |
| | | <div class="approval-content"> |
| | | <Card class="approval-content-card"> |
| | | <template style="position: relative"> |
| | | <el-form |
| | | ref="form" |
| | | :model="form" |
| | | :rules="rules" |
| | | inline |
| | | label-position="top" |
| | | |
| | | > |
| | | <el-form ref="form" :model="form" :rules="rules" inline label-position="top"> |
| | | <div class="header-title" style="margin-bottom: 38px"> |
| | | <div style="display: flex; align-items: center; gap: 13px"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>所属实验调度</div> |
| | | </div> |
| | | <el-button @click="handleStopExperiment" type="danger" v-if='form.status != 2 && form.status != 3 && form.status != 4'> |
| | | <el-button @click="handleStopExperiment" type="danger" |
| | | v-if='form.status != 2 && form.status != 3 && form.status != 4 && userRole == 3'> |
| | | 申请终止实验</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | |
| | | <div style="padding-left: 25px;margin-top: 28px;"> |
| | | <el-form-item prop="experimentDate" label="试验日期"> |
| | | <el-date-picker v-model="form.experimentDate" type="datetime" :disabled="true" placeholder="选择日期时间"> |
| | | <el-date-picker v-model="form.experimentDate" type="datetime" :disabled="true" placeholder="选择日期时间"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | </div> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="content-box"> |
| | | <AiEditor |
| | | ref="purposeEditor" |
| | | :readOnly="true" |
| | | :value="form.experimentObjective" |
| | | height="200px" |
| | | placeholder="请输入实验目的..." |
| | | /> |
| | | <AiEditor ref="purposeEditor" :readOnly="true" :value="form.experimentObjective" height="400px" |
| | | placeholder="请输入实验目的..." /> |
| | | </div> |
| | | |
| | | <div class="header-title" style="margin-bottom: 38px"> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="content-box"> |
| | | <AiEditor |
| | | ref="processEditor" |
| | | :readOnly="true" |
| | | :value="form.experimentParamRoute" |
| | | height="200px" |
| | | placeholder="请输入工艺参数及路线..." |
| | | /> |
| | | <AiEditor ref="processEditor" :readOnly="true" :value="form.experimentParamRoute" height="400px" |
| | | placeholder="请输入工艺参数及路线..." /> |
| | | </div> |
| | | |
| | | <div class="header-title" style="margin-bottom: 38px"> |
| | |
| | | <div>三、实验材料及设备</div> |
| | | </div> |
| | | </div> |
| | | <DynamicComponent |
| | | ref="materialComponent" |
| | | title="实验材料" |
| | | :dialogCanEdit="false" |
| | | :dataSource="form.experimentMaterial" |
| | | :editable="false" |
| | | /> |
| | | <DynamicComponent |
| | | ref="equipmentComponent" |
| | | title="实验所用设备" |
| | | :dialogCanEdit="false" |
| | | :dataSource="form.experimentDevice" |
| | | :editable="false" |
| | | /> |
| | | <DynamicComponent ref="materialComponent" title="实验材料" :dialogCanEdit="false" |
| | | :dataSource="form.experimentMaterial" :editable="false" /> |
| | | <DynamicComponent ref="equipmentComponent" title="实验所用设备" :dialogCanEdit="false" |
| | | :dataSource="form.experimentDevice" :editable="false" /> |
| | | |
| | | <div class="header-title" style="margin-bottom: 38px"> |
| | | <div class="header-title-left"> |
| | |
| | | 步骤{{ idx + 1 }}:{{ item.stepName }} |
| | | </div> |
| | | </div> |
| | | <DynamicComponent |
| | | :dialogCanEdit="false" |
| | | :ref="'stepContent' + idx" |
| | | :dataSource="item.content" |
| | | :editable="false" |
| | | /> |
| | | <DynamicComponent :dialogCanEdit="false" :ref="'stepContent' + idx" :dataSource="item.content" |
| | | :editable="false" /> |
| | | </div> |
| | | </el-form> |
| | | </template> |
| | |
| | | <!-- 右侧审批流程 --> |
| | | <div class="approval-flow" v-if="showApprovalFlow"> |
| | | <div class="flow-content"> |
| | | <approval-process |
| | | :processData="approvalProcessData" |
| | | /> |
| | | <approval-process :processData="approvalProcessData" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | <SignatureCanvas |
| | | :visible="signatureDialogVisible" |
| | | @confirm="handleSignatureConfirm" |
| | | /> |
| | | <SignatureCanvas :visible="signatureDialogVisible" @confirm="handleSignatureConfirm" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | selectedParticipants: [], // 实验参与人员 |
| | | showApprovalFlow: false, |
| | | approvalProcessData: [], |
| | | userRole: '', |
| | | }; |
| | | }, |
| | | watch: { |
| | |
| | | if (val && this.data && this.data.id) { |
| | | // 弹窗打开时,确保数据已获取 |
| | | this.getPlanDetail(this.data.id); |
| | | const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}'); |
| | | this.userRole = userInfo.roleType || ''; |
| | | } |
| | | }, |
| | | immediate: true, |
| | |
| | | this.signatureDialogVisible = true; |
| | | }, |
| | | handleSignatureConfirm(imageData) { |
| | | console.log("imageData imageData", imageData); |
| | | this.signatureDialogVisible = false; |
| | | this.imgSrc = imageData; |
| | | }, |
| | |
| | | this.handleClose(); |
| | | return; |
| | | } |
| | | if(res.stopReason){ |
| | | if (res.stopReason) { |
| | | this.showApprovalFlow = true; |
| | | //中止实验申请 |
| | | let processData = []; |
| | | processData.push({ |
| | | type: "primary", |
| | | let processData = []; |
| | | processData.push({ |
| | | type: "primary", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "提交人:", value: res.updateBy || "" }, |
| | | { label: "提交时间:", value: res.createTime || "" }, |
| | | ], |
| | | }); |
| | | if (res.status == 4 || res.status == 3) { |
| | | processData.push({ |
| | | type: 'primary', |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "提交人:", value: res.updateBy || "" }, |
| | | { label: "提交时间:", value: res.createTime || "" }, |
| | | ], |
| | | }); |
| | | if(res.status==4||res.status==3){ |
| | | processData.push({ |
| | | type:'primary', |
| | | mode: "list", |
| | | fields: [ |
| | | { |
| | | label: "审核结果:", |
| | | value: |
| | | res.status ==3 |
| | | ? "通过" |
| | | : res.status ==4 |
| | | { |
| | | label: "审核结果:", |
| | | value: |
| | | res.status == 3 |
| | | ? "通过" |
| | | : res.status == 4 |
| | | ? "驳回" |
| | | : "待审批", |
| | | }, |
| | | { label: "审批意见:", value: res.auditRemark || "" }, |
| | | { label: "审核人:", value: res.auditPersonName || "" }, |
| | | { label: "审核时间:", value: res.auditTime || "" }, |
| | | ], |
| | | }); |
| | | }else{ |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "等待审核"}, |
| | | ], |
| | | }); |
| | | } |
| | | this.approvalProcessData = processData; |
| | | }, |
| | | { label: "审批意见:", value: res.auditRemark || "" }, |
| | | { label: "审核人:", value: res.auditPersonName || "" }, |
| | | { label: "审核时间:", value: res.auditTime || "" }, |
| | | ], |
| | | }); |
| | | } else { |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "等待审核" }, |
| | | ], |
| | | }); |
| | | } |
| | | this.approvalProcessData = processData; |
| | | } |
| | | |
| | | // 填充基本表单数据 |
| | |
| | | experimentObjective: res.experimentObjective || '', |
| | | experimentParamRoute: res.experimentParamRoute || '', |
| | | }; |
| | | |
| | | |
| | | // 构建实验调度数据 |
| | | if (res.experimentDispatch) { |
| | | this.dispatchData = [res.experimentDispatch]; |
| | | } |
| | | |
| | | |
| | | // 填充组别数据 |
| | | if (res.dispatchId) { |
| | | try { |
| | |
| | | console.error('获取组别列表失败:', err); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 填充实验材料和设备 |
| | | if (res.experimentMaterial) { |
| | | try { |
| | |
| | | ? JSON.parse(res.experimentMaterial) |
| | | : res.experimentMaterial; |
| | | this.form.experimentMaterial = materialData; |
| | | |
| | | |
| | | // 为DynamicComponent设置初始数据 |
| | | // this.$nextTick(() => { |
| | | // if (this.$refs.materialComponent) { |
| | |
| | | console.error('解析实验材料数据失败:', err); |
| | | } |
| | | } |
| | | |
| | | |
| | | if (res.experimentDevice) { |
| | | try { |
| | | const deviceData = typeof res.experimentDevice === 'string' |
| | | ? JSON.parse(res.experimentDevice) |
| | | : res.experimentDevice; |
| | | this.form.experimentDevice = deviceData; |
| | | |
| | | |
| | | // 为DynamicComponent设置初始数据 |
| | | this.$nextTick(() => { |
| | | // if (this.$refs.equipmentComponent) { |
| | |
| | | console.error('解析实验设备数据失败:', err); |
| | | } |
| | | } |
| | | |
| | | |
| | | // 填充实验步骤 |
| | | if (res.experimentStepRecord) { |
| | | try { |
| | | const stepsData = typeof res.experimentStepRecord === 'string' |
| | | ? JSON.parse(res.experimentStepRecord) |
| | | : res.experimentStepRecord; |
| | | |
| | | |
| | | this.stepList = (stepsData || []).map(step => ({ |
| | | stepName: step.stepName, |
| | | content: step.content |
| | | })); |
| | | |
| | | |
| | | // 设置步骤内容的初始数据 |
| | | this.$nextTick(() => { |
| | | // this.stepList.forEach((step, index) => { |
| | |
| | | this.stepList = []; |
| | | } |
| | | } |
| | | |
| | | |
| | | // 设置实验人员 |
| | | if (res.experimentSchemePersons) { |
| | | try { |
| | | const participantsData = typeof res.experimentSchemePersons === 'string' |
| | | ? JSON.parse(res.experimentSchemePersons) |
| | | : res.experimentSchemePersons; |
| | | |
| | | |
| | | this.selectedParticipants = participantsData || []; |
| | | } catch (err) { |
| | | console.error('解析实验人员数据失败:', err); |
| | | this.selectedParticipants = []; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | // 更新编辑器内容 |
| | | this.$nextTick(() => { |
| | | if (this.$refs.purposeEditor) { |
| | |
| | | this.$refs.processEditor.setContent(this.form.experimentParamRoute); |
| | | } |
| | | }); |
| | | |
| | | |
| | | } catch (error) { |
| | | console.error("获取方案详情失败:", error); |
| | | this.$message.error("获取方案详情失败"); |
| | |
| | | } |
| | | |
| | | ::v-deep .el-dialog__body { |
| | | padding: 20px; |
| | | // padding: 20px; |
| | | |
| | | max-height: 80vh; |
| | | overflow: hidden; |
| | | } |
| | |
| | | |
| | | .approval-dialog { |
| | | display: flex; |
| | | height: 60vh; |
| | | padding:20px; |
| | | min-height: 60vh; |
| | | max-height: 78vh; |
| | | padding: 20px; |
| | | overflow: hidden; |
| | | |
| | | @media screen and (max-width: 1200px) { |
| | | flex-direction: column; |
| | | height: auto; |
| | | |
| | | .approval-content, .approval-flow { |
| | | |
| | | .approval-content, |
| | | .approval-flow { |
| | | width: 100%; |
| | | margin-right: 0; |
| | | margin-bottom: 20px; |
| | |
| | | |
| | | .approval-flow { |
| | | flex: 3; |
| | | min-width: 350px; |
| | | padding: 40px 20px; |
| | | max-width: 305px; |
| | | padding: 20px 0px; |
| | | background: #ffffff; |
| | | box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08); |
| | | border-radius: 10px; |
| | |
| | | } |
| | | |
| | | .approval-content-card { |
| | | height: calc(100% - 100px) !important; |
| | | height: calc(100% - 10px) !important; |
| | | box-shadow: none !important; |
| | | } |
| | | |
| | |
| | | border: 1px solid #dcdfe6; |
| | | |
| | | &:nth-child(1) { |
| | | background: linear-gradient( |
| | | to bottom, |
| | | rgba(4, 156, 154, 0.2) 0%, |
| | | rgba(5, 242, 194, 0) 70% |
| | | ); |
| | | background: linear-gradient(to bottom, |
| | | rgba(4, 156, 154, 0.2) 0%, |
| | | rgba(5, 242, 194, 0) 70%); |
| | | } |
| | | |
| | | &:nth-child(2) { |
| | | background: linear-gradient( |
| | | to bottom, |
| | | rgba(5, 160, 193, 0.2) 0%, |
| | | rgba(5, 242, 194, 0) 70% |
| | | ); |
| | | background: linear-gradient(to bottom, |
| | | rgba(5, 160, 193, 0.2) 0%, |
| | | rgba(5, 242, 194, 0) 70%); |
| | | } |
| | | |
| | | &:nth-child(3) { |
| | | background: linear-gradient( |
| | | to bottom, |
| | | rgba(255, 77, 79, 0.2) 0%, |
| | | rgba(255, 242, 194, 0) 70% |
| | | ); |
| | | background: linear-gradient(to bottom, |
| | | rgba(255, 77, 79, 0.2) 0%, |
| | | rgba(255, 242, 194, 0) 70%); |
| | | } |
| | | |
| | | &:nth-child(4) { |
| | | background: linear-gradient( |
| | | to bottom, |
| | | rgba(250, 199, 20, 0.21) 0%, |
| | | rgba(255, 242, 194, 0) 70% |
| | | ); |
| | | background: linear-gradient(to bottom, |
| | | rgba(250, 199, 20, 0.21) 0%, |
| | | rgba(255, 242, 194, 0) 70%); |
| | | } |
| | | |
| | | .member-item { |
| | |
| | | .step-list { |
| | | background: #eff8fa; |
| | | padding: 20px; |
| | | |
| | | |
| | | .step-list-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | padding: 25px; |
| | | background: #ffffff; |
| | | |
| | | |
| | | .step-list-item-title { |
| | | font-weight: 500; |
| | | font-size: 14px; |
| | |
| | | margin-bottom: 20px; |
| | | width: 65%; |
| | | display: flex; |
| | | |
| | | |
| | | .content-box-left { |
| | | flex: 1; |
| | | |
| | | div { |
| | | padding: 10px 0; |
| | | } |
| | | } |
| | | |
| | | |
| | | .content-box-right { |
| | | flex: 1; |
| | | |
| | | div { |
| | | padding: 10px 0; |
| | | } |