更多ruoyi-nbcio功能请看演示系统
gitee源代码地址
前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio
演示地址:RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/
更多nbcio-boot功能请看演示系统
gitee源代码地址
后端代码: https://gitee.com/nbacheng/nbcio-boot
前端代码:https://gitee.com/nbacheng/nbcio-vue.git
在线演示(包括H5) : http://218.75.87.38:9888
1、原先 vue的HistoricDetail.vue代码如下:
<style lang="less"> </style> <template> <div class="search"> <el-tabs tab-position="top" v-model="activeName" :value="processed === true ? 'approval' : 'form'" @tab-click="changeTab"> <el-tab-pane label="表单信息" name="form"> <div v-if="customForm.visible"> <!-- 自定义表单 --> <component ref="refCustomForm" :disabled="customForm.disabled" v-bind:is="customForm.formComponent" :model="customForm.model" :customFormData="customForm.customFormData" :isNew = "customForm.isNew"></component> </div> <div style="margin-left:10%;margin-bottom: 30px"> <!--对上传文件进行显示处理,临时方案 add by nbacheng 2022-07-27 --> <el-upload action="#" :on-preview="handleFilePreview" :file-list="fileList" v-if="fileDisplay" /> </div> </el-tab-pane > <el-tab-pane label="流转记录" name="record"> <el-card class="box-card" shadow="never"> <el-col :span="20" :offset="2"> <div class="block"> <el-timeline> <el-timeline-item v-for="(item,index) in historyProcNodeList" :key="index" :icon="setIcon(item.endTime)" :color="setColor(item.endTime)"> <p style="font-weight: 700">{{ item.activityName }}</p> <el-card v-if="item.activityType === 'startEvent'" class="box-card" shadow="hover"> {{ item.assigneeName }} 在 {{ item.createTime }} 发起流程 </el-card> <el-card v-if="item.activityType === 'userTask'" class="box-card" shadow="hover"> <el-descriptions :column="5" :labelStyle="{'font-weight': 'bold'}"> <el-descriptions-item label="实际办理">{{ item.assigneeName || '-'}}</el-descriptions-item> <el-descriptions-item label="候选办理">{{ item.candidate || '-'}}</el-descriptions-item> <el-descriptions-item label="接收时间">{{ item.createTime || '-'}}</el-descriptions-item> <el-descriptions-item label="办结时间">{{ item.endTime || '-' }}</el-descriptions-item> <el-descriptions-item label="耗时">{{ item.duration || '-'}}</el-descriptions-item> </el-descriptions> <div v-if="item.commentList && item.commentList.length > 0"> <div v-for="(comment, index) in item.commentList" :key="index"> <el-divider content-position="left"> <el-tag :type="approveTypeTag(comment.type)" size="mini">{{ commentType(comment.type) }}</el-tag> <el-tag type="info" effect="plain" size="mini">{{ comment.time }}</el-tag> </el-divider> <span>{{ comment.fullMessage }}</span> </div> </div> </el-card> <el-card v-if="item.activityType === 'endEvent'" class="box-card" shadow="hover"> {{ item.createTime }} 结束流程 </el-card> </el-timeline-item> </el-timeline> </div> </el-col> </el-card> </el-tab-pane> <el-tab-pane label="流程跟踪" name="track"> <el-card class="box-card" shadow="never"> <process-viewer :key="`designer-${loadIndex}`" :style="'height:' + height" :xml="xmlData" :finishedInfo="finishedInfo" :allCommentList="historyProcNodeList" /> </el-card> </el-tab-pane> </el-tabs> </div> </template> <script> import {detailProcessByDataId} from "@/api/workflow/process"; import ProcessViewer from '@/components/ProcessViewer' import { flowableMixin } from '@/views/workflow/mixins/flowableMixin' export default { name: 'HistoricDetail', mixins: [flowableMixin], components: { ProcessViewer, }, props: { /**/ dataId: { type: String, default: '', required: true } }, computed: { commentType() { return val => { switch (val) { case '1': return '通过' case '2': return '退回' case '3': return '驳回' case '4': return '委派' case '5': return '转办' case '6': return '终止' case '7': return '撤回' case '8': return '拒绝' case '9': return '跳过' case '10': return '前加签' case '11': return '后加签' case '12': return '多实例加签' case '13': return '跳转' case '14': return '收回' } } }, approveTypeTag() { return val => { switch (val) { case '1': return 'success' case '2': return 'warning' case '3': return 'danger' case '4': return 'primary' case '5': return 'success' case '6': return 'danger' case '7': return 'info' } } } }, data() { return { height: document.documentElement.clientHeight - 205 + 'px;', // 模型xml数据 loadIndex: 0, xmlData: undefined, finishedInfo: { finishedSequenceFlowSet: [], finishedTaskSet: [], unfinishedTaskSet: [], rejectedTaskSet: [] }, historyProcNodeList: [], processed: false, activeName:'form', //获取当然tabname customForm: { //自定义业务表单 formId: '', title: '', disabled: false, visible: false, formComponent: null, model: {}, /*流程数据*/ customFormData: {}, isNew: false, disableSubmit: true }, fileDisplay: false, // formdesigner是否显示上传的文件控件 fileList: [], //表单设计器上传的文件列表 }; }, created() { this.init(); }, watch: { dataId: function(newval, oldName) { this.init(); } }, methods: { init() { // 获取流程变量 this.detailProcesssByDataId(this.dataId); }, detailProcesssByDataId(dataId) { const params = {dataId: dataId} detailProcessByDataId(params).then(res => { console.log("detailProcessByDataId res=",res); if (res.code === 200 && res.data != null) { const data = res.data; this.xmlData = data.bpmnXml; this.processFormList = data.processFormList; if(this.processFormList.length == 1 && this.processFormList[0].formValues.hasOwnProperty('routeName')) { this.customForm.disabled = true; this.customForm.visible = true; this.customForm.formComponent = this.getFormComponent(this.processFormList[0].formValues.routeName).component; this.customForm.model = this.processFormList[0].formValues.formData; this.customForm.customFormData = this.processFormList[0].formValues.formData; console.log("detailProcess customForm",this.customForm); } this.historyProcNodeList = data.historyProcNodeList; this.finishedInfo = data.flowViewer; } }) }, changeTab(tab, event) { console.log("changeTab tab=",tab); if(tab.name === 'form') { console.log("changeTab this.processFormList=",this.processFormList); if(this.customForm.formId === "") { // 回填数据,这里主要是处理文件列表显示,临时解决,以后应该在formdesigner里完成 this.processFormList.forEach((item, i) => { if (item.hasOwnProperty('list') && item.list != null) { this.fillFormData(item.list, item) // 更新表单 this.key = +new Date().getTime() } }); } } }, setIcon(val) { if (val) { return "el-icon-check"; } else { return "el-icon-time"; } }, setColor(val) { if (val) { return "#2bc418"; } else { return "#b3bdbb"; } }, fillFormData(list, formConf) { // for formdesigner console.log("fillFormData list=",list); console.log("fillFormData formConf=",formConf); list.forEach((item, i) => { // 特殊处理el-upload,包括 回显图片 if(formConf.formValues[item.id] != '') { const val = formConf.formValues[item.id]; if (item.ele === 'el-upload') { console.log('fillFormData val=',val) if(item['list-type'] != 'text') {//图片 this.fileList = [] //隐藏加的el-upload文件列表 //item['file-list'] = JSON.parse(val) if(val != '') { item['file-list'] = JSON.parse(val) } } else { //列表 console.log("列表fillFormData val",val) this.fileList = JSON.parse(val) item['file-list'] = [] //隐藏加的表单设计器的文件列表 } // 回显图片 this.fileDisplay = true } } if (Array.isArray(item.columns)) { this.fillFormData(item.columns, formConf) } }) }, } }; </script> <style lang="scss" scoped> .clearfix:before, .clearfix:after { display: table; content: ""; } .clearfix:after { clear: both } .box-card { width: 100%; margin-bottom: 20px; } .el-tag + .el-tag { margin-left: 10px; } .el-row { margin-bottom: 20px; &:last-child { margin-bottom: 0; } } .el-col { border-radius: 4px; } .button-new-tag { margin-left: 10px; } </style>
2、修改成vue3后的代码如下:
<style lang="less"> </style> <template> <div class="search"> <el-tabs tab-position="top" v-model="activeName" :value="processed === true ? 'approval' : 'form'" @tab-click="changeTab"> <el-tab-pane label="表单信息" name="form"> <div v-if="customForm.visible"> <!-- 自定义表单 --> <component ref="refCustomForm" :disabled="customForm.disabled" :is="customForm.formComponent" :model="customForm.model" :customFormData="customForm.customFormData" :isNew = "customForm.isNew"></component> </div> <div style="margin-left:10%;margin-bottom: 30px"> <!--对上传文件进行显示处理,临时方案 add by nbacheng 2022-07-27 --> <el-upload action="#" :on-preview="handleFilePreview" :file-list="fileList" v-if="fileDisplay" /> </div> </el-tab-pane > <el-tab-pane label="流转记录" name="record"> <el-card class="box-card" shadow="never"> <el-col :span="20" :offset="2"> <div class="block"> <el-timeline> <el-timeline-item v-for="(item,index) in historyProcNodeList" :key="index" :icon="setIcon(item.endTime)" :color="setColor(item.endTime)"> <p style="font-weight: 700">{{ item.activityName }}</p> <el-card v-if="item.activityType === 'startEvent'" class="box-card" shadow="hover"> {{ item.assigneeName }} 在 {{ item.createTime }} 发起流程 </el-card> <el-card v-if="item.activityType === 'userTask'" class="box-card" shadow="hover"> <el-descriptions :column="5" :labelStyle="{'font-weight': 'bold'}"> <el-descriptions-item label="实际办理">{{ item.assigneeName || '-'}}</el-descriptions-item> <el-descriptions-item label="候选办理">{{ item.candidate || '-'}}</el-descriptions-item> <el-descriptions-item label="接收时间">{{ item.createTime || '-'}}</el-descriptions-item> <el-descriptions-item label="办结时间">{{ item.endTime || '-' }}</el-descriptions-item> <el-descriptions-item label="耗时">{{ item.duration || '-'}}</el-descriptions-item> </el-descriptions> <div v-if="item.commentList && item.commentList.length > 0"> <div v-for="(comment, index) in item.commentList" :key="index"> <el-divider content-position="left"> <el-tag :type="approveTypeTag(comment.type)" size="small">{{ commentType(comment.type) }}</el-tag> <el-tag type="info" effect="plain" size="small">{{ comment.time }}</el-tag> </el-divider> <span>{{ comment.fullMessage }}</span> </div> </div> </el-card> <el-card v-if="item.activityType === 'endEvent'" class="box-card" shadow="hover"> {{ item.createTime }} 结束流程 </el-card> </el-timeline-item> </el-timeline> </div> </el-col> </el-card> </el-tab-pane> <el-tab-pane label="流程跟踪" name="track"> <el-card class="box-card" shadow="never"> <process-viewer :key="`designer-${loadIndex}`" :style="'height:' + height" :xml="xmlData" :finishedInfo="finishedInfo" :allCommentList="historyProcNodeList" /> </el-card> </el-tab-pane> </el-tabs> </div> </template> <script setup lang="ts"> import {detailProcessByDataId} from "@/api/workflow/process"; import ProcessViewer from '@/components/ProcessViewer' import { useFlowable } from '@/views/workflow/hooks/useFlowable' defineOptions({ name: 'HistoricDetail' }) const props = defineProps({ dataId: { type: String, default: '', required: true } }) const commentType = computed(() => { return val => { switch (val) { case '1': return '通过' case '2': return '退回' case '3': return '驳回' case '4': return '委派' case '5': return '转办' case '6': return '终止' case '7': return '撤回' case '8': return '拒绝' case '9': return '跳过' case '10': return '前加签' case '11': return '后加签' case '12': return '多实例加签' case '13': return '跳转' case '14': return '收回' } } }) const approveTypeTag = computed(() => { return val => { switch (val) { case '1': return 'success' case '2': return 'warning' case '3': return 'danger' case '4': return 'primary' case '5': return 'success' case '6': return 'danger' case '7': return 'info' } } }) const { getFormComponent } = useFlowable() const height = ref(document.documentElement.clientHeight - 205 + 'px;') // 模型xml数据 const loadIndex = ref(0) const xmlData = ref(null) const finishedInfo = ref({ finishedSequenceFlowSet: [], finishedTaskSet: [], unfinishedTaskSet: [], rejectedTaskSet: [] }) const historyProcNodeList = ref<any>([]) const processed = ref(false) const activeName = ref('form') //获取当然tabname const processFormList = ref<any>([]) const customForm = ref({ //自定义业务表单 formId: '', title: '', disabled: false, visible: false, formComponent: null, model: {}, /*流程数据*/ customFormData: {}, isNew: false, disableSubmit: true }) const fileDisplay = ref(false) // formdesigner是否显示上传的文件控件 const fileList = ref<any>([]) //表单设计器上传的文件列表 const key = ref<any>() const init = () => { // 获取流程变量 detailProcesssByDataId(props.dataId); } const detailProcesssByDataId = (dataId) => { const params = {dataId: dataId} detailProcessByDataId(params).then(res => { console.log("detailProcessByDataId res=",res); if (res.code === 200 && res.data != null) { const data = res.data; xmlData.value = data.bpmnXml; processFormList.value = data.processFormList; if(processFormList.value.length == 1 && processFormList.value[0].formValues.hasOwnProperty('routeName')) { customForm.value.disabled = true; customForm.value.visible = true; customForm.value.formComponent = getFormComponent(processFormList.value[0].formValues.routeName).component; customForm.value.model = processFormList.value[0].formValues.formData; customForm.value.customFormData = processFormList.value[0].formValues.formData; console.log("detailProcess customForm.value",customForm.value); } historyProcNodeList.value = data.historyProcNodeList; finishedInfo.value = data.flowViewer; } }) } const changeTab = (tab, event) => { console.log("changeTab tab=",tab); const tabname = toRaw(tab); if(tabname.paneName.value === 'form') { console.log("changeTab processFormList.value=",processFormList.value); if(customForm.value.formId === "") { // 回填数据,这里主要是处理文件列表显示,临时解决,以后应该在formdesigner里完成 processFormList.value.forEach((item, i) => { if (item.hasOwnProperty('list') && item.list != null) { fillFormData(item.list, item) // 更新表单 key.value = +new Date().getTime() } }); } } } const setIcon = (val) => { if (val) { return "el-icon-check"; } else { return "el-icon-time"; } } const setColor = (val) => { if (val) { return "#2bc418"; } else { return "#b3bdbb"; } } const fillFormData = (list, formConf) => { // for formdesigner console.log("fillFormData list=",list); console.log("fillFormData formConf=",formConf); list.forEach((item, i) => { // 特殊处理el-upload,包括 回显图片 if(formConf.formValues[item.id] != '') { const val = formConf.formValues[item.id]; if (item.ele === 'el-upload') { console.log('fillFormData val=',val) if(item['list-type'] != 'text') {//图片 fileList.value = [] //隐藏加的el-upload文件列表 //item['file-list'] = JSON.parse(val) if(val != '') { item['file-list'] = JSON.parse(val) } } else { //列表 console.log("列表fillFormData val",val) fileList.value = JSON.parse(val) item['file-list'] = [] //隐藏加的表单设计器的文件列表 } // 回显图片 fileDisplay.value = true } } if (Array.isArray(item.columns)) { fillFormData(item.columns, formConf) } }) } onMounted(() => { init(); }); </script> <style lang="scss" scoped> .clearfix:before, .clearfix:after { display: table; content: ""; } .clearfix:after { clear: both } .box-card { width: 100%; margin-bottom: 20px; } .el-tag + .el-tag { margin-left: 10px; } .el-row { margin-bottom: 20px; &:last-child { margin-bottom: 0; } } .el-col { border-radius: 4px; } .button-new-tag { margin-left: 10px; } </style>
3、效果图如下: