Commit 27d24cd0 by jason

【工作流】- 流程实例新界面修改

parent 4680a7dc
import request from '@/config/axios' import request from '@/config/axios'
import { ProcessDefinitionVO } from '@/api/bpm/model' import { ProcessDefinitionVO } from '@/api/bpm/model'
import { NodeType } from '@/components/SimpleProcessDesignerV2/src/consts'
export type Task = { export type Task = {
id: string id: string
name: string name: string
...@@ -22,6 +22,35 @@ export type ProcessInstanceVO = { ...@@ -22,6 +22,35 @@ export type ProcessInstanceVO = {
processDefinition?: ProcessDefinitionVO processDefinition?: ProcessDefinitionVO
} }
// 用户信息
export type User = {
id: number,
nickname: string,
avatar: string
}
// 审批任务信息
export type ApprovalTaskInfo = {
id: number,
ownerUser: User,
assigneeUser: User,
status: number,
reason: string
}
// 审批节点信息
export type ApprovalNodeInfo = {
id : number
name: string
nodeType: NodeType
status: number
startTime?: Date
endTime?: Date
candidateUserList?: User[]
tasks: ApprovalTaskInfo[]
}
export const getProcessInstanceMyPage = async (params: any) => { export const getProcessInstanceMyPage = async (params: any) => {
return await request.get({ url: '/bpm/process-instance/my-page', params }) return await request.get({ url: '/bpm/process-instance/my-page', params })
} }
...@@ -57,3 +86,8 @@ export const getProcessInstance = async (id: string) => { ...@@ -57,3 +86,8 @@ export const getProcessInstance = async (id: string) => {
export const getProcessInstanceCopyPage = async (params: any) => { export const getProcessInstanceCopyPage = async (params: any) => {
return await request.get({ url: '/bpm/process-instance/copy/page', params }) return await request.get({ url: '/bpm/process-instance/copy/page', params })
} }
export const getApprovalDetail = async (processInstanceId?:string, processDefinitionId?:string) => {
const param = processInstanceId ? '?processInstanceId='+ processInstanceId : '?processDefinitionId='+ processDefinitionId
return await request.get({ url: 'bpm/process-instance/get-approval-detail'+ param })
}
import request from '@/config/axios' import request from '@/config/axios'
/**
* 任务状态枚举
*/
export enum TaskStatusEnum {
/**
* 未开始
*/
NOT_START = -1,
/**
* 待审批
*/
WAIT = 0,
/**
* 审批中
*/
RUNNING = 1,
/**
* 审批通过
*/
APPROVE = 2,
/**
* 审批不通过
*/
REJECT = 3,
/**
* 已取消
*/
CANCEL = 4,
/**
* 已退回
*/
RETURN = 5,
/**
* 委派中
*/
DELEGATE = 6,
/**
* 审批通过中
*/
APPROVING = 7,
}
export type TaskVO = { export type TaskVO = {
id: number id: number
} }
......
<template> <template>
<div class="simple-flow-canvas"> <div class="simple-flow-canvas" v-loading="loading">
<div class="simple-flow-container"> <div class="simple-flow-container" >
<div class="top-area-container"> <div class="top-area-container">
<div class="top-actions"> <div class="top-actions">
<div class="canvas-control"> <div class="canvas-control">
...@@ -15,7 +15,10 @@ ...@@ -15,7 +15,10 @@
</div> </div>
</div> </div>
<div class="scale-container" :style="`transform: scale(${scaleValue / 100});`"> <div class="scale-container" :style="`transform: scale(${scaleValue / 100});`">
<ProcessNodeTree v-if="processNodeTree" v-model:flow-node="processNodeTree" /> <ProcessNodeTree
v-if="processNodeTree"
v-model:flow-node="processNodeTree"
/>
</div> </div>
</div> </div>
<Dialog v-model="errorDialogVisible" title="保存失败" width="400" :fullscreen="false"> <Dialog v-model="errorDialogVisible" title="保存失败" width="400" :fullscreen="false">
...@@ -46,6 +49,7 @@ import * as DeptApi from '@/api/system/dept' ...@@ -46,6 +49,7 @@ import * as DeptApi from '@/api/system/dept'
import * as PostApi from '@/api/system/post' import * as PostApi from '@/api/system/post'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import * as UserGroupApi from '@/api/bpm/userGroup' import * as UserGroupApi from '@/api/bpm/userGroup'
import { fa } from 'element-plus/es/locale'
defineOptions({ defineOptions({
name: 'SimpleProcessDesigner' name: 'SimpleProcessDesigner'
}) })
...@@ -56,7 +60,7 @@ const props = defineProps({ ...@@ -56,7 +60,7 @@ const props = defineProps({
required: true required: true
} }
}) })
const loading = ref(true)
const formFields = ref<string[]>([]) const formFields = ref<string[]>([])
const formType = ref(20) const formType = ref(20)
const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表 const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表
...@@ -163,44 +167,49 @@ const zoomIn = () => { ...@@ -163,44 +167,49 @@ const zoomIn = () => {
} }
onMounted(async () => { onMounted(async () => {
// 获取表单字段 try {
const bpmnModel = await getModel(props.modelId) loading.value = true
if (bpmnModel) { // 获取表单字段
formType.value = bpmnModel.formType const bpmnModel = await getModel(props.modelId)
if (formType.value === 10) { if (bpmnModel) {
const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO formType.value = bpmnModel.formType
formFields.value = bpmnForm?.fields if (formType.value === 10) {
const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
formFields.value = bpmnForm?.fields
}
} }
} // 获得角色列表
// 获得角色列表 roleOptions.value = await RoleApi.getSimpleRoleList()
roleOptions.value = await RoleApi.getSimpleRoleList() // 获得岗位列表
// 获得岗位列表 postOptions.value = await PostApi.getSimplePostList()
postOptions.value = await PostApi.getSimplePostList() // 获得用户列表
// 获得用户列表 userOptions.value = await UserApi.getSimpleUserList()
userOptions.value = await UserApi.getSimpleUserList() // 获得部门列表
// 获得部门列表 deptOptions.value = await DeptApi.getSimpleDeptList()
deptOptions.value = await DeptApi.getSimpleDeptList()
deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id') deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id')
// 获取用户组列表 // 获取用户组列表
userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList() userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
// 获取 SIMPLE 设计器模型 // 获取 SIMPLE 设计器模型
const result = await getBpmSimpleModel(props.modelId) const result = await getBpmSimpleModel(props.modelId)
if (result) { if (result) {
processNodeTree.value = result processNodeTree.value = result
} else { } else {
// 初始值 // 初始值
processNodeTree.value = { processNodeTree.value = {
name: '发起人', name: '发起人',
type: NodeType.START_USER_NODE, type: NodeType.START_USER_NODE,
id: NodeId.START_USER_NODE_ID, id: NodeId.START_USER_NODE_ID,
childNode: { childNode: {
id: NodeId.END_EVENT_NODE_ID, id: NodeId.END_EVENT_NODE_ID,
name: '结束', name: '结束',
type: NodeType.END_EVENT_NODE type: NodeType.END_EVENT_NODE
}
} }
} }
} finally {
loading.value = false
} }
}) })
</script> </script>
...@@ -292,7 +292,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ ...@@ -292,7 +292,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
}, },
{ {
path: 'process-instance/detail', path: 'process-instance/detail',
component: () => import('@/views/bpm/processInstance/detail/index.vue'), component: () => import('@/views/bpm/processInstance/detail/index_new.vue'),
name: 'BpmProcessInstanceDetail', name: 'BpmProcessInstanceDetail',
meta: { meta: {
noCache: true, noCache: true,
......
<template> <template>
<div <div
class="h-50px position-fixed bottom-10 text-14px flex items-center color-#32373c dark:color-#fff font-bold btn-container" class="h-50px bottom-10 text-14px flex items-center color-#32373c dark:color-#fff font-bold btn-container"
> >
<el-popover :visible="passVisible" placement="top-end" :width="500" trigger="click"> <el-popover :visible="passVisible" placement="top-end" :width="500" trigger="click">
<template #reference> <template #reference>
...@@ -120,6 +120,7 @@ ...@@ -120,6 +120,7 @@
<div @click="handleSign"> <Icon :size="14" icon="ep:plus" />&nbsp;加签 </div> <div @click="handleSign"> <Icon :size="14" icon="ep:plus" />&nbsp;加签 </div>
<div @click="handleBack"> <Icon :size="14" icon="fa:mail-reply" />&nbsp;退回 </div> <div @click="handleBack"> <Icon :size="14" icon="fa:mail-reply" />&nbsp;退回 </div>
</div> </div>
<!-- </div> -->
<!-- 弹窗:转派审批人 --> <!-- 弹窗:转派审批人 -->
<TaskTransferForm ref="taskTransferFormRef" @success="getDetail" /> <TaskTransferForm ref="taskTransferFormRef" @success="getDetail" />
<!-- 弹窗:回退节点 --> <!-- 弹窗:回退节点 -->
...@@ -299,10 +300,11 @@ defineExpose({ loadRunningTask }) ...@@ -299,10 +300,11 @@ defineExpose({ loadRunningTask })
.btn-container { .btn-container {
> div { > div {
display: flex;
margin: 0 15px; margin: 0 15px;
cursor: pointer; cursor: pointer;
display: flex;
align-items: center; align-items: center;
&:hover { &:hover {
color: #6db5ff; color: #6db5ff;
} }
......
<template> <template>
<ContentWrap :bodyStyle="{ padding: '10px 20px' }" class="position-relative"> <ContentWrap :bodyStyle="{ padding: '10px 20px' }" class="position-relative">
<img <div class="processInstance-wrap-main">
class="position-absolute right-20px" <el-scrollbar>
width="150" <img
:src="auditIcons[processInstance.status]" class="position-absolute right-20px"
alt="" width="150"
/> :src="auditIcons[processInstance.status]"
<div class="text-#878c93">编号:{{ id }}</div> alt=""
<el-divider class="!my-8px" /> />
<div class="flex items-center gap-5 mb-10px"> <div class="text-#878c93 h-15px">编号:{{ id }}</div>
<div class="text-26px font-bold mb-5px">{{ processInstance.name }}</div> <el-divider class="!my-8px" />
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="processInstance.status" /> <div class="flex items-center gap-5 mb-10px h-40px">
</div> <div class="text-26px font-bold mb-5px">{{ processInstance.name }}</div>
<dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS" :value="processInstance.status" />
</div>
<div class="flex items-center gap-5 mb-10px text-13px"> <div class="flex items-center gap-5 mb-10px text-13px h-35px">
<div class="bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600"> <div
<img class="rounded-full h-28px" src="@/assets/imgs/avatar.jpg" alt="" /> class="bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600"
{{ processInstance?.startUser?.nickname }} >
</div> <img class="rounded-full h-28px" src="@/assets/imgs/avatar.jpg" alt="" />
<div class="text-#878c93"> {{ formatDate(processInstance.startTime) }} 提交 </div> {{ processInstance?.startUser?.nickname }}
</div> </div>
<div class="text-#878c93"> {{ formatDate(processInstance.startTime) }} 提交 </div>
</div>
<el-tabs> <el-tabs v-model="activeTab">
<!-- 表单信息 --> <!-- 表单信息 -->
<el-tab-pane label="表单信息"> <el-tab-pane label="表单信息" name="form">
<el-row :gutter="10"> <div class="form-scoll-area">
<el-col :span="18" class="!flex !flex-col formCol"> <el-scrollbar>
<!-- 表单信息 --> <el-row :gutter="10">
<div v-loading="processInstanceLoading" class="form-box flex flex-col mb-30px flex-1"> <el-col :span="18" class="!flex !flex-col formCol">
<!-- 情况一:流程表单 --> <!-- 表单信息 -->
<el-col <div
v-if="processInstance?.processDefinition?.formType === 10" v-loading="processInstanceLoading"
:offset="6" class="form-box flex flex-col mb-30px flex-1"
:span="16" >
> <!-- 情况一:流程表单 -->
<form-create <el-col
v-model="detailForm.value" v-if="processInstance?.processDefinition?.formType === 10"
v-model:api="fApi" :offset="6"
:option="detailForm.option" :span="16"
:rule="detailForm.rule" >
/> <form-create
</el-col> v-model="detailForm.value"
<!-- 情况二:业务表单 --> v-model:api="fApi"
<div v-if="processInstance?.processDefinition?.formType === 20"> :option="detailForm.option"
<BusinessFormComponent :id="processInstance.businessKey" /> :rule="detailForm.rule"
</div> />
</el-col>
<!-- 情况二:业务表单 -->
<div v-if="processInstance?.processDefinition?.formType === 20">
<BusinessFormComponent :id="processInstance.businessKey" />
</div>
</div>
</el-col>
<el-col :span="6">
<!-- 审批记录时间线 -->
<ProcessInstanceTimeline :process-instance-id="id" />
</el-col>
</el-row>
</el-scrollbar>
</div> </div>
</el-tab-pane>
<!-- 操作栏按钮 --> <!-- 流程图 -->
<ProcessInstanceOperationButton <el-tab-pane label="流程图" name="diagram">
ref="operationButtonRef" <ProcessInstanceBpmnViewer
:processInstance="processInstance" :id="`${id}`"
:userOptions="userOptions" :bpmn-xml="bpmnXml"
@success="getDetail" :loading="processInstanceLoading"
:process-instance="processInstance"
:tasks="tasks"
/> />
</el-col> </el-tab-pane>
<el-col :span="6"> <!-- 流转记录 -->
<!-- 审批记录时间线 --> <el-tab-pane label="流转记录" name="record">
<ProcessInstanceTimeline :process-instance="processInstance" :tasks="tasks" /> <ProcessInstanceTaskList
</el-col> :loading="tasksLoad"
</el-row> :process-instance="processInstance"
</el-tab-pane> :tasks="tasks"
<!-- 流程图 --> @refresh="getTaskList"
<el-tab-pane label="流程图"> />
<ProcessInstanceBpmnViewer </el-tab-pane>
:id="`${id}`" <!-- 流转评论 -->
:bpmn-xml="bpmnXml" <el-tab-pane label="流转评论" name="comment"> 流转评论 </el-tab-pane>
:loading="processInstanceLoading" </el-tabs>
:process-instance="processInstance"
:tasks="tasks" <div class=" b-t-solid border-t-1px border-[var(--el-border-color)]" v-if="activeTab === 'form'">
/> <!-- 操作栏按钮 -->
</el-tab-pane> <ProcessInstanceOperationButton
<!-- 流转记录 --> ref="operationButtonRef"
<el-tab-pane label="流转记录"> :processInstance="processInstance"
<ProcessInstanceTaskList :userOptions="userOptions"
:loading="tasksLoad" @success="getDetail"
:process-instance="processInstance" />
:tasks="tasks" </div>
@refresh="getTaskList" </el-scrollbar>
/> </div>
</el-tab-pane>
<!-- 流转评论 -->
<el-tab-pane label="流转评论"> 流转评论 </el-tab-pane>
</el-tabs>
</ContentWrap> </ContentWrap>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
...@@ -209,6 +225,9 @@ const getTaskList = async () => { ...@@ -209,6 +225,9 @@ const getTaskList = async () => {
} }
} }
/** 当前的Tab */
const activeTab = ref('form')
/** 初始化 */ /** 初始化 */
const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表 const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
onMounted(async () => { onMounted(async () => {
...@@ -219,9 +238,29 @@ onMounted(async () => { ...@@ -219,9 +238,29 @@ onMounted(async () => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$wrap-padding-height: 30px ;
$wrap-margin-height: 15px;
$button-height: 51px;
$process-header-height: 194px;
.processInstance-wrap-main {
height: calc(100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 45px);
max-height: calc(100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 45px);
overflow: auto;
.form-scoll-area {
height: calc(100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 45px - $process-header-height - 40px);
max-height: calc(100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - 45px - $process-header-height - 40px);
overflow: auto;
}
}
.form-box { .form-box {
:deep(.el-card) { :deep(.el-card) {
border: none; border: none;
} }
} }
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment