| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564 |
- <!--
- 危险作业票详情(pcView)
- 布局与字段顺序参考 EHS 子应用「危险作业票」动火作业查看态
- (kd-aiot-frontend-ehs/src/views/DangerousWorkList/add.vue,isView=true):
- 所属危险作业 / 作业类型 / 申请单位 / 申请人 / 作业地点
- / 作业开始时间 / 作业结束时间 / 作业票模板 / 作业票内容 / 备注
- 作业票内容按 EHS 内置作业票模板渲染(不同作业类型套用不同模板);
- 页面用 tab 区分「作业票信息」与「后续环节」(tab 栏在上方),默认选中「作业票信息」;
- 动火、受限空间、高处作业、吊装作业、临时用电作业、动土作业、断路作业、盲板抽堵作业八类作业共用本页面与 submit.vue,按作业类型分发到各自的组件:
- 动火作业 fireFlowNodes.js + components/fireTicketDetail.vue + components/flowNodeForm.vue
- 受限空间 confinedSpaceFlowNodes.js + components/confinedSpaceFlow.vue
- 高处作业 heightFlowNodes.js + components/heightFlow.vue
- 吊装作业 hoistingFlowNodes.js + components/hoistingFlow.vue
- 临时用电 electricityFlowNodes.js + components/electricityFlow.vue
- 动土作业 breakGroundFlowNodes.js + components/breakGroundFlow.vue
- 断路作业 breakRoadFlowNodes.js + components/breakRoadFlow.vue
- 盲板抽堵 blindPlateFlowNodes.js + components/blindPlateFlow.vue
- 「后续环节」tab 顶部为当前处理环节(可填写),下方为全部环节的查看内容;
- 环节填写值通过 getTableValue 提供给审批组件(submit.vue),
- 在审批通过前合并写入作业票内容(extensionJson)
- -->
- <template>
- <div class="ticket-detail" v-loading="loading">
- <!-- 概要信息 -->
- <div class="detail-summary">
- <span class="summary-title">
- <i class="el-icon-document" />
- {{ templateName || '作业票信息' }}
- <el-tag v-if="statusText" :type="statusTag" size="mini">
- {{ statusText }}
- </el-tag>
- </span>
- <div class="summary-extra">
- <span v-if="ticketCode">作业票编号:{{ ticketCode }}</span>
- <span v-if="ticket.createTime">申请时间:{{ ticket.createTime }}</span>
- <span v-if="ticket.processInstanceId">
- 流程实例:{{ ticket.processInstanceId }}
- </span>
- </div>
- </div>
- <el-tabs v-model="activeTab" type="card" class="detail-tabs">
- <!-- 作业票信息 -->
- <el-tab-pane label="作业票信息" name="info">
- <el-form
- ref="formRef"
- :model="form"
- label-width="120px"
- size="small"
- disabled
- class="el-form-box"
- >
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="所属危险作业:">
- <el-input :value="workName" disabled placeholder="-" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="作业类型:">
- <el-select
- :value="ticket.workType"
- placeholder="-"
- style="width: 100%"
- >
- <el-option
- v-for="item in workTypeOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="申请单位:">
- <el-input
- :value="ticket.applyDeptName"
- disabled
- placeholder="-"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="申请人:">
- <el-input
- :value="ticket.applicantName"
- disabled
- placeholder="-"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="作业地点:">
- <el-input
- :value="ticket.workLocation"
- disabled
- placeholder="-"
- />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="作业开始时间:">
- <el-input :value="ticket.startTime" disabled placeholder="-" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="作业结束时间:">
- <el-input :value="ticket.endTime" disabled placeholder="-" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="作业票模板:">
- <el-input :value="templateName" disabled placeholder="-" />
- </el-form-item>
- <el-form-item label="作业票内容:">
- <ticket-content-view
- v-if="template"
- :template="template"
- :extension="extension"
- />
- <div v-else class="empty-text">
- {{
- ticket.workType
- ? '未匹配到该作业类型的作业票模板,展示已保存的原始内容'
- : '暂无作业票内容'
- }}
- </div>
- <!-- 未匹配到模板时的降级展示:按 key-value 列出原始内容 -->
- <div v-if="!template && hasExtension" class="raw-extension">
- <div v-for="(value, key) in extension" :key="key" class="raw-row">
- <span class="raw-key">{{ key }}</span>
- <span class="raw-value">{{ value }}</span>
- </div>
- </div>
- </el-form-item>
- <el-form-item label="备注:">
- <el-input
- :value="remark"
- type="textarea"
- :rows="3"
- disabled
- placeholder="-"
- />
- </el-form-item>
- </el-form>
- </el-tab-pane>
- <!-- 作业类型专项内容(先适配动火作业票) -->
- <el-tab-pane
- v-if="isFireWork || currentFireNode"
- label="后续环节"
- name="flow"
- >
- <!-- 当前处理环节:可填写 -->
- <div v-if="currentFireNode" class="current-node-box">
- <flow-node-form
- ref="nodeForm"
- :node="currentFireNode"
- :value="nodeForm"
- @input="handleNodeInput"
- />
- </div>
- <div v-else class="node-tip">
- 未识别到当前处理环节,以下为全部环节的查看内容
- </div>
- <!-- 全部环节(查看态,当前环节已在上方单独展示,这里排除避免重复) -->
- <fire-ticket-detail
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- :current-node-key="currentFireNode ? currentFireNode.key : ''"
- :exclude-node-keys="currentFireNode ? [currentFireNode.key] : []"
- />
- </el-tab-pane>
- <!-- 作业类型专项内容(受限空间作业票,独立组件实现) -->
- <el-tab-pane
- v-if="isConfinedSpaceWork || currentConfinedNode"
- label="后续环节"
- name="flowConfined"
- >
- <confined-space-flow
- ref="confinedFlow"
- :node="currentConfinedNode"
- :nodes="confinedFlowNodes"
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- />
- </el-tab-pane>
- <!-- 作业类型专项内容(高处作业票,独立组件实现) -->
- <el-tab-pane
- v-if="isHeightWork || currentHeightNode"
- label="后续环节"
- name="flowHeight"
- >
- <height-flow
- ref="heightFlow"
- :node="currentHeightNode"
- :nodes="heightFlowNodes"
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- :task-label="currentTaskName || taskDefinitionKey"
- />
- </el-tab-pane>
- <!-- 作业类型专项内容(吊装作业票,独立组件实现) -->
- <el-tab-pane
- v-if="isHoistingWork || currentHoistingNode"
- label="后续环节"
- name="flowHoisting"
- >
- <hoisting-flow
- ref="hoistingFlow"
- :node="currentHoistingNode"
- :nodes="hoistingFlowNodes"
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- :task-label="currentTaskName || taskDefinitionKey"
- />
- </el-tab-pane>
- <!-- 作业类型专项内容(临时用电作业票,独立组件实现) -->
- <el-tab-pane
- v-if="isElectricityWork || currentElectricityNode"
- label="后续环节"
- name="flowElectricity"
- >
- <electricity-flow
- ref="electricityFlow"
- :node="currentElectricityNode"
- :nodes="electricityFlowNodes"
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- :task-label="currentTaskName || taskDefinitionKey"
- />
- </el-tab-pane>
- <!-- 作业类型专项内容(动土作业票,独立组件实现) -->
- <el-tab-pane
- v-if="isBreakGroundWork || currentBreakGroundNode"
- label="后续环节"
- name="flowBreakGround"
- >
- <break-ground-flow
- ref="breakGroundFlow"
- :node="currentBreakGroundNode"
- :nodes="breakGroundFlowNodes"
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- :task-label="currentTaskName || taskDefinitionKey"
- />
- </el-tab-pane>
- <!-- 作业类型专项内容(断路作业票,独立组件实现) -->
- <el-tab-pane
- v-if="isBreakRoadWork || currentBreakRoadNode"
- label="后续环节"
- name="flowBreakRoad"
- >
- <break-road-flow
- ref="breakRoadFlow"
- :node="currentBreakRoadNode"
- :nodes="breakRoadFlowNodes"
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- :task-label="currentTaskName || taskDefinitionKey"
- />
- </el-tab-pane>
- <!-- 作业类型专项内容(盲板抽堵作业票,独立组件实现) -->
- <el-tab-pane
- v-if="isBlindPlateWork || currentBlindPlateNode"
- label="后续环节"
- name="flowBlindPlate"
- >
- <blind-plate-flow
- ref="blindPlateFlow"
- :node="currentBlindPlateNode"
- :nodes="blindPlateFlowNodes"
- :ticket="ticket"
- :extension="extension"
- :variables="variables"
- :task-label="currentTaskName || taskDefinitionKey"
- />
- </el-tab-pane>
- </el-tabs>
- </div>
- </template>
- <script>
- import {
- ticketGetById,
- workGetById,
- ticketUpdate
- } from '@/api/bpm/components/dangerousWork';
- import { getDictByCode } from '@/api/sys';
- import { getWorkTicketTemplate } from './templates';
- import { resolveWorkTypeLabel, BUILT_IN_WORK_TYPES } from './workTypes';
- import { matchFireFlowNode } from './fireFlowNodes';
- import {
- getCurrentTaskInfo,
- loadProcessFormVariables,
- loadNodeValues,
- buildNodeVariables,
- buildNodePayload,
- mergeExtension,
- buildTicketUpdateParams,
- parseJsonObject
- } from './fireFlowTask';
- // 受限空间作业:独立实现,动火相关文件不做任何改动
- import {
- matchConfinedSpaceFlowNode,
- CONFINED_SPACE_FLOW_NODES
- } from './confinedSpaceFlowNodes';
- // 高处作业:独立实现,动火 / 受限空间相关文件不做任何改动
- import { matchHeightFlowNode, HEIGHT_FLOW_NODES } from './heightFlowNodes';
- // 吊装作业:独立实现,动火 / 受限空间 / 高处作业相关文件不做任何改动
- import {
- matchHoistingFlowNode,
- HOISTING_FLOW_NODES
- } from './hoistingFlowNodes';
- // 临时用电作业:独立实现,其它作业类型相关文件不做任何改动
- import {
- matchElectricityFlowNode,
- ELECTRICITY_FLOW_NODES
- } from './electricityFlowNodes';
- // 动土作业:独立实现,其它作业类型相关文件不做任何改动
- import {
- matchBreakGroundFlowNode,
- BREAK_GROUND_FLOW_NODES
- } from './breakGroundFlowNodes';
- // 断路作业:独立实现,其它作业类型相关文件不做任何改动
- import {
- matchBreakRoadFlowNode,
- BREAK_ROAD_FLOW_NODES
- } from './breakRoadFlowNodes';
- // 盲板抽堵作业:独立实现,其它作业类型相关文件不做任何改动
- import {
- matchBlindPlateFlowNode,
- BLIND_PLATE_FLOW_NODES
- } from './blindPlateFlowNodes';
- import TicketContentView from './components/ticketContentView.vue';
- import FireTicketDetail from './components/fireTicketDetail.vue';
- import FlowNodeForm from './components/flowNodeForm.vue';
- import ConfinedSpaceFlow from './components/confinedSpaceFlow.vue';
- import HeightFlow from './components/heightFlow.vue';
- import HoistingFlow from './components/hoistingFlow.vue';
- import ElectricityFlow from './components/electricityFlow.vue';
- import BreakGroundFlow from './components/breakGroundFlow.vue';
- import BreakRoadFlow from './components/breakRoadFlow.vue';
- import BlindPlateFlow from './components/blindPlateFlow.vue';
- // 作业票状态:1-待提交、2-审批中、3-已通过、4-已驳回
- const TICKET_STATUS = {
- 1: '待提交',
- 2: '审批中',
- 3: '已通过',
- 4: '已驳回'
- };
- // 作业票编号可能落在扩展数据的不同 key 上
- const TICKET_CODE_KEYS = ['permit_no', 'ticket_no', 'apply_no', 'code'];
- export default {
- name: 'TestDetail',
- components: {
- TicketContentView,
- FireTicketDetail,
- FlowNodeForm,
- ConfinedSpaceFlow,
- HeightFlow,
- HoistingFlow,
- ElectricityFlow,
- BreakGroundFlow,
- BreakRoadFlow,
- BlindPlateFlow
- },
- props: {
- // 作业票 id
- businessId: {
- default: ''
- },
- businessCode: {
- default: ''
- },
- taskId: {
- default: ''
- },
- id: {
- default: ''
- },
- taskDefinitionKey: {
- default: ''
- },
- businessType: {
- default: ''
- },
- fromUser: {
- default: ''
- },
- createTime: {
- default: ''
- }
- },
- data() {
- return {
- loading: false,
- // 当前 tab:info-作业票信息(默认)、flow-后续环节
- activeTab: 'info',
- // 作业票
- ticket: {},
- // 所属危险作业
- work: {},
- // 作业票内容(extensionJson 解析结果)
- extension: {},
- // 流程变量(流程实例 formVariables,后续环节数据来源)
- variables: {},
- // 匹配到的作业票模板
- template: null,
- // 作业类型字典(ehs_hazardous_work_type)
- workTypeDict: [],
- // el-form 的 model(查看态仅用于结构占位)
- form: {},
- // 当前待办任务的名称(任务定义 key 之外的第二重匹配依据)
- currentTaskName: '',
- // 当前环节的填写值
- nodeForm: {}
- };
- },
- computed: {
- // 作业类型名称
- workTypeName() {
- return (
- resolveWorkTypeLabel(this.ticket.workType, this.workTypeDict) || '-'
- );
- },
- // 作业类型下拉:优先后端字典,字典未配置时用内置作业类型兜底
- workTypeOptions() {
- if (this.workTypeDict.length) {
- return this.workTypeDict.map((item) => ({
- value: item.dictCode,
- label: item.dictValue
- }));
- }
- return BUILT_IN_WORK_TYPES.map((item) => ({
- value: item.code,
- label: item.name
- }));
- },
- // 所属危险作业名称(作业票详情不返回,按 workId 再查)
- workName() {
- return this.ticket.workName || this.work.workName || '';
- },
- // 作业票模板名称
- templateName() {
- return this.template?.name || '';
- },
- // 备注
- remark() {
- return this.extension.remark || '';
- },
- /**
- * 是否动火作业
- */
- isFireWork() {
- return this.template?.key === 'fire';
- },
- /**
- * 当前处理环节(动火)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- * 非动火作业直接返回 null:动火与受限空间的环节名称有重合
- * (如「气体分析」「安全交底」),不加限制会串台
- */
- currentFireNode() {
- if (!this.isFireWork) {
- return null;
- }
- return matchFireFlowNode(this.taskDefinitionKey, this.currentTaskName);
- },
- /**
- * 是否受限空间作业
- */
- isConfinedSpaceWork() {
- return this.template?.key === 'confined_space';
- },
- /**
- * 受限空间作业的全部后续环节
- */
- confinedFlowNodes() {
- return CONFINED_SPACE_FLOW_NODES;
- },
- /**
- * 当前处理环节(受限空间)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- */
- currentConfinedNode() {
- if (!this.isConfinedSpaceWork) {
- return null;
- }
- return matchConfinedSpaceFlowNode(
- this.taskDefinitionKey,
- this.currentTaskName
- );
- },
- /**
- * 是否高处作业
- */
- isHeightWork() {
- return this.template?.key === 'height';
- },
- /**
- * 高处作业的全部后续环节
- */
- heightFlowNodes() {
- return HEIGHT_FLOW_NODES;
- },
- /**
- * 当前处理环节(高处作业)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- */
- currentHeightNode() {
- if (!this.isHeightWork) {
- return null;
- }
- return matchHeightFlowNode(this.taskDefinitionKey, this.currentTaskName);
- },
- /**
- * 是否吊装作业
- */
- isHoistingWork() {
- return this.template?.key === 'hoisting';
- },
- /**
- * 吊装作业的全部后续环节
- */
- hoistingFlowNodes() {
- return HOISTING_FLOW_NODES;
- },
- /**
- * 当前处理环节(吊装作业)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- */
- currentHoistingNode() {
- if (!this.isHoistingWork) {
- return null;
- }
- return matchHoistingFlowNode(
- this.taskDefinitionKey,
- this.currentTaskName
- );
- },
- /**
- * 是否临时用电作业
- */
- isElectricityWork() {
- return this.template?.key === 'electricity';
- },
- /**
- * 临时用电作业的全部后续环节
- */
- electricityFlowNodes() {
- return ELECTRICITY_FLOW_NODES;
- },
- /**
- * 当前处理环节(临时用电作业)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- */
- currentElectricityNode() {
- if (!this.isElectricityWork) {
- return null;
- }
- return matchElectricityFlowNode(
- this.taskDefinitionKey,
- this.currentTaskName
- );
- },
- /**
- * 是否动土作业
- */
- isBreakGroundWork() {
- return this.template?.key === 'break_ground';
- },
- /**
- * 动土作业的全部后续环节
- */
- breakGroundFlowNodes() {
- return BREAK_GROUND_FLOW_NODES;
- },
- /**
- * 当前处理环节(动土作业)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- */
- currentBreakGroundNode() {
- if (!this.isBreakGroundWork) {
- return null;
- }
- return matchBreakGroundFlowNode(
- this.taskDefinitionKey,
- this.currentTaskName
- );
- },
- /**
- * 是否断路作业
- */
- isBreakRoadWork() {
- return this.template?.key === 'break_road';
- },
- /**
- * 断路作业的全部后续环节
- */
- breakRoadFlowNodes() {
- return BREAK_ROAD_FLOW_NODES;
- },
- /**
- * 当前处理环节(断路作业)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- */
- currentBreakRoadNode() {
- if (!this.isBreakRoadWork) {
- return null;
- }
- return matchBreakRoadFlowNode(
- this.taskDefinitionKey,
- this.currentTaskName
- );
- },
- /**
- * 是否盲板抽堵作业
- */
- isBlindPlateWork() {
- return this.template?.key === 'blind_plate';
- },
- /**
- * 盲板抽堵作业的全部后续环节
- */
- blindPlateFlowNodes() {
- return BLIND_PLATE_FLOW_NODES;
- },
- /**
- * 当前处理环节(盲板抽堵作业)
- * 任务定义 key 在不同平台不一致,用「任务定义 key + 任务名称」一起匹配
- */
- currentBlindPlateNode() {
- if (!this.isBlindPlateWork) {
- return null;
- }
- return matchBlindPlateFlowNode(
- this.taskDefinitionKey,
- this.currentTaskName
- );
- },
- // 作业票状态文案
- statusText() {
- return (
- this.ticket.statusName || TICKET_STATUS[this.ticket.status] || ''
- );
- },
- // 作业票状态标签色
- statusTag() {
- const typeMap = {
- 1: 'info',
- 2: 'warning',
- 3: 'success',
- 4: 'danger'
- };
- return typeMap[this.ticket.status] || 'info';
- },
- // 作业票编号
- ticketCode() {
- const key = TICKET_CODE_KEYS.find(
- (item) => this.extension[item] !== undefined && this.extension[item]
- );
- return key ? this.extension[key] : '';
- },
- // 是否有扩展内容
- hasExtension() {
- return Object.keys(this.extension).length > 0;
- }
- },
- watch: {
- businessId: {
- immediate: true,
- handler(id) {
- if (id) {
- this.load(id);
- }
- }
- },
- // 任务定义 key 变化时重新识别当前处理环节并回显其内容
- // 只回显,不切换 tab:页面默认停在「作业票信息」
- taskDefinitionKey() {
- this.loadCurrentNode();
- }
- },
- methods: {
- async load(id) {
- this.loading = true;
- this.reset();
- try {
- const [ticket, dict] = await Promise.all([
- ticketGetById(id),
- this.loadWorkTypeDict()
- ]);
- this.ticket = ticket || {};
- this.extension = parseJsonObject(this.ticket.extensionJson);
- this.workTypeDict = dict;
- // 按作业类型匹配作业票模板
- this.template = getWorkTicketTemplate(
- this.ticket.workType,
- this.workTypeName === '-' ? '' : this.workTypeName
- );
- // 作业票详情不返回所属作业名称,按 workId 再查一次
- if (this.ticket.workId) {
- try {
- this.work = (await workGetById(this.ticket.workId)) || {};
- } catch (e) {
- this.work = {};
- }
- }
- // 后续环节(风险辨识、安全措施落实、各环节意见等)取流程变量
- await this.loadVariables();
- // 识别当前处理环节并回显(只回显内容,不切换 tab)
- await this.loadCurrentNode();
- } catch (e) {
- this.$message.error(e?.message || '查询作业票详情失败');
- } finally {
- this.loading = false;
- }
- },
- // 流程变量:作业票后续环节的数据来源
- async loadVariables() {
- const { vars } = await loadProcessFormVariables(this.id);
- this.variables = vars;
- },
- /**
- * 识别当前处理环节并回显其内容
- * 任务定义 key 由流程设计器决定,取不到时用任务名称兜底
- */
- async loadCurrentNode() {
- this.currentTaskName = '';
- this.nodeForm = {};
- if (!this.id) {
- return;
- }
- const info = await getCurrentTaskInfo(this.id, this.taskDefinitionKey);
- this.currentTaskName = info.name;
- // 受限空间作业:环节内容由受限空间自己的组件回显,这里不参与
- if (this.currentConfinedNode) {
- return;
- }
- // 高处作业:环节内容由高处作业自己的组件回显,这里不参与
- if (this.currentHeightNode) {
- return;
- }
- // 吊装作业:环节内容由吊装作业自己的组件回显,这里不参与
- if (this.currentHoistingNode) {
- return;
- }
- // 临时用电作业:环节内容由临时用电自己的组件回显,这里不参与
- if (this.currentElectricityNode) {
- return;
- }
- // 动土作业:环节内容由动土作业自己的组件回显,这里不参与
- if (this.currentBreakGroundNode) {
- return;
- }
- // 断路作业:环节内容由断路作业自己的组件回显,这里不参与
- if (this.currentBreakRoadNode) {
- return;
- }
- // 盲板抽堵作业:环节内容由盲板抽堵作业自己的组件回显,这里不参与
- if (this.currentBlindPlateNode) {
- return;
- }
- const node = this.currentFireNode;
- if (!node) {
- return;
- }
- // 环节数据统一存放在作业票内容(extensionJson)里,流程变量仅作兼容兜底
- this.nodeForm = loadNodeValues(node, [this.extension, this.variables]);
- },
- // 环节填写值变化
- handleNodeInput(val) {
- this.nodeForm = val;
- },
- /**
- * 当前环节表单校验
- */
- async validateNodeForm() {
- if (this.isConfinedSpaceWork) {
- return this.validateConfinedNodeForm();
- }
- if (this.isHeightWork) {
- return this.validateHeightNodeForm();
- }
- if (this.isHoistingWork) {
- return this.validateHoistingNodeForm();
- }
- if (this.isElectricityWork) {
- return this.validateElectricityNodeForm();
- }
- if (this.isBreakGroundWork) {
- return this.validateBreakGroundNodeForm();
- }
- if (this.isBreakRoadWork) {
- return this.validateBreakRoadNodeForm();
- }
- if (this.isBlindPlateWork) {
- return this.validateBlindPlateNodeForm();
- }
- if (!this.currentFireNode || !this.$refs.nodeForm) {
- return true;
- }
- return this.$refs.nodeForm.validate();
- },
- /**
- * 受限空间作业的当前环节表单校验
- */
- async validateConfinedNodeForm() {
- if (!this.currentConfinedNode || !this.$refs.confinedFlow) {
- return true;
- }
- return this.$refs.confinedFlow.validate();
- },
- /**
- * 高处作业的当前环节表单校验
- */
- async validateHeightNodeForm() {
- if (!this.currentHeightNode || !this.$refs.heightFlow) {
- return true;
- }
- return this.$refs.heightFlow.validate();
- },
- /**
- * 吊装作业的当前环节表单校验
- */
- async validateHoistingNodeForm() {
- if (!this.currentHoistingNode || !this.$refs.hoistingFlow) {
- return true;
- }
- return this.$refs.hoistingFlow.validate();
- },
- /**
- * 临时用电作业的当前环节表单校验
- */
- async validateElectricityNodeForm() {
- if (!this.currentElectricityNode || !this.$refs.electricityFlow) {
- return true;
- }
- return this.$refs.electricityFlow.validate();
- },
- /**
- * 动土作业的当前环节表单校验
- */
- async validateBreakGroundNodeForm() {
- if (!this.currentBreakGroundNode || !this.$refs.breakGroundFlow) {
- return true;
- }
- return this.$refs.breakGroundFlow.validate();
- },
- /**
- * 断路作业的当前环节表单校验
- */
- async validateBreakRoadNodeForm() {
- if (!this.currentBreakRoadNode || !this.$refs.breakRoadFlow) {
- return true;
- }
- return this.$refs.breakRoadFlow.validate();
- },
- /**
- * 盲板抽堵作业的当前环节表单校验
- */
- async validateBlindPlateNodeForm() {
- if (!this.currentBlindPlateNode || !this.$refs.blindPlateFlow) {
- return true;
- }
- return this.$refs.blindPlateFlow.validate();
- },
- /**
- * 供审批组件(submit.vue)取当前环节数据
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getTableValue() {
- if (this.isConfinedSpaceWork) {
- return this.getConfinedTableValue();
- }
- if (this.isHeightWork) {
- return this.getHeightTableValue();
- }
- if (this.isHoistingWork) {
- return this.getHoistingTableValue();
- }
- if (this.isElectricityWork) {
- return this.getElectricityTableValue();
- }
- if (this.isBreakGroundWork) {
- return this.getBreakGroundTableValue();
- }
- if (this.isBreakRoadWork) {
- return this.getBreakRoadTableValue();
- }
- if (this.isBlindPlateWork) {
- return this.getBlindPlateTableValue();
- }
- if (!this.currentFireNode) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateNodeForm();
- const payload = buildNodePayload(this.currentFireNode, this.nodeForm);
- const variables = buildNodeVariables(
- this.currentFireNode,
- this.nodeForm
- );
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 取受限空间作业当前环节的数据(供审批组件 submit.vue 使用)
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getConfinedTableValue() {
- const flow = this.$refs.confinedFlow;
- if (!this.currentConfinedNode || !flow) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateConfinedNodeForm();
- const payload = flow.getPayload();
- const variables = flow.getVariables();
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 取高处作业当前环节的数据(供审批组件 submit.vue 使用)
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getHeightTableValue() {
- const flow = this.$refs.heightFlow;
- if (!this.currentHeightNode || !flow) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateHeightNodeForm();
- const payload = flow.getPayload();
- const variables = flow.getVariables();
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 取吊装作业当前环节的数据(供审批组件 submit.vue 使用)
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getHoistingTableValue() {
- const flow = this.$refs.hoistingFlow;
- if (!this.currentHoistingNode || !flow) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateHoistingNodeForm();
- const payload = flow.getPayload();
- const variables = flow.getVariables();
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 取临时用电作业当前环节的数据(供审批组件 submit.vue 使用)
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getElectricityTableValue() {
- const flow = this.$refs.electricityFlow;
- if (!this.currentElectricityNode || !flow) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateElectricityNodeForm();
- const payload = flow.getPayload();
- const variables = flow.getVariables();
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 取动土作业当前环节的数据(供审批组件 submit.vue 使用)
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getBreakGroundTableValue() {
- const flow = this.$refs.breakGroundFlow;
- if (!this.currentBreakGroundNode || !flow) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateBreakGroundNodeForm();
- const payload = flow.getPayload();
- const variables = flow.getVariables();
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 取断路作业当前环节的数据(供审批组件 submit.vue 使用)
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getBreakRoadTableValue() {
- const flow = this.$refs.breakRoadFlow;
- if (!this.currentBreakRoadNode || !flow) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateBreakRoadNodeForm();
- const payload = flow.getPayload();
- const variables = flow.getVariables();
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 取盲板抽堵作业当前环节的数据(供审批组件 submit.vue 使用)
- * 取数的同时把环节内容合并进作业票内容(extensionJson)并落库,
- * 保证审批通过后数据已经落在作业票上
- * @returns {Promise<{valid: boolean, variables: object, payload: object, saved: boolean, message: string}>}
- */
- async getBlindPlateTableValue() {
- const flow = this.$refs.blindPlateFlow;
- if (!this.currentBlindPlateNode || !flow) {
- return {
- valid: true,
- variables: {},
- payload: {},
- saved: true,
- message: ''
- };
- }
- const valid = await this.validateBlindPlateNodeForm();
- const payload = flow.getPayload();
- const variables = flow.getVariables();
- if (!valid) {
- return {
- valid,
- variables,
- payload,
- saved: false,
- message: '请填写当前环节的必填内容'
- };
- }
- const saved = await this.updateExtension(payload);
- return {
- valid,
- variables,
- payload,
- saved: saved.saved,
- message: saved.message
- };
- },
- /**
- * 把环节内容合并进作业票内容(extensionJson)并保存
- */
- async updateExtension(payload) {
- if (!Object.keys(payload || {}).length) {
- return { saved: true, message: '' };
- }
- if (!this.businessId && !this.ticket?.id) {
- return { saved: false, message: '缺少作业票信息,无法保存环节内容' };
- }
- const extension = mergeExtension(this.extension, payload);
- const params = buildTicketUpdateParams(
- this.ticket,
- extension,
- this.businessId
- );
- try {
- await ticketUpdate(params);
- // 同步本地内容,避免详情页显示旧值
- this.extension = extension;
- return { saved: true, message: '' };
- } catch (e) {
- return {
- saved: false,
- message: e?.message || '环节内容保存失败'
- };
- }
- },
- /** 供审批组件提交时调用,保存业务数据 */
- async save(data) {
- if (this.isConfinedSpaceWork) {
- return this.saveConfined(data);
- }
- if (this.isHeightWork) {
- return this.saveHeight(data);
- }
- if (this.isHoistingWork) {
- return this.saveHoisting(data);
- }
- if (this.isElectricityWork) {
- return this.saveElectricity(data);
- }
- if (this.isBreakGroundWork) {
- return this.saveBreakGround(data);
- }
- if (this.isBreakRoadWork) {
- return this.saveBreakRoad(data);
- }
- if (this.isBlindPlateWork) {
- return this.saveBlindPlate(data);
- }
- const payload =
- data && data.payload
- ? data.payload
- : buildNodePayload(this.currentFireNode, this.nodeForm);
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- /**
- * 受限空间作业:供审批组件提交时调用,保存业务数据
- */
- async saveConfined(data) {
- const flow = this.$refs.confinedFlow;
- const payload =
- data && data.payload
- ? data.payload
- : flow
- ? flow.getPayload()
- : {};
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- /**
- * 高处作业:供审批组件提交时调用,保存业务数据
- */
- async saveHeight(data) {
- const flow = this.$refs.heightFlow;
- const payload =
- data && data.payload
- ? data.payload
- : flow
- ? flow.getPayload()
- : {};
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- /**
- * 吊装作业:供审批组件提交时调用,保存业务数据
- */
- async saveHoisting(data) {
- const flow = this.$refs.hoistingFlow;
- const payload =
- data && data.payload
- ? data.payload
- : flow
- ? flow.getPayload()
- : {};
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- /**
- * 临时用电作业:供审批组件提交时调用,保存业务数据
- */
- async saveElectricity(data) {
- const flow = this.$refs.electricityFlow;
- const payload =
- data && data.payload
- ? data.payload
- : flow
- ? flow.getPayload()
- : {};
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- /**
- * 动土作业:供审批组件提交时调用,保存业务数据
- */
- async saveBreakGround(data) {
- const flow = this.$refs.breakGroundFlow;
- const payload =
- data && data.payload
- ? data.payload
- : flow
- ? flow.getPayload()
- : {};
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- /**
- * 断路作业:供审批组件提交时调用,保存业务数据
- */
- async saveBreakRoad(data) {
- const flow = this.$refs.breakRoadFlow;
- const payload =
- data && data.payload
- ? data.payload
- : flow
- ? flow.getPayload()
- : {};
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- /**
- * 盲板抽堵作业:供审批组件提交时调用,保存业务数据
- */
- async saveBlindPlate(data) {
- const flow = this.$refs.blindPlateFlow;
- const payload =
- data && data.payload
- ? data.payload
- : flow
- ? flow.getPayload()
- : {};
- if (!Object.keys(payload).length) {
- return data;
- }
- try {
- const res = await this.updateExtension(payload);
- if (!res.saved) {
- console.error('保存环节内容失败', res.message);
- }
- } catch (e) {
- console.error('保存环节内容失败', e);
- }
- return data;
- },
- // 作业类型字典:{dictCode, dictValue} 形式
- async loadWorkTypeDict() {
- try {
- const items = await getDictByCode('ehs_hazardous_work_type');
- return (items || []).map((item) => ({
- dictCode: item.key,
- dictValue: item.label
- }));
- } catch (e) {
- return [];
- }
- },
- reset() {
- this.ticket = {};
- this.work = {};
- this.extension = {};
- this.variables = {};
- this.template = null;
- this.currentTaskName = '';
- this.nodeForm = {};
- this.activeTab = 'info';
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .ticket-detail {
- .detail-summary {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 4px 10px;
- }
- .summary-title {
- font-size: 15px;
- font-weight: 500;
- color: #303133;
- i {
- color: #409eff;
- margin-right: 4px;
- }
- ::v-deep .el-tag {
- margin-left: 8px;
- }
- }
- .summary-extra {
- font-size: 12px;
- color: #909399;
- line-height: 20px;
- span {
- margin-left: 14px;
- }
- }
- .detail-tabs {
- ::v-deep .el-tabs__content {
- padding-top: 12px;
- }
- }
- .current-node-box {
- padding: 16px;
- margin-bottom: 16px;
- border: 1px solid #d9ecff;
- border-radius: 4px;
- background: #f5faff;
- }
- .node-tip {
- padding: 10px 0;
- font-size: 13px;
- color: #909399;
- }
- .el-form-box {
- max-height: calc(100vh - 320px);
- overflow-y: auto;
- padding-right: 10px;
- }
- .empty-text {
- padding: 10px 0;
- font-size: 13px;
- color: #909399;
- }
- .raw-extension {
- padding: 8px 12px;
- background: #f6f7f9;
- border-radius: 4px;
- }
- .raw-row {
- display: flex;
- font-size: 13px;
- line-height: 24px;
- word-break: break-all;
- }
- .raw-key {
- flex: 0 0 180px;
- color: #909399;
- }
- .raw-value {
- flex: 1;
- color: #303133;
- }
- }
- </style>
|