Compare commits
2 Commits
b2c621ffbb
...
bb38116df8
| Author | SHA1 | Date |
|---|---|---|
|
|
bb38116df8 | |
|
|
807ba06ef4 |
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
// WFTask
|
||||
import { defHttp } from '@/utils/http/axios';
|
||||
import {MyUncompletedParams} from './model/WFTaskModel'
|
||||
import {MyUncompletedParams,TaskDetailParam} from './model/WFTaskModel'
|
||||
|
||||
enum Api {
|
||||
// 我的待办
|
||||
|
|
@ -12,6 +12,7 @@ import {MyUncompletedParams} from './model/WFTaskModel'
|
|||
LoadMyReadPage='/api/WFTask/LoadMyReadPage',
|
||||
// 我的委托
|
||||
LoadMyDelegatePage='/api/WFTask/LoadMyDelegatePage',
|
||||
GetTaskDetail='/api/WFTask/Get',
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -37,4 +38,10 @@ import {MyUncompletedParams} from './model/WFTaskModel'
|
|||
*/
|
||||
export function getLoadMyDelegatePage(params?: MyUncompletedParams) {
|
||||
return defHttp.get({ url: Api.LoadMyDelegatePage, params });
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @description: GetTaskDetail
|
||||
*/
|
||||
export function getTaskDetail(params?: TaskDetailParam) {
|
||||
return defHttp.get({ url: Api.GetTaskDetail, params });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,4 +7,7 @@
|
|||
limit: number;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
}
|
||||
export interface TaskDetailParam {
|
||||
id: string;
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<a-tab-pane key="1" tab="自定义表单">
|
||||
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
|
||||
<a-space-compact block>
|
||||
<a-input v-model:value="formData.formCode" placeholder="请选择表单" readonly />
|
||||
<a-input v-model:value="node.formCode" placeholder="请选择表单" readonly />
|
||||
<a-button >选择</a-button>
|
||||
</a-space-compact>
|
||||
<a-space-compact block>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
<a-button :disabled="data.defaultZoom >= 3.9" :icon="h(ZoomInOutlined)" @click="processZoomIn()">
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<div class="ml-2 tag-box">
|
||||
<a-tag color="processing">正在审核</a-tag>
|
||||
<a-tag color="success">已审核</a-tag>
|
||||
</div>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
|
|
@ -22,6 +26,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="my-process-designer__container">
|
||||
|
||||
<div class="my-process-designer__canvas" ref="bpmn-canvas" id="view"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -33,6 +38,8 @@
|
|||
import { SaveOutlined, ZoomOutOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
|
||||
import BpmnViewer from 'bpmn-js/lib/Viewer'
|
||||
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
|
||||
const emit = defineEmits(['event', 'element-click']);
|
||||
|
||||
const data = reactive({
|
||||
bpmnModeler: null,
|
||||
defaultZoom: 1,
|
||||
|
|
@ -40,7 +47,7 @@
|
|||
|
||||
const props = defineProps({
|
||||
xml: String,
|
||||
flowViewer:{
|
||||
flowViewer: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
finishedTaskSet: [],
|
||||
|
|
@ -48,7 +55,11 @@
|
|||
unfinishedTaskSet: [],
|
||||
rejectedTaskSet: [],
|
||||
})
|
||||
}
|
||||
},
|
||||
events: {
|
||||
type: Array,
|
||||
default: () => ["element.click"]
|
||||
},
|
||||
})
|
||||
watch(
|
||||
() => props.xml,
|
||||
|
|
@ -71,6 +82,19 @@
|
|||
MoveCanvasModule
|
||||
],
|
||||
})
|
||||
initModelListeners()
|
||||
}
|
||||
function initModelListeners() {
|
||||
const EventBus = data.bpmnModerler.get("eventBus");
|
||||
// 注册需要的监听事件, 将. 替换为 - , 避免解析异常
|
||||
props.events.forEach(event => {
|
||||
EventBus.on(event, function (eventObj) {
|
||||
let eventName = event.replace('.', "-");
|
||||
let element = eventObj ? eventObj.element : null;
|
||||
emit(eventName, element, eventObj);
|
||||
emit('event', eventName, element, eventObj);
|
||||
});
|
||||
});
|
||||
}
|
||||
async function createDiagram(xml) {
|
||||
const viewer = data.bpmnModerler
|
||||
|
|
@ -103,6 +127,7 @@
|
|||
// 设置节点颜色
|
||||
function setNodeColor() {
|
||||
const elementRegistry = data.bpmnModerler.get('elementRegistry')
|
||||
console.log(elementRegistry)
|
||||
let { finishedTaskSet, rejectedTaskSet, unfinishedTaskSet, finishedSequenceFlowSet } = props.flowViewer
|
||||
if (Array.isArray(finishedSequenceFlowSet)) {
|
||||
finishedSequenceFlowSet.forEach(item => {
|
||||
|
|
@ -120,6 +145,7 @@
|
|||
}
|
||||
})
|
||||
}
|
||||
console.log(unfinishedTaskSet)
|
||||
if (Array.isArray(unfinishedTaskSet)) {
|
||||
unfinishedTaskSet.forEach(item => {
|
||||
if (elementRegistry._elements[item]) {
|
||||
|
|
@ -161,13 +187,22 @@
|
|||
function getOperationTagType(type) {
|
||||
return 'success';
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.my-process-designer {
|
||||
width: 100%;
|
||||
}
|
||||
.tag-box{
|
||||
float: right;
|
||||
}
|
||||
::v-deep .ant-tag-success{
|
||||
padding: 5px 11px;
|
||||
}
|
||||
::v-deep .ant-tag-processing{
|
||||
padding: 5px 11px;
|
||||
|
||||
}
|
||||
::v-deep .bjs-container a {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@
|
|||
"workflow":{
|
||||
"scheme_preview":"流程模板设计",
|
||||
"create_preview":"流程发起",
|
||||
"task_preview":"流程详情"
|
||||
"task_audit_preview":"审核节点",
|
||||
"task_look_preview":"查看流程"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,17 +48,29 @@ const dashboard: AppRouteModule = {
|
|||
component: () => import('@/views/demo/workflow/create/preview.vue'),
|
||||
},
|
||||
{
|
||||
path: 'task_preview/:id',
|
||||
name: 'TaskPreview',
|
||||
path: 'task_audit_preview/:id',
|
||||
name: 'TaskAuditPreview',
|
||||
meta: {
|
||||
hideMenu: true,
|
||||
title: t('routes.demo.workflow.task_preview'),
|
||||
title: t('routes.demo.workflow.task_audit_preview'),
|
||||
ignoreKeepAlive: true,
|
||||
showMenu: false,
|
||||
currentActiveMenu: '/workflow/create',
|
||||
currentActiveMenu: '/workflow/task',
|
||||
},
|
||||
component: () => import('@/views/demo/workflow/task/detail.vue'),
|
||||
}
|
||||
component: () => import('@/views/demo/workflow/task/process/audit.vue'),
|
||||
},
|
||||
{
|
||||
path: 'task_look_preview/:id',
|
||||
name: 'TaskLookPreview',
|
||||
meta: {
|
||||
hideMenu: true,
|
||||
title: t('routes.demo.workflow.task_look_preview'),
|
||||
ignoreKeepAlive: true,
|
||||
showMenu: false,
|
||||
currentActiveMenu: '/workflow/task',
|
||||
},
|
||||
component: () => import('@/views/demo/workflow/task/process/look.vue'),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* 日期格式化
|
||||
*/
|
||||
export function formatDate(v, format) {
|
||||
if (!v) return "";
|
||||
var d = v;
|
||||
if (typeof v === 'string') {
|
||||
if (v.indexOf("/Date(") > -1)
|
||||
d = new Date(parseInt(v.replace("/Date(", "").replace(")/", ""), 10));
|
||||
else
|
||||
d = new Date(Date.parse(v.replace(/-/g, "/").replace("T", " ").split(".")[0]));//.split(".")[0] 用来处理出现毫秒的情况,截取掉.xxx,否则会出错
|
||||
}
|
||||
var o = {
|
||||
"M+": d.getMonth() + 1, //month
|
||||
"d+": d.getDate(), //day
|
||||
"h+": d.getHours(), //hour
|
||||
"H+": d.getHours(), //hour
|
||||
"m+": d.getMinutes(), //minute
|
||||
"s+": d.getSeconds(), //second
|
||||
"q+": Math.floor((d.getMonth() + 3) / 3), //quarter
|
||||
"S": d.getMilliseconds() //millisecond
|
||||
};
|
||||
if (/(y+)/.test(format)) {
|
||||
format = format.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp("(" + k + ")").test(format)) {
|
||||
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
|
||||
}
|
||||
}
|
||||
return format;
|
||||
|
||||
}
|
||||
|
||||
|
||||
export function dateFormat(date,format = 'yyyy-MM-dd hh:mm:ss'){
|
||||
return formatDate(date,format);
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
</BasicTable>
|
||||
</BasicDrawer>
|
||||
<a-modal width="90%" height="80%" v-model:open="postOpen" title="流程模板预览" @ok="postHandleOk">
|
||||
<a-modal width="70%" height="80%" v-model:open="postOpen" title="流程模板预览" @ok="postHandleOk">
|
||||
<process-designer :key="designerOpen" style="border:1px solid rgba(0, 0, 0, 0.1);" ref="modelDesigner"
|
||||
v-loading="designerData.loading" :pageFlow="flowContent" :pageView="content" :pageType="'detail'"
|
||||
@save="onSaveDesigner" />
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@
|
|||
},
|
||||
});
|
||||
function handleDetail(record){
|
||||
go('/dashboard/task_preview/detail?id=' + record.id);
|
||||
go('/dashboard/task_look_preview/detail?processId=' + record.id);
|
||||
}
|
||||
function handleRevocation(record){
|
||||
console.log(record)
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@
|
|||
},
|
||||
});
|
||||
function handleDetail(record){
|
||||
go('/dashboard/task_preview/detail?id=' + record.id);
|
||||
go('/dashboard/task_look_preview/detail?processId=' + record.id);
|
||||
}
|
||||
function handleRevocation(record){
|
||||
console.log(record)
|
||||
|
|
|
|||
|
|
@ -1,109 +0,0 @@
|
|||
<template>
|
||||
<PageWrapper :class="prefixCls">
|
||||
<a-tabs v-model:activeKey="activeName">
|
||||
<a-tab-pane key="form" tab="表单信息">
|
||||
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="flow" tab="流程信息" force-render>
|
||||
<div class="process-design" :style="'display: flex; height:' + designerData.height">
|
||||
<process-viewer :key="`designer-${id}`" :xml="flowContent" :flowViewer="flowViewer"/>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
||||
</PageWrapper>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount } from 'vue';
|
||||
import ProcessViewer from '@/components/ProcessViewer/index.vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { SendOutlined, SaveOutlined, CloseCircleOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
|
||||
import { getBPMN } from '@/api/sys/WFProcess'
|
||||
import { getLoadMyUserList } from '@/api/sys/WFDelegate'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { buildGUID } from '@/utils/uuid';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
|
||||
const prefixCls = 'preview-box'
|
||||
const tabStore = useMultipleTabStore();
|
||||
const router = useRouter();
|
||||
const content = ref('')
|
||||
const flowContent = ref('')
|
||||
const flowViewer = ref({})
|
||||
const route = useRoute()
|
||||
const id = route.query.id
|
||||
const designerOpen = ref(false)
|
||||
const formRef = ref();
|
||||
const labelCol = { span: 7 };
|
||||
const wrapperCol = { span: 13 };
|
||||
|
||||
const designerData = reactive({
|
||||
loading: false,
|
||||
xmlString: '',
|
||||
controlForm: {
|
||||
prefix: 'flowable',
|
||||
},
|
||||
height: document.documentElement.clientHeight - 230.5 + "px;",
|
||||
midVisible: false,
|
||||
isCustmerTitle: false,
|
||||
nodeUsers: [],
|
||||
selectUsersVisible: false,
|
||||
|
||||
isDraft: false,
|
||||
delegateUsers: []
|
||||
})
|
||||
const activeName = ref('flow')
|
||||
async function getDetailInfo() {
|
||||
let data = await getBPMN({ id: id })
|
||||
flowContent.value = data.flowContent
|
||||
flowViewer.value = data.flowViewer
|
||||
// var result = {
|
||||
// // 流程图xml
|
||||
// flowContent: "",
|
||||
// // 流程图节点id
|
||||
// flowViewer: {
|
||||
// // 完成节点id集合
|
||||
// finishedTaskSet: [],
|
||||
// // 完成线条节点id集合
|
||||
// finishedSequenceFlowSet: [],
|
||||
// // 当前节点id集合
|
||||
// unfinishedTaskSet: [],
|
||||
// // 拒绝节点id集合(暂无示例)
|
||||
// rejectedTaskSet: [],
|
||||
// }
|
||||
// // 后续还需确定需不需要节点的一些审核信息,需要的话还需要增加返回字段
|
||||
// }
|
||||
}
|
||||
function closePreview() {
|
||||
if (!id) {
|
||||
tabStore.closeTabByKey('/dashboard/task_preview/detail', router);
|
||||
} else {
|
||||
// /dashboard/create_preview/add?id=测试1
|
||||
tabStore.closeTabByKey('/dashboard/task_preview/detail?id=' + id, router);
|
||||
}
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
getDetailInfo()
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.preview-box {
|
||||
background-color: @component-background;
|
||||
|
||||
.btn-box {
|
||||
padding: 10px;
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 480px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
}
|
||||
}
|
||||
function handleDetail(record) {
|
||||
go('/dashboard/task_preview/detail?id=' + record.id);
|
||||
go('/dashboard/task_look_preview/detail?processId=' + record.id);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
},
|
||||
});
|
||||
function handleDetail(record) {
|
||||
go('/dashboard/task_preview/detail?id=' + record.id);
|
||||
go('/dashboard/task_look_preview/detail?processId=' + record.id);
|
||||
}
|
||||
async function handleUrge(record) {
|
||||
var query = {
|
||||
|
|
|
|||
|
|
@ -1,575 +1,293 @@
|
|||
<template>
|
||||
<l-fullscreen-dialog
|
||||
:title="`${title}`"
|
||||
:visible.sync="midVisible"
|
||||
:showOk="false"
|
||||
<PageWrapper :class="prefixCls">
|
||||
<a-tabs v-model:activeKey="activeName">
|
||||
<a-tab-pane key="form" tab="表单信息">
|
||||
|
||||
@closed="handleClosed"
|
||||
@opened="handleOpened"
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="flow" tab="流程信息(审核)" force-render>
|
||||
<div class="process-design" :style="'display: flex; height:' + designerData.height">
|
||||
<process-viewer :key="`designer-${id}`" :events="[
|
||||
'element.click',
|
||||
]" @element-click="elementClick" :xml="flowContent" :flowViewer="flowViewer" />
|
||||
<div class="info-box" v-if="designerData.nodeLogs.length>0" >
|
||||
<a-drawer v-model:open="infoOpen" class="custom-class" title="记录信息" placement="right">
|
||||
<a-timeline>
|
||||
<a-timeline-item v-for="(item,index) in designerData.nodeLogs" :key="index">
|
||||
<div class="title">{{item.time}}</div>
|
||||
<a-card hoverable size="small">
|
||||
<div class="type-title">{{item.name}}</div>
|
||||
<div class="content">
|
||||
<span class="link" v-for="(userName,index2) in item.userNames">{{userName}}</span>
|
||||
<!-- <l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user> -->
|
||||
{{item.des}}
|
||||
</div>
|
||||
</a-card>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</a-drawer>
|
||||
|
||||
ref="formDialog"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
||||
<template #headerRight v-if="isRead && task && task.f_State == 1" >
|
||||
<el-button size="mini" type="primary" @click="handleRead" >{{$t('确认阅读')}}</el-button>
|
||||
</template>
|
||||
</PageWrapper>
|
||||
|
||||
<l-layout class="l-tab-page" :right="400">
|
||||
<l-panel :style="{'padding-right':isRead?'':0 }" >
|
||||
<div class="l-auto-window" style="padding: 0 8px;" >
|
||||
<el-tabs v-model="activeName" @tab-click="handleTabClick" >
|
||||
<el-tab-pane v-if="hasWfForm" :label="$t('表单信息')" name="form">
|
||||
<div class="l-rblock" v-loading="formSchemeLoding">
|
||||
<template v-if="showForm" >
|
||||
<l-form-viewer
|
||||
v-if="formType == '1'"
|
||||
:formInfo="formInfo"
|
||||
:isWfForm="true"
|
||||
:authFieldsMap="formAuthFieldsMap"
|
||||
ref="wfForm"
|
||||
></l-form-viewer>
|
||||
<component ref="wfForm" v-else :requiredMap="formRequiredMap" :authFieldsMap="formAuthFieldsMap" :isWfForm="true" :is="sysFormComponent"></component>
|
||||
</template>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('流程信息')" name="wfinfo">
|
||||
<l-layout style="background: #f1f2f5;" :right="320">
|
||||
<l-panel class="flow-panel" style="padding:0;padding-top:0;" >
|
||||
<template #title>
|
||||
<el-button-group>
|
||||
<el-tooltip effect="dark" :content="$t('复原')" placement="bottom">
|
||||
<el-button size="mini" icon="el-icon-aim" @click="resetZoom"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" :content="$t('放大')" placement="bottom">
|
||||
<el-button size="mini" icon="el-icon-zoom-in" @click="handlerZoom(0.1)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" :content="$t('缩小')" placement="bottom">
|
||||
<el-button size="mini" icon="el-icon-zoom-out" @click="handlerZoom(-0.1)"></el-button>
|
||||
</el-tooltip>
|
||||
</el-button-group>
|
||||
|
||||
<div style="float:right;" >
|
||||
<el-tag size="small" effect="plain" style="margin-right: 8px;">正在审核</el-tag>
|
||||
<el-tag size="small" effect="plain" style="margin-right: 8px;" type="success">已审核</el-tag>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<b-wflow-viewer
|
||||
ref="bflow"
|
||||
@elementClick="elementClick"
|
||||
>
|
||||
</b-wflow-viewer>
|
||||
</l-panel>
|
||||
<template #right >
|
||||
<l-panel v-if="nodeLogs.length>0" class="flow-panel" style="padding:0;padding-top:0;" >
|
||||
<template #title >
|
||||
记录信息
|
||||
</template>
|
||||
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
|
||||
<el-timeline>
|
||||
<el-timeline-item :type="item.type" v-for="(item,index) in nodeLogs" :key="index" :timestamp="item.time" placement="top">
|
||||
<el-card shadow="hover">
|
||||
<div class="title" >{{item.name}}</div>
|
||||
<div class="content">
|
||||
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
|
||||
{{item.des}}
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</l-panel>
|
||||
</template>
|
||||
</l-layout>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('流转记录')" name="wflogs">
|
||||
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
|
||||
<el-timeline>
|
||||
<el-timeline-item :type="item.type" v-for="(item,index) in logs" :key="index" :timestamp="item.time" placement="top">
|
||||
<el-card shadow="hover">
|
||||
<div class="title" >{{item.name}}</div>
|
||||
<div class="content">
|
||||
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
|
||||
{{item.des}}
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</l-panel>
|
||||
|
||||
<template #right v-if="!isRead">
|
||||
<l-panel style="padding-left:0;" title="审批栏" >
|
||||
<div class="l-rblock" style="padding:8px;" >
|
||||
<el-form :model="formData" :rules="myRules" size="mini" ref="form" >
|
||||
<el-form-item :label="isCreateAgain?'备注':'审批意见'" prop="des">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model="formData.des"
|
||||
placeholder="请输入"
|
||||
|
||||
rows="3"
|
||||
>
|
||||
</el-input >
|
||||
</el-form-item>
|
||||
<el-form-item class="l-task-btns" >
|
||||
<el-button v-for="(btn,index) in taskBtns" :key="index" :type="btn.type" @click="handleBtnClick(btn)" >{{btn.name}}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<l-wf-audit-info :data="userLogs" ></l-wf-audit-info>
|
||||
</div>
|
||||
</l-panel>
|
||||
</template>
|
||||
</l-layout>
|
||||
|
||||
|
||||
<l-dialog
|
||||
:width="500"
|
||||
:height="nodeUsers.length * 48 + 88"
|
||||
title="选择下一审核节点人员"
|
||||
:visible.sync="selectUsersVisible"
|
||||
@ok="handleSelectUsersSave"
|
||||
@close="handleSelectUsersCloseForm"
|
||||
|
||||
:showClose="false"
|
||||
>
|
||||
<select-users ref="selectUsers" :nodeList="nodeUsers"></select-users>
|
||||
</l-dialog>
|
||||
|
||||
<l-dialog
|
||||
:title="$t(tUserType == 1?`选择转移人员`:`选择加签人员`)"
|
||||
:visible.sync="selectTUserVisible"
|
||||
:height="480"
|
||||
width="1024px"
|
||||
:hasBtns="false"
|
||||
>
|
||||
<l-user-select-panel @change="handleChange" :multiple="false" ref="userSelectPanel" ></l-user-select-panel>
|
||||
</l-dialog>
|
||||
|
||||
<l-dialog
|
||||
:title="$t('驳回节点选择')"
|
||||
:visible.sync="selectRejectNodeVisible"
|
||||
:height="136"
|
||||
:width="500"
|
||||
|
||||
@ok="handleSelectRejectNodeSave"
|
||||
@close="handleRejectNodeCloseForm"
|
||||
|
||||
:showClose="false"
|
||||
>
|
||||
<select-reject-node ref="selectRejectNode" :nodeList="completedNodes"></select-reject-node>
|
||||
</l-dialog>
|
||||
|
||||
<!--选择签章-->
|
||||
<l-dialog
|
||||
:title="$t('选择签章')"
|
||||
:visible.sync="selectSignVisible"
|
||||
:height="480"
|
||||
:width="508"
|
||||
|
||||
@ok="handleSelectSignSave"
|
||||
@closed="handleSelectSignCloseForm"
|
||||
@opened="handleSelectSignOpenForm"
|
||||
>
|
||||
<select-sign ref="SelectSign" ></select-sign>
|
||||
</l-dialog>
|
||||
</l-fullscreen-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from '../../../mixins/wf'
|
||||
import SelectUsers from './selectAuditUsers.vue'
|
||||
import SelectRejectNode from './selectRejectNode.vue'
|
||||
import SelectSign from './selectSign.vue'
|
||||
<script lang="ts" setup>
|
||||
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount } from 'vue';
|
||||
import ProcessViewer from '@/components/ProcessViewer/index.vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { SendOutlined, SaveOutlined, CloseCircleOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
|
||||
import { getBPMN } from '@/api/sys/WFProcess'
|
||||
import { getLoadMyUserList } from '@/api/sys/WFDelegate'
|
||||
import { getTaskDetail } from '@/api/sys/WFTask'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { buildGUID } from '@/utils/uuid';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { dateFormat } from '@/utils/base'
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
|
||||
const api = window.$api.workflow.process
|
||||
const apiStamp = window.$api.workflow.stamp
|
||||
|
||||
export default {
|
||||
mixins:[mixin()],
|
||||
components:{
|
||||
SelectUsers,
|
||||
SelectRejectNode,
|
||||
SelectSign
|
||||
const prefixCls = 'preview-box'
|
||||
const tabStore = useMultipleTabStore();
|
||||
const router = useRouter();
|
||||
const content = ref('')
|
||||
const flowContent = ref('')
|
||||
const flowViewer = ref({})
|
||||
const route = useRoute()
|
||||
const processId = route.query.processId
|
||||
const taskId = route.query.taskId
|
||||
const designerOpen = ref(false)
|
||||
const formRef = ref();
|
||||
const labelCol = { span: 7 };
|
||||
const wrapperCol = { span: 13 };
|
||||
const infoOpen = ref(true)
|
||||
const designerData = reactive({
|
||||
loading: false,
|
||||
xmlString: '',
|
||||
controlForm: {
|
||||
prefix: 'flowable',
|
||||
},
|
||||
props:{
|
||||
isCreateAgain:Boolean,
|
||||
isRead:Boolean
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
midVisible:false,
|
||||
formData:{
|
||||
des:''
|
||||
},
|
||||
rules:{
|
||||
des:[
|
||||
{ required: true, message: '请填写审批意见',trigger: 'blur' }
|
||||
],
|
||||
},
|
||||
height: document.documentElement.clientHeight - 200.5 + "px;",
|
||||
midVisible: false,
|
||||
isCustmerTitle: false,
|
||||
nodeUsers: [],
|
||||
selectUsersVisible: false,
|
||||
|
||||
currentBtn:null,
|
||||
|
||||
nodeUsers:[],
|
||||
selectUsersVisible:false,
|
||||
selectTUserVisible:false,
|
||||
tUserType:1, // 1 转移 2 加签,
|
||||
|
||||
selectRejectNodeVisible:false, // 驳回节点选择
|
||||
selectSignVisible:false, // 选择签章
|
||||
stampList:[]
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
myRules(){
|
||||
if(this.isCreateAgain || this.isRead){
|
||||
return {}
|
||||
}
|
||||
else{
|
||||
return this.rules
|
||||
}
|
||||
},
|
||||
completedNodes(){
|
||||
const nodes = this.$deepClone(this.wfData)
|
||||
return nodes.filter(t=>t.hasFinish && t.id != this.currentNode.id)
|
||||
},
|
||||
},
|
||||
watch:{
|
||||
visible: {
|
||||
handler (n) {
|
||||
this.midVisible = n
|
||||
}
|
||||
},
|
||||
},
|
||||
methods:{
|
||||
resetZoom(){
|
||||
this.$refs.bflow.reset()
|
||||
},
|
||||
handlerZoom(r){
|
||||
this.$refs.bflow.handlerZoom(r)
|
||||
},
|
||||
elementClick(node){
|
||||
if(node){
|
||||
this.nodeLogs = this.nodeMap[node.id] || []
|
||||
}
|
||||
else{
|
||||
this.nodeLogs = []
|
||||
}
|
||||
},
|
||||
|
||||
resetFormToMe(){
|
||||
this.$refs.form && this.$refs.form.resetFields()
|
||||
this.taskBtns = []
|
||||
},
|
||||
setForm(){
|
||||
this.$refs.form && this.$refs.form.clearValidate()
|
||||
this.currentNode = this.wfData.find(t=>t.id == this.task.f_UnitId)
|
||||
|
||||
// 设置审核按钮
|
||||
const btns = []
|
||||
if(this.currentNode.type =='startEvent'){
|
||||
btns.push({
|
||||
code:'learun_create',
|
||||
name:'提交',
|
||||
type:'primary'
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.currentNode.btnlist.forEach(btn => {
|
||||
if(btn.code == 'agree'){
|
||||
btn.type = 'primary'
|
||||
}
|
||||
else if(btn.code == 'disagree'){
|
||||
btn.type = 'danger'
|
||||
}
|
||||
btns.push(btn)
|
||||
})
|
||||
|
||||
if(this.currentNode.isAddSign){
|
||||
btns.push({
|
||||
code:'learun_sign',
|
||||
name:'加签',
|
||||
type:'success'
|
||||
})
|
||||
}
|
||||
|
||||
if(this.currentNode.isTransfer){
|
||||
btns.push({
|
||||
code:'learun_transfer',
|
||||
name:'转移',
|
||||
type:'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
this.taskBtns = btns
|
||||
},
|
||||
|
||||
validateForm(){
|
||||
return this.$formValidateWraper(this.$refs.form)
|
||||
},
|
||||
|
||||
handleBtnClick(btn){
|
||||
this.$refs.formDialog.showLoading('流程处理中...')
|
||||
this.$nextTick(async ()=>{
|
||||
this.currentBtn = btn
|
||||
|
||||
if(!(await this.validateForm())){
|
||||
this.$refs.formDialog.hideLoading()
|
||||
return
|
||||
}
|
||||
|
||||
if(!(await this.validateWfForm())){
|
||||
this.$refs.formDialog.hideLoading()
|
||||
return
|
||||
}
|
||||
|
||||
if(!(await this.saveWfForm(btn.code))){
|
||||
this.$refs.formDialog.hideLoading()
|
||||
return
|
||||
}
|
||||
let res
|
||||
switch(btn.code){
|
||||
case 'learun_create':
|
||||
res = await this.$awaitWraper(api.createAgain({
|
||||
processId:this.processId,
|
||||
des:`重新提交${this.formData.des?'-':''}${this.formData.des}`
|
||||
}))
|
||||
break
|
||||
case 'learun_sign':
|
||||
this.tUserType = 2
|
||||
this.selectTUserVisible = true
|
||||
break
|
||||
case 'learun_transfer':
|
||||
this.tUserType = 1
|
||||
this.selectTUserVisible = true
|
||||
break
|
||||
default:
|
||||
if(this.task.f_Type == 6){// 加签审核
|
||||
res = await this.$awaitWraper(api.signAudit(this.taskId,{
|
||||
code:btn.code,
|
||||
name:btn.name,
|
||||
des:this.formData.des
|
||||
}))
|
||||
}
|
||||
else {
|
||||
if(this.currentNode.rejectType == '2' && btn.code == 'disagree'){
|
||||
this.selectRejectNodeVisible = true
|
||||
this.$refs.formDialog.hideLoading()
|
||||
return
|
||||
}
|
||||
|
||||
if(btn.isSign){
|
||||
// 加载签章数据
|
||||
const stampList = await this.$awaitWraper(apiStamp.getList(this.loginInfo.f_UserId))
|
||||
|
||||
if(stampList && stampList.length >0){
|
||||
this.stampList = stampList
|
||||
this.selectSignVisible = true
|
||||
this.$refs.formDialog.hideLoading()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
res = await this.audit()
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
this.$refs.formDialog.hideLoading()
|
||||
if(res){
|
||||
this.midVisible = false
|
||||
this.$emit('refresh')
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async audit(){
|
||||
// 获取接下来节点审核人
|
||||
if(this.currentBtn.isNextAuditor){
|
||||
const res = await api.getNextUsers({processId:this.processId,nodeId:this.currentNode.id})
|
||||
const nodeUserMap = res.data.data
|
||||
const nodeUsers = []
|
||||
for(let key in nodeUserMap){
|
||||
const nodeUserItem = nodeUserMap[key]
|
||||
if(nodeUserItem.length > 1){
|
||||
nodeUsers.push({
|
||||
name:this.wfData.find(t=>t.id == key).name,
|
||||
id:key,
|
||||
options:nodeUserItem.map(t=>{return{value:t.id,label:t.name} })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.nodeUsers = nodeUsers
|
||||
|
||||
if(this.nodeUsers.length > 0){
|
||||
this.selectUsersVisible = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return await this.$awaitWraper(api.audit(this.taskId,{
|
||||
code:this.currentBtn.code,
|
||||
name:this.currentBtn.name,
|
||||
des:this.formData.des
|
||||
}))
|
||||
},
|
||||
|
||||
|
||||
|
||||
handleSelectUsersSave(){
|
||||
this.selectUsersVisible = false
|
||||
this.$refs.formDialog.showLoading('流程处理中...')
|
||||
const nextUsers = this.$refs.selectUsers.getForm()
|
||||
this.$nextTick(async ()=>{
|
||||
const res = await this.$awaitWraper(api.audit(this.taskId,{
|
||||
code:this.currentBtn.code,
|
||||
name:this.currentBtn.name,
|
||||
nextUsers: nextUsers,
|
||||
des:this.formData.des
|
||||
}))
|
||||
if(res){
|
||||
this.midVisible = false
|
||||
}
|
||||
this.$refs.formDialog.hideLoading()
|
||||
this.$emit('refresh')
|
||||
})
|
||||
},
|
||||
handleSelectUsersCloseForm(){
|
||||
this.$refs.selectUsers.resetForm()
|
||||
},
|
||||
handleChange(userInfo){
|
||||
if(userInfo){
|
||||
const title = this.tUserType == 1?'转移':'加签'
|
||||
if(this.loginInfo.f_UserId == userInfo.f_UserId){
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: `${title}不能给自己本人`
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
this.$confirm(`是否确定${title}给${userInfo.f_RealName}?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.selectTUserVisible = false
|
||||
this.$refs.formDialog.showLoading('流程处理中...')
|
||||
|
||||
this.$nextTick(async ()=>{
|
||||
let res
|
||||
|
||||
if(this.tUserType == 1){
|
||||
res = await this.$awaitWraper(api.transferUser(this.taskId,{
|
||||
toUserId:userInfo.f_UserId,
|
||||
des:`转移给${userInfo.f_RealName}${this.formData.des?'-':''}${this.formData.des}`
|
||||
}))
|
||||
}
|
||||
else{
|
||||
res = await this.$awaitWraper(api.sign(this.taskId,{
|
||||
toUserId:userInfo.f_UserId,
|
||||
des:`加签给${userInfo.f_RealName}${this.formData.des?'-':''}${this.formData.des}`
|
||||
}))
|
||||
}
|
||||
|
||||
this.$refs.formDialog.hideLoading()
|
||||
|
||||
if(res){
|
||||
this.midVisible = false
|
||||
this.$emit('refresh')
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: `已取消${title}`
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
async handleSelectRejectNodeSave(){
|
||||
if(await this.$refs.selectRejectNode.validateForm()){
|
||||
this.$refs.formDialog.showLoading('流程处理中...')
|
||||
const nextId = this.$refs.selectRejectNode.getForm()
|
||||
this.selectRejectNodeVisible = false
|
||||
this.$nextTick(async ()=>{
|
||||
const res = await this.$awaitWraper(api.audit(this.taskId,{
|
||||
code:this.currentBtn.code,
|
||||
name:this.currentBtn.name,
|
||||
nextId: nextId,
|
||||
des:this.formData.des
|
||||
}))
|
||||
if(res){
|
||||
this.midVisible = false
|
||||
}
|
||||
this.$refs.formDialog.hideLoading()
|
||||
this.$emit('refresh')
|
||||
})
|
||||
}
|
||||
},
|
||||
handleRejectNodeCloseForm(){
|
||||
this.$refs.selectRejectNode.resetForm()
|
||||
},
|
||||
|
||||
async handleRead(){
|
||||
|
||||
this.$refs.formDialog.showLoading('流程处理中...')
|
||||
const res = await this.$awaitWraper(api.readAudit(this.taskId))
|
||||
if(res){
|
||||
this.midVisible = false
|
||||
}
|
||||
this.$refs.formDialog.hideLoading()
|
||||
this.$emit('refresh')
|
||||
},
|
||||
|
||||
|
||||
// 签章
|
||||
async handleSelectSignSave(){
|
||||
if(await this.$refs.SelectSign.validateForm()){
|
||||
this.$refs.formDialog.showLoading('流程处理中...')
|
||||
const {f_StampId,f_Password} = this.$refs.SelectSign.getForm()
|
||||
this.selectSignVisible = false
|
||||
this.$nextTick(async ()=>{
|
||||
const res = await this.$awaitWraper(api.audit(this.taskId,{
|
||||
code:this.currentBtn.code,
|
||||
name:this.currentBtn.name,
|
||||
stampImg:f_StampId,
|
||||
stampPassWord:f_Password,
|
||||
des:this.formData.des
|
||||
}))
|
||||
if(res){
|
||||
this.midVisible = false
|
||||
}
|
||||
this.$refs.formDialog.hideLoading()
|
||||
this.$emit('refresh')
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
handleSelectSignCloseForm(){
|
||||
this.$refs.SelectSign.resetForm()
|
||||
},
|
||||
handleSelectSignOpenForm(){
|
||||
this.$refs.SelectSign.setForm(this.stampList)
|
||||
}
|
||||
isDraft: false,
|
||||
delegateUsers: [],
|
||||
task: null,
|
||||
process: null,
|
||||
logs: [],// 流程日志信息
|
||||
nodeMap: {},// 需要处理的任务
|
||||
userLogs: [],// 人员日志信息
|
||||
nodeLogs: [],
|
||||
taskBtns: [],
|
||||
})
|
||||
const activeName = ref('flow')
|
||||
function elementClick(element) {
|
||||
console.log('elementClick')
|
||||
console.log(element)
|
||||
if (element) {
|
||||
designerData.nodeLogs = designerData.nodeMap[element.id] || []
|
||||
infoOpen.value = true
|
||||
}
|
||||
}
|
||||
else {
|
||||
designerData.nodeLogs = []
|
||||
}
|
||||
}
|
||||
async function getDetailInfo() {
|
||||
let data = await getBPMN({ id: processId })
|
||||
flowContent.value = data.flowContent
|
||||
flowViewer.value = data.flowViewer
|
||||
}
|
||||
async function getTaskInfo() {
|
||||
let data = await getTaskDetail({ id: taskId })
|
||||
designerData.process = data.process
|
||||
designerData.task = data.task
|
||||
setLogsAndTasks(data.logs, data.tasks)
|
||||
}
|
||||
function setLogsAndTasks(logs, tasks) {
|
||||
const res = []
|
||||
const taskMap = {}
|
||||
const nodeMap = {}
|
||||
const userLogs = []
|
||||
|
||||
tasks.forEach(task => {
|
||||
nodeMap[task.unitId] = nodeMap[task.unitId] || [{
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
userNames: [],
|
||||
des: '正在审核',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary',
|
||||
isFinish: false
|
||||
}]
|
||||
|
||||
if (task.type == 2) {
|
||||
|
||||
taskMap[task.unitId + task.type] = taskMap[task.unitId + task.type] || {
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
userNames: [],
|
||||
des: '正在查阅',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary'
|
||||
}
|
||||
taskMap[task.unitId + task.type].userIds.push(task.userId)
|
||||
taskMap[task.unitId + task.type].userNames.push(task.userName)
|
||||
|
||||
if (nodeMap[task.unitId].length == 1) {
|
||||
nodeMap[task.unitId].push({
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
userNames: [],
|
||||
des: '正在查阅',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary',
|
||||
isFinish: true
|
||||
})
|
||||
}
|
||||
nodeMap[task.unitId][1].userIds.push(task.userId)
|
||||
nodeMap[task.unitId][1].userNames.push(task.userName)
|
||||
|
||||
}
|
||||
else {
|
||||
taskMap[task.unitId] = taskMap[task.unitId] || {
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
userNames: [],
|
||||
des: '正在审核',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary'
|
||||
}
|
||||
taskMap[task.unitId].userIds.push(task.userId)
|
||||
nodeMap[task.unitId][0].userIds.push(task.userId)
|
||||
taskMap[task.unitId].userNames.push(task.userName)
|
||||
nodeMap[task.unitId][0].userNames.push(task.userName)
|
||||
}
|
||||
})
|
||||
|
||||
for (let key in taskMap) {
|
||||
res.push(taskMap[key])
|
||||
}
|
||||
|
||||
for (let key in nodeMap) {
|
||||
nodeMap[key] = nodeMap[key].filter(t => t.userIds.length > 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
logs.forEach(log => {
|
||||
res.push({
|
||||
unitId: log.unitId,
|
||||
name: log.unitName,
|
||||
userIds: [log.userId],
|
||||
userNames: [log.userName],
|
||||
des: log.des ? log.des : log.f_OperationName,
|
||||
time: dateFormat(log.createDate),
|
||||
type: 'info'
|
||||
})
|
||||
|
||||
nodeMap[log.unitId] = nodeMap[log.unitId] || []
|
||||
nodeMap[log.unitId].push({
|
||||
unitId: log.unitId,
|
||||
name: log.unitName,
|
||||
userIds: [log.userId],
|
||||
userNames: [log.userName],
|
||||
time: dateFormat(log.createDate),
|
||||
des: log.des ? log.des : log.f_OperationName,
|
||||
type: 'info',
|
||||
isFinish: true
|
||||
})
|
||||
|
||||
if (log.f_TaskType == 1 && !['sign'].includes(log.f_OperationCode)) { // 右侧显示审核记录
|
||||
const userLogIndex = userLogs.findIndex(t => t.id == log.unitId)
|
||||
if (userLogIndex == -1) {
|
||||
userLogs.push({
|
||||
id: log.unitId,
|
||||
name: log.unitName,
|
||||
user: log.f_UserName,
|
||||
time: dateFormat(log.createDate),
|
||||
des: log.des,
|
||||
img: log.f_StampImg
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
designerData.logs = res
|
||||
designerData.nodeMap = nodeMap
|
||||
designerData.userLogs = userLogs.sort(function (a, b) {
|
||||
return b.time < a.time ? -1 : 1
|
||||
})
|
||||
|
||||
|
||||
//console.log(logs,'logs')
|
||||
}
|
||||
|
||||
function closePreview() {
|
||||
if (!id) {
|
||||
tabStore.closeTabByKey('/dashboard/task_preview/detail', router);
|
||||
} else {
|
||||
// /dashboard/create_preview/add?id=测试1
|
||||
tabStore.closeTabByKey('/dashboard/task_preview/detail?id=' + id, router);
|
||||
}
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
getDetailInfo()
|
||||
getTaskInfo()
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.info-box {
|
||||
display: inline-block;
|
||||
width: 300px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-top: 40px;
|
||||
|
||||
<style lang="scss">
|
||||
.l-task-btns{
|
||||
.el-button{
|
||||
margin: 0;
|
||||
margin-top: 8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.ant-timeline-item-content {
|
||||
.title {
|
||||
color: #909399;
|
||||
line-height: 1;
|
||||
margin-bottom: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.type-title {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.link{
|
||||
color:#409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-box {
|
||||
background-color: @component-background;
|
||||
height: 100%;
|
||||
|
||||
.btn-box {
|
||||
padding: 10px;
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 480px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,153 +1,229 @@
|
|||
<template>
|
||||
<l-fullscreen-dialog
|
||||
:title="`${$t('查看流程')}【${title}】`"
|
||||
:visible.sync="midVisible"
|
||||
:showOk="false"
|
||||
|
||||
@closed="handleClosed"
|
||||
@opened="handleOpened"
|
||||
|
||||
ref="formDialog"
|
||||
>
|
||||
<l-layout class="l-tab-page" :right="400">
|
||||
<l-panel :style="{ 'padding-right':userLogs.length >0?0:''}" >
|
||||
<div class="l-auto-window" style="padding: 0 8px;" >
|
||||
<el-tabs v-model="activeName" @tab-click="handleTabClick" >
|
||||
<el-tab-pane v-if="hasWfForm" :label="$t('表单信息')" name="form">
|
||||
<div class="l-rblock" v-loading="formSchemeLoding">
|
||||
<template v-if="showForm" >
|
||||
<l-form-viewer
|
||||
v-if="formType == '1'"
|
||||
:formInfo="formInfo"
|
||||
:isWfForm="true"
|
||||
:authFieldsMap="formAuthFieldsMap"
|
||||
ref="wfForm"
|
||||
></l-form-viewer>
|
||||
<component ref="wfForm" v-else :requiredMap="formRequiredMap" :authFieldsMap="formAuthFieldsMap" :isWfForm="true" :is="sysFormComponent"></component>
|
||||
</template>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('流程信息')" name="wfinfo">
|
||||
<l-layout style="background: #f1f2f5;" :right="320">
|
||||
<l-panel class="flow-panel" style="padding:0;padding-top:0;" >
|
||||
<template #title>
|
||||
<el-button-group>
|
||||
<el-tooltip effect="dark" :content="$t('复原')" placement="bottom">
|
||||
<el-button size="mini" icon="el-icon-aim" @click="resetZoom"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" :content="$t('放大')" placement="bottom">
|
||||
<el-button size="mini" icon="el-icon-zoom-in" @click="handlerZoom(0.1)"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" :content="$t('缩小')" placement="bottom">
|
||||
<el-button size="mini" icon="el-icon-zoom-out" @click="handlerZoom(-0.1)"></el-button>
|
||||
</el-tooltip>
|
||||
</el-button-group>
|
||||
|
||||
<div style="float:right;" >
|
||||
<el-tag size="small" effect="plain" style="margin-right: 8px;">正在审核</el-tag>
|
||||
<el-tag size="small" effect="plain" style="margin-right: 8px;" type="success">已审核</el-tag>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<b-wflow-viewer
|
||||
ref="bflow"
|
||||
@elementClick="elementClick"
|
||||
>
|
||||
</b-wflow-viewer>
|
||||
</l-panel>
|
||||
<template #right >
|
||||
<l-panel v-if="nodeLogs.length>0" class="flow-panel" style="padding:0;padding-top:0;" >
|
||||
<template #title >
|
||||
记录信息
|
||||
</template>
|
||||
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
|
||||
<el-timeline>
|
||||
<el-timeline-item :type="item.type" v-for="(item,index) in nodeLogs" :key="index" :timestamp="item.time" placement="top">
|
||||
<el-card shadow="hover">
|
||||
<div class="title" >{{item.name}}</div>
|
||||
<div class="content">
|
||||
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
|
||||
{{item.des}}
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</l-panel>
|
||||
</template>
|
||||
</l-layout>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('流转记录')" name="wflogs">
|
||||
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
|
||||
<el-timeline>
|
||||
<el-timeline-item :type="item.type" v-for="(item,index) in logs" :key="index" :timestamp="item.time" placement="top">
|
||||
<el-card shadow="hover">
|
||||
<div class="title" >{{item.name}}</div>
|
||||
<div class="content">
|
||||
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
|
||||
{{item.des}}
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</l-panel>
|
||||
<template #right >
|
||||
<l-panel v-if="userLogs.length >0" style="padding-left:0;" title="审批信息" >
|
||||
<div class="l-rblock" style="padding:8px;" >
|
||||
<l-wf-audit-info :data="userLogs" ></l-wf-audit-info>
|
||||
</div>
|
||||
</l-panel>
|
||||
</template>
|
||||
</l-layout>
|
||||
</l-fullscreen-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from '../../../mixins/wf'
|
||||
export default {
|
||||
mixins:[mixin()],
|
||||
data () {
|
||||
return {
|
||||
midVisible:false,
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
visible: {
|
||||
handler (n) {
|
||||
this.midVisible = n
|
||||
}
|
||||
},
|
||||
},
|
||||
methods:{
|
||||
resetZoom(){
|
||||
this.$refs.bflow.reset()
|
||||
},
|
||||
handlerZoom(r){
|
||||
this.$refs.bflow.handlerZoom(r)
|
||||
},
|
||||
elementClick(node){
|
||||
if(node){
|
||||
this.nodeLogs = this.nodeMap[node.id] || []
|
||||
}
|
||||
else{
|
||||
this.nodeLogs = []
|
||||
}
|
||||
},
|
||||
setForm(){
|
||||
if(this.type == 'look' && this.task)
|
||||
{
|
||||
this.currentNode = this.wfData.find(t=>t.id == this.task.f_UnitId)
|
||||
|
||||
}
|
||||
else{
|
||||
this.currentNode = this.wfData.find(t=>t.type == 'startEvent')
|
||||
}
|
||||
|
||||
}
|
||||
<PageWrapper :class="prefixCls">
|
||||
<a-tabs v-model:activeKey="activeName">
|
||||
<a-tab-pane key="form" tab="表单信息">
|
||||
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="flow" tab="流程信息" force-render>
|
||||
<div class="process-design" :style="'display: flex; height:' + designerData.height">
|
||||
<process-viewer :key="`designer-${id}`" :events="[
|
||||
'element.click',
|
||||
]" @element-click="elementClick" :xml="flowContent" :flowViewer="flowViewer" />
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
||||
</PageWrapper>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount } from 'vue';
|
||||
import ProcessViewer from '@/components/ProcessViewer/index.vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { SendOutlined, SaveOutlined, CloseCircleOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
|
||||
import { getBPMN } from '@/api/sys/WFProcess'
|
||||
import { getLoadMyUserList } from '@/api/sys/WFDelegate'
|
||||
import { getTaskDetail } from '@/api/sys/WFTask'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { buildGUID } from '@/utils/uuid';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import {dateFormat} from '@/utils/base'
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
|
||||
const prefixCls = 'preview-box'
|
||||
const tabStore = useMultipleTabStore();
|
||||
const router = useRouter();
|
||||
const content = ref('')
|
||||
const flowContent = ref('')
|
||||
const flowViewer = ref({})
|
||||
const route = useRoute()
|
||||
const processId = route.query.processId
|
||||
const taskId = route.query.taskId
|
||||
const designerOpen = ref(false)
|
||||
const formRef = ref();
|
||||
const labelCol = { span: 7 };
|
||||
const wrapperCol = { span: 13 };
|
||||
|
||||
const designerData = reactive({
|
||||
loading: false,
|
||||
xmlString: '',
|
||||
controlForm: {
|
||||
prefix: 'flowable',
|
||||
},
|
||||
height: document.documentElement.clientHeight - 230.5 + "px;",
|
||||
midVisible: false,
|
||||
isCustmerTitle: false,
|
||||
nodeUsers: [],
|
||||
selectUsersVisible: false,
|
||||
|
||||
isDraft: false,
|
||||
delegateUsers: [],
|
||||
task: null,
|
||||
process: null,
|
||||
logs: [],// 流程日志信息
|
||||
nodeMap: {},// 需要处理的任务
|
||||
userLogs: [],// 人员日志信息
|
||||
nodeLogs: [],
|
||||
taskBtns: [],
|
||||
})
|
||||
const activeName = ref('flow')
|
||||
function elementClick(element) {
|
||||
console.log('elementClick')
|
||||
console.log(element)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
async function getDetailInfo() {
|
||||
let data = await getBPMN({ id: processId })
|
||||
flowContent.value = data.flowContent
|
||||
flowViewer.value = data.flowViewer
|
||||
}
|
||||
async function getTaskInfo() {
|
||||
let data = await getTaskDetail({ id: taskId })
|
||||
designerData.process = data.process
|
||||
designerData.task = data.task
|
||||
setLogsAndTasks(data.logs, data.tasks)
|
||||
}
|
||||
function setLogsAndTasks(logs, tasks) {
|
||||
const res = []
|
||||
const taskMap = {}
|
||||
const nodeMap = {}
|
||||
const userLogs = []
|
||||
|
||||
tasks.forEach(task => {
|
||||
nodeMap[task.unitId] = nodeMap[task.unitId] || [{
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
des: '正在审核',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary',
|
||||
isFinish: false
|
||||
}]
|
||||
|
||||
if (task.type == 2) {
|
||||
|
||||
taskMap[task.unitId + task.type] = taskMap[task.unitId + task.type] || {
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
des: '正在查阅',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary'
|
||||
}
|
||||
taskMap[task.unitId + task.type].userIds.push(task.userId)
|
||||
|
||||
if (nodeMap[task.unitId].length == 1) {
|
||||
nodeMap[task.unitId].push({
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
des: '正在查阅',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary',
|
||||
isFinish: true
|
||||
})
|
||||
}
|
||||
nodeMap[task.unitId][1].userIds.push(task.userId)
|
||||
|
||||
}
|
||||
else {
|
||||
taskMap[task.unitId] = taskMap[task.unitId] || {
|
||||
unitId: task.unitId,
|
||||
name: task.unitName,
|
||||
userIds: [],
|
||||
des: '正在审核',
|
||||
time: `当前-创建时间:${dateFormat(task.createDate)}`,
|
||||
type: 'primary'
|
||||
}
|
||||
taskMap[task.unitId].userIds.push(task.userId)
|
||||
nodeMap[task.unitId][0].userIds.push(task.userId)
|
||||
}
|
||||
})
|
||||
|
||||
for (let key in taskMap) {
|
||||
res.push(taskMap[key])
|
||||
}
|
||||
|
||||
for (let key in nodeMap) {
|
||||
nodeMap[key] = nodeMap[key].filter(t => t.userIds.length > 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
logs.forEach(log => {
|
||||
res.push({
|
||||
unitId: log.unitId,
|
||||
name: log.unitName,
|
||||
userIds: [log.userId],
|
||||
des: log.des ? log.des : log.f_OperationName,
|
||||
time: dateFormat(log.createDate),
|
||||
type: 'info'
|
||||
})
|
||||
|
||||
nodeMap[log.unitId] = nodeMap[log.unitId] || []
|
||||
nodeMap[log.unitId].push({
|
||||
unitId: log.unitId,
|
||||
name: log.unitName,
|
||||
userIds: [log.userId],
|
||||
time: dateFormat(log.createDate),
|
||||
des: log.des ? log.des : log.f_OperationName,
|
||||
type: 'info',
|
||||
isFinish: true
|
||||
})
|
||||
|
||||
if (log.f_TaskType == 1 && !['sign'].includes(log.f_OperationCode)) { // 右侧显示审核记录
|
||||
const userLogIndex = userLogs.findIndex(t => t.id == log.unitId)
|
||||
if (userLogIndex == -1) {
|
||||
userLogs.push({
|
||||
id: log.unitId,
|
||||
name: log.unitName,
|
||||
user: log.f_UserName,
|
||||
time: dateFormat(log.createDate),
|
||||
des: log.des,
|
||||
img: log.f_StampImg
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
designerData.logs = res
|
||||
designerData.nodeMap = nodeMap
|
||||
designerData.userLogs = userLogs.sort(function (a, b) {
|
||||
return b.time < a.time ? -1 : 1
|
||||
})
|
||||
|
||||
|
||||
//console.log(logs,'logs')
|
||||
}
|
||||
|
||||
function closePreview() {
|
||||
if (!id) {
|
||||
tabStore.closeTabByKey('/dashboard/task_preview/detail', router);
|
||||
} else {
|
||||
// /dashboard/create_preview/add?id=测试1
|
||||
tabStore.closeTabByKey('/dashboard/task_preview/detail?id=' + id, router);
|
||||
}
|
||||
}
|
||||
onBeforeMount(() => {
|
||||
getDetailInfo()
|
||||
getTaskInfo()
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.preview-box {
|
||||
background-color: @component-background;
|
||||
|
||||
.btn-box {
|
||||
padding: 10px;
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 480px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -107,7 +107,7 @@
|
|||
},
|
||||
});
|
||||
function handleDetail(record){
|
||||
go('/dashboard/task_preview/detail?id=' + record.id);
|
||||
go('/dashboard/task_look_preview/detail?processId=' + record.id);
|
||||
}
|
||||
function handleRevocation(record){
|
||||
console.log(record)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue'
|
||||
import { reactive ,h} from 'vue'
|
||||
import { BasicTable, useTable, TableAction } from '@/components/Table';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { getLoadMyUncompletedPage } from '@/api/sys/WFTask'
|
||||
|
|
@ -103,7 +103,7 @@
|
|||
},
|
||||
});
|
||||
function handleDetail(record){
|
||||
go('/dashboard/task_preview/detail?id=' + record.id);
|
||||
go('/dashboard/task_audit_preview/detail?processId=' + record.processId+"&taskId="+record.id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@
|
|||
const userInfo = await userStore.login({
|
||||
password: data.password,
|
||||
account: data.account,
|
||||
mode: 'modal', //不要默认的错误提示
|
||||
mode: 'none', //不要默认的错误提示
|
||||
});
|
||||
console.log(userInfo)
|
||||
localStorage.setItem('fireUserLoginName',userInfo.name)
|
||||
|
|
|
|||
Loading…
Reference in New Issue