Blame view

src/views/workflow/components/processViewer.vue 12.9 KB
1
<!--
2
 * @Description:
3 4 5
 * @Autor: renchao
 * @LastEditTime: 2023-05-17 10:41:15
-->
任超 committed
6
<template>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
  <div>
    <div class="process-viewer">
      <div v-show="!isLoading" ref="processCanvas" class="process-canvas" style="height: 280px;" />
      <!-- 自定义箭头样式,用于成功状态下流程连线箭头 -->
      <defs ref="customSuccessDefs">
        <marker id="sequenceflow-end-white-success" view-box="0 0 20 20" ref-x="11" ref-y="10" marker-width="10"
          marker-height="10" orient="auto">
          <path class="success-arrow" d="M 1 5 L 11 10 L 1 15 Z"
            style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
        </marker>
        <marker id="conditional-flow-marker-white-success" view-box="0 0 20 20" ref-x="-1" ref-y="10" marker-width="10"
          marker-height="10" orient="auto">
          <path class="success-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z"
            style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
        </marker>
      </defs>
      <!-- 自定义箭头样式,用于失败状态下流程连线箭头 -->
      <defs ref="customFailDefs">
        <marker id="sequenceflow-end-white-fail" view-box="0 0 20 20" ref-x="11" ref-y="10" marker-width="10"
          marker-height="10" orient="auto">
          <path class="fail-arrow" d="M 1 5 L 11 10 L 1 15 Z"
            style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
        </marker>
        <marker id="conditional-flow-marker-white-fail" view-box="0 0 20 20" ref-x="-1" ref-y="10" marker-width="10"
          marker-height="10" orient="auto">
          <path class="fail-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z"
            style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
        </marker>
      </defs>

      <div style="position: absolute; top: 0px; left: 0px; width: 100%;">
        <el-row type="flex" justify="end">
          <el-button-group key="scale-control" size="medium">
            <el-button size="medium" type="default" :plain="true" :disabled="defaultZoom <= 0.3" icon="el-icon-zoom-out"
              @click="processZoomOut()" />
            <el-button size="medium" type="default" style="width: 90px;">{{ Math.floor(this.defaultZoom * 10 * 10) + "%"
            }}</el-button>
            <el-button size="medium" type="default" :plain="true" :disabled="defaultZoom >= 3.9" icon="el-icon-zoom-in"
              @click="processZoomIn()" />
            <el-button size="medium" type="default" icon="el-icon-c-scale-to-original" @click="processReZoom()" />
            <slot />
          </el-button-group>
        </el-row>
      </div>
    </div>
任超 committed
52
    <!-- 已完成节点悬浮弹窗 -->
53 54 55 56 57
    <div class="information-list">
      <el-select v-model="selectValue" @change="handleSelect">
        <el-option v-for="item in selectOptions" :key="item.value" :label="item.label" :value="item.value">
        </el-option>
      </el-select>
xiaomiao committed
58
      <el-table height="190" :data="taskCommentList" size="mini" border header-cell-class-name="table-header-gray">
59
        <el-table-column label="序号" header-align="center" align="center" type="index" width="55px" />
xiaomiao committed
60 61
        <el-table-column label="流程状态" header-align="center" align="center">
          <template slot-scope="scope">
xiaomiao committed
62 63
            <div v-if="scope.row.endTime">已完结</div>
            <div v-else>正在办理</div>
xiaomiao committed
64 65
          </template>
        </el-table-column>
xiaomiao committed
66
        <el-table-column label="环节名称" prop="name" minWidth="100" align="center" />
67
        <el-table-column label="办理人" prop="agent" minWidth="120" align="center" />
xiaomiao committed
68 69 70 71
        <el-table-column label="转入时间" prop="createTime" :formatter="formatDate" width="160" align="center" />
        <el-table-column label="认领时间" prop="claimTime" :formatter="formatDate" width="160" align="center" />
        <el-table-column label="转出时间" prop="endTime" :formatter="formatDate" width="160" align="center" />
        <el-table-column label="操作方式" prop="controls" align="center"/>
xiaomiao committed
72
        <el-table-column label="意见" prop="idea" align="center"/>
73
      </el-table>
任超 committed
74 75 76 77
    </div>
  </div>
</template>
<script>
xiaomiao committed
78 79 80 81 82 83 84 85
  import '@/styles/package/theme/index.scss'
  import BpmnViewer from 'bpmn-js/lib/Viewer'
  import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'
  export default {
    props: {
      formData: {
        type: Object,
        default: {}
任超 committed
86 87
      }
    },
xiaomiao committed
88 89 90 91 92 93 94 95 96 97 98 99
    data () {
      return {
        dlgTitle: undefined,
        defaultZoom: 1,
        // 是否正在加载流程图
        isLoading: true,
        bpmnViewer: undefined,
        // 已完成流程元素
        processNodeInfo: undefined,
        // 当前任务id
        selectTaskId: undefined,
        // 任务节点审批记录
100
        taskList:[],
xiaomiao committed
101 102 103 104 105 106
        taskCommentList: [],
        // 已完成任务悬浮延迟Timer
        hoverTimer: null,
        // 下拉
        selectValue: '',
        selectOptions: []
任超 committed
107 108
      }
    },
xiaomiao committed
109 110
    created () {
      this.$nextTick(() => {
111 112 113
        // 获取流程记录
        this.getCommentList()
         this.setProcessStatus(this.formData.finishedInfo);
xiaomiao committed
114
        this.importXML(this.formData.xml)
115

xiaomiao committed
116
      })
任超 committed
117
    },
xiaomiao committed
118 119
    destroyed () {
      this.clearViewer()
任超 committed
120
    },
xiaomiao committed
121
    methods: {
xiaomiao committed
122 123 124 125 126 127 128 129
      formatDate(row, column) {
          let data = row[column.property]
          if(data == null) {
              return null
          }
          let dt = new Date(data)
           return dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate() + ' ' + dt.getHours() + ':' + dt.getMinutes() + ':' + dt.getSeconds()
        },
xiaomiao committed
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
      processReZoom () {
        this.defaultZoom = 1
        this.bpmnViewer.get('canvas').zoom('fit-viewport', 'auto')
      },
      processZoomIn (zoomStep = 0.1) {
        const newZoom = Math.floor(this.defaultZoom * 100 + zoomStep * 100) / 100
        if (newZoom > 4) {
          throw new Error('[Process Designer Warn ]: The zoom ratio cannot be greater than 4')
        }
        this.defaultZoom = newZoom
        this.bpmnViewer.get('canvas').zoom(this.defaultZoom)
      },
      processZoomOut (zoomStep = 0.1) {
        const newZoom = Math.floor(this.defaultZoom * 100 - zoomStep * 100) / 100
        if (newZoom < 0.2) {
          throw new Error('[Process Designer Warn ]: The zoom ratio cannot be scss than 0.2')
        }
        this.defaultZoom = newZoom
        this.bpmnViewer.get('canvas').zoom(this.defaultZoom)
      },
      getOperationTagType (type) {
        return 'success'
      },
      // 流程图预览清空
      clearViewer (a) {
        if (this.$refs.processCanvas) {
          this.$refs.processCanvas.innerHTML = ''
        }
        if (this.bpmnViewer) {
          this.bpmnViewer.destroy()
        }
        this.bpmnViewer = null
      },
      // 添加自定义箭头
      addCustomDefs () {
        const canvas = this.bpmnViewer.get('canvas')
        const svg = canvas._svg
        const customSuccessDefs = this.$refs.customSuccessDefs
        const customFailDefs = this.$refs.customFailDefs
        svg.appendChild(customSuccessDefs)
        svg.appendChild(customFailDefs)
      },
      // 任务悬浮弹窗
      onSelectElement (element) {
        this.selectTaskId = undefined
        this.dlgTitle = undefined
xiaomiao committed
176 177 178 179
        let allfinishedTaskSet = [...this.processNodeInfo.finishedTaskSet, ...this.processNodeInfo.unfinishedTaskSet]
        if (this.processNodeInfo == null || allfinishedTaskSet == null)
          return
        if (element == null || allfinishedTaskSet.indexOf(element.id) === -1) {
xiaomiao committed
180 181 182
          return
        }
        this.selectTaskId = element.id
xiaomiao committed
183
        this.selectValue = element.id
xiaomiao committed
184 185
        this.dlgTitle = element.businessObject ? element.businessObject.name : undefined
        // 计算当前悬浮任务审批记录,如果记录为空不显示弹窗
186
        this.taskCommentList = (this.taskList || []).filter(item => {
xiaomiao committed
187
          return item.taskDefinitionKey === this.selectTaskId
xiaomiao committed
188
        })
xiaomiao committed
189
          if (this.taskCommentList.length==0) {
190
          this.taskCommentList = this.taskList;
191
        }
xiaomiao committed
192 193 194
      },
      // 下拉列表切换
      handleSelect (val) {
195
        this.taskCommentList = (this.taskList || []).filter(item => {
xiaomiao committed
196
          return item.taskDefinitionKey === val
xiaomiao committed
197
        })
xiaomiao committed
198
        if (this.taskCommentList.length==0) {
199
          this.taskCommentList = this.taskList;
xiaomiao committed
200
        }
xiaomiao committed
201 202 203 204 205 206 207 208 209 210 211 212
      },
      // 显示流程图
      async importXML (xml) {
        let xmlData = this.$x2js.xml2js(xml).definitions.process;
        this.selectOptions = xmlData.userTask.map(item => {
          return { value: item._id, label: item._name }
        })
        this.selectOptions = [{ value: xmlData.startEvent._id, label: '浏览记录' }, ...this.selectOptions]
        this.selectOptions = this.selectOptions.map(item => {
          if (this.formData.finishedInfo.finishedTaskSet.includes(item.value)) {
            return item
          }
xiaomiao committed
213 214 215
          if (this.formData.finishedInfo.unfinishedTaskSet.includes(item.value)) {
            return item
          }
xiaomiao committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
        }).filter(Boolean);
        this.selectValue = xmlData.startEvent._id
        this.clearViewer('a')
        if (xml != null && xml !== '') {
          try {
            this.bpmnViewer = new BpmnViewer({
              additionalModules: [
                // 移动整个画布
                MoveCanvasModule
              ],
              container: this.$refs.processCanvas
            })
            // 任务节点悬浮事件
            this.bpmnViewer.on('element.click', ({ element }) => {
              this.onSelectElement(element)
            })
            await this.bpmnViewer.importXML(xml)
            this.isLoading = true
            this.addCustomDefs()
          } catch (e) {
            this.clearViewer('b')
          } finally {
            this.isLoading = false
            this.setProcessStatus(this.processNodeInfo)
            this.$nextTick(() => {
              this.processReZoom()
            })
          }
244
        }
xiaomiao committed
245
      },
246 247 248
       // 获取流程记录
      getCommentList() {
        this.formData.allCommentList.forEach(async (item,index) => {
xiaomiao committed
249 250 251
          item.comments.forEach(element => {
            if(element.type=="COMPLETE"){
              this.formData.allCommentList[index].idea=element.message
xiaomiao committed
252
               this.formData.allCommentList[index].controls="完成"
xiaomiao committed
253 254 255
            }
          });
            this.formData.allCommentList[index].agent=item.assignee.name
256
        })
xiaomiao committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
        this.formData.handlinglist.forEach(async (item,index) => {
          if(item.assignee.name){
            this.formData.handlinglist[index].agent=item.assignee.name
          }else{
            let str=""
            item.countersign.forEach((item) => {
               str+=item.name+","
            })
            str=str.slice(0, -1);
            this.formData.allCommentList[index].agent=str
          }

        })
           this.taskList =[...this.formData.allCommentList,...this.formData.handlinglist];
          //  this.taskList =this.formData.allCommentList;
272 273
          //  处理数据之后赋值
            this.taskCommentList=this.taskList
xiaomiao committed
274

275 276
      },

xiaomiao committed
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
      // 设置流程图元素状态
      setProcessStatus (processNodeInfo) {
        this.processNodeInfo = processNodeInfo
        if (this.isLoading || this.processNodeInfo == null || this.bpmnViewer == null) return
        const { finishedTaskSet, rejectedTaskSet, unfinishedTaskSet, finishedSequenceFlowSet } = this.processNodeInfo
        const canvas = this.bpmnViewer.get('canvas')
        const elementRegistry = this.bpmnViewer.get('elementRegistry')
        if (Array.isArray(finishedSequenceFlowSet)) {
          finishedSequenceFlowSet.forEach(item => {
            if (item != null) {
              canvas.addMarker(item, 'success')
              const element = elementRegistry.get(item)
              const conditionExpression = element.businessObject.conditionExpression
              if (conditionExpression) {
                canvas.addMarker(item, 'condition-expression')
              }
            }
任超 committed
294 295
          })
        }
xiaomiao committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
        if (Array.isArray(finishedTaskSet)) {
          finishedTaskSet.forEach(item => canvas.addMarker(item, 'success'))
        }
        if (Array.isArray(unfinishedTaskSet)) {
          unfinishedTaskSet.forEach(item => canvas.addMarker(item, 'primary'))
        }
        if (Array.isArray(rejectedTaskSet)) {
          rejectedTaskSet.forEach(item => {
            if (item != null) {
              const element = elementRegistry.get(item)
              if (element.type.includes('Task')) {
                canvas.addMarker(item, 'danger')
              } else {
                canvas.addMarker(item, 'warning')
              }
任超 committed
311
            }
xiaomiao committed
312 313
          })
        }
314

任超 committed
315 316 317
      }
    }
  }
318 319
</script>
<style scoped lang="scss">
xiaomiao committed
320
  .information-list {
xiaomiao committed
321 322
    height: 220px;
    margin-top: 10px;
323

xiaomiao committed
324 325 326 327
    p {
      font-size: 16px;
      line-height: 24px;
    }
328
  }
xiaomiao committed
329 330 331
  /deep/.bjs-powered-by {
    display: none;
  }
xiaomiao committed
332 333 334 335
  // /deep/.information-list {
  //   height: 170px;
  //   overflow: visible;
  // }
xiaomiao committed
336
</style>