CaiYuanYiTiHua/src/views/demo/workflow/task/process/look.vue

655 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<PageWrapper :class="prefixCls">
<!-- <div class="btn-box">
<a-button
type="primary"
@click="closePage"
class="ml-2"
danger
>关闭
</a-button>
</div> -->
<div class="maper-container" v-if="mapConfig?.isShowMap">
<MapboxMap
:mapConfig="mapConfig"
@handlerDrawComplete="handlerDrawComplete"
@mapOnLoad="onMapboxLoad"
ref="MapboxComponent"
/>
</div>
<div :class="mapConfig?.isShowMap ? 'form-container' : ''">
<a-layout>
<a-layout>
<a-layout-content>
<a-tabs v-model:activeKey="activeName" @change="changeActive" type="card" >
<a-tab-pane
key="form"
:tab="
designerData.formCurrentNode.formTitle
? designerData.formCurrentNode.formTitle
: '表单信息'
"
v-if="formVisble"
>
<div>
<ImagePreview v-if="isShowImagePreview" :globalImagePreviewUrl="globalImagePreviewUrl" @closeImagePreview="closeImagePreview"></ImagePreview>
<FormViewer
ref="formBoxRef"
:formConfig="formConfig"
:processId="designerData.process.id"
:formVerison="designerData.formCurrentNode.formVerison"
:formRelationId="designerData.formCurrentNode.formRelationId"
:instanceInfo="designerData.process.instanceInfo"
:issueId="designerData.formCurrentNode.issueId"
:isDetail="true"
@getFormSuccess="getFormSuccess"
v-if="formVisble"
/>
</div>
</a-tab-pane>
<a-tab-pane key="flow" tab="流程模板" force-render>
<div class="process-design" :style="'display: flex; height:' + designerData.height">
<process-viewer
v-if="processVisble"
:key="`designer-${id}`"
:events="['element.click']"
@element-click="elementClick"
:xml="flowContent"
:flowViewer="flowViewer"
/>
</div>
</a-tab-pane>
<a-tab-pane key="record" tab="操作记录" force-render>
<div :style="'padding:10px 0 40px 0;overflow:auto; height:' + designerData.height">
<a-timeline>
<a-timeline-item
v-for="(item, index) in designerData.logs"
:key="index"
:color="item.type"
>
<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"
:key="index2"
>{{ userName }}</span
>
{{ item.des }}
</div>
</a-card>
</a-timeline-item>
</a-timeline>
</div>
</a-tab-pane>
</a-tabs>
</a-layout-content>
<div v-if="designerData.userLogs.length > 0" :style="footerStyle">
<a-tabs v-model:activeKey="auditName">
<a-tab-pane key="audit" tab="审批信息">
<div class="approval-info">
<auditInfo :data="designerData.userLogs" />
</div>
</a-tab-pane>
</a-tabs>
</div>
<!-- <a-layout-sider :style="footerStyle" v-if="designerData.userLogs.length > 0">
<a-tabs v-model:activeKey="auditName">
<a-tab-pane key="audit" tab="审批信息">
<div class="approval-info">
<auditInfo :data="designerData.userLogs" />
</div>
</a-tab-pane>
</a-tabs>
</a-layout-sider> -->
</a-layout>
</a-layout>
</div>
<!-- 节点记录信息 -->
<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"
:color="item.type"
>
<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" :key="index2">{{
userName
}}</span>
{{ item.des }}
</div>
</a-card>
</a-timeline-item>
</a-timeline>
</a-drawer>
</div>
</PageWrapper>
</template>
<script lang="ts" setup>
import { ref, reactive, onBeforeMount, defineAsyncComponent,watch } from 'vue';
import { FormViewer } from '@/components/FormViewer';
import { ProcessViewer } from '@/components/ProcessViewer';
import { PageWrapper } from '@/components/Page';
import { getBPMN } from '@/api/sys/WFProcess';
import { IFormConfig } from '@/views/demo/form-design/typings/v-form-component';
import { dateFormat } from '@/utils/base';
import { designerDataType, logsType } from './processModel';
import { auditInfo } from './page';
import { getGeom } from '@/api/sys/layerManagement';
import { useMessage } from '@/hooks/web/useMessage';
import { storeToRefs } from 'pinia';
import ImagePreview from "@/components/Upload/src/components/image_preview.vue";
import { userFormFileStore } from '@/store/modules/formFileUrl';
const { createMessage } = useMessage();
const MapboxMap = defineAsyncComponent(() => import('@/components/MapboxMaps/MapComponent.vue'));
const mapConfig = ref({ isShowMap: false });
const MapboxComponent = ref();
const props = defineProps({
processId: String,
});
const prefixCls = 'preview-box';
const flowContent = ref('');
const flowViewer = ref({});
const infoOpen = ref(true);
const formBoxRef = ref<any>();
const formVisble = ref(false);
const processVisble = ref(false);
// 表单数据
const formConfig = ref<IFormConfig>({
// 表单配置
schemas: [],
layout: 'horizontal',
labelLayout: 'flex',
labelWidth: 100,
labelCol: {},
wrapperCol: {},
currentItem: {
component: '',
componentProps: {},
},
activeKey: 1,
});
const designerData: designerDataType = reactive({
loading: false,
xmlString: '',
height: document.documentElement.clientHeight - 300.5 + 'px;',
midVisible: false,
isCustmerTitle: false,
nodeUsers: [],
selectUsersVisible: false,
selectTUserVisible: false,
tUserType: 1, // 1 转移 2 加签,
isDraft: false,
delegateUsers: [],
task: {},
process: {},
logs: [], // 流程日志信息
nodeMap: {}, // 需要处理的任务
userLogs: [], // 人员日志信息
nodeLogs: [],
taskBtns: [],
currentNode: {},
stampList: [],
currentBtn: {
code: '',
name: '',
isNextAuditor: false,
},
wfData: [],
selectRejectNodeVisible: false,
selectSignVisible: false,
formCurrentNode: {},
});
const activeName = ref('form');
const auditName = ref('audit');
const footerStyle = ref({
height: '220px',
width: '100%',
overFlow: 'auto',
color: '#fff',
backgroundColor: '#ffffff',
zIndex: '123',
padding: '0px 0px',
position: 'fixed',
bottom: '0px',
right: '0px',
});
function changeActive(activeKey) {
if (activeKey == 'flow') {
processVisble.value = true;
} else {
processVisble.value = false;
}
}
function elementClick(element: { id: string | number }) {
if (element) {
designerData.nodeLogs = designerData.nodeMap[element.id] || [];
infoOpen.value = true;
} else {
designerData.nodeLogs = [];
}
}
async function getDetailInfo() {
let query: any = {
id: props.processId,
};
let data = await getBPMN(query);
flowContent.value = data.flowContent;
flowViewer.value = data.flowViewer;
designerData.process = data.process;
designerData.task = data.task;
let content = JSON.parse(data.scheme.content);
let wfData = content.wfData;
let currentNode;
const auditNode = wfData.find((t) => t.id == data.flowViewer.unfinishedTaskSet[0]);
// 流程已结束
if (data.process.isFinished == 1) {
data.flowViewer.finishedTaskSet.forEach((finishElement) => {
wfData.forEach((element) => {
if (finishElement == element.id && element.type == 'bpmn:Task') {
currentNode = element;
}
});
});
mapConfig.value = currentNode.mapConfig;
} else {
if (auditNode.isInherit) {
currentNode = wfData.find((t) => t.type == 'bpmn:StartEvent');
mapConfig.value = currentNode.mapConfig;
footerStyle.value.width = mapConfig.value?.isShowMap ? '60%' : '100%';
} else {
currentNode = auditNode;
var currentMapNode = wfData.find((t) => t.type == 'bpmn:StartEvent');
mapConfig.value = currentMapNode.mapConfig;
footerStyle.value.width = mapConfig.value?.isShowMap ? '60%' : '100%';
}
}
if (currentNode.authFields.length > 0) {
formVisble.value = true;
} else {
activeName.value = 'flow';
processVisble.value = true;
}
designerData.formCurrentNode = currentNode;
formConfig.value = currentNode.authFields;
setLogsAndTasks(data.logs, data.tasks);
// getBtns();
}
function setLogsAndTasks(logs: any[], tasks: any[]) {
const res: logsType[] = [];
const taskMap = {};
const nodeMap = {};
const userLogs: any[] = [];
tasks.forEach(
(task: {
unitId: string | number;
unitName: any;
createDate: any;
type: number;
userId: any;
userName: any;
}) => {
nodeMap[task.unitId] = nodeMap[task.unitId] || [
{
unitId: task.unitId,
name: task.unitName,
userIds: [],
userNames: [],
des: '正在审核',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'blue',
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: 'blue',
};
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: 'blue',
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: 'blue',
};
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: { userIds: string | any[] }) => t.userIds.length > 0);
}
logs.reverse();
logs.forEach(
(log: {
unitId: string;
unitName: any;
userId: string;
userName: string;
des: string;
operationName: string;
createDate: any;
taskType: number;
operationCode: string;
stampImg: any;
}) => {
res.push({
unitId: log.unitId,
name: log.unitName,
userIds: [log.userId],
userNames: [log.userName],
des: log.des ? log.des : log.operationName,
time: dateFormat(log.createDate),
type: 'gray',
});
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.operationName,
type: 'gray',
isFinish: true,
});
if (log.taskType == 1 && !['sign'].includes(log.operationCode)) {
// 右侧显示审核记录
// const userLogIndex = userLogs.findIndex((t) => t.id == log.unitId);
// if (userLogIndex == -1) {
userLogs.push({
id: log.unitId,
name: log.unitName,
user: log.userName,
time: dateFormat(log.createDate),
des: log.des,
img: log.stampImg,
});
// }
}
},
);
designerData.logs = res;
designerData.nodeMap = nodeMap;
designerData.userLogs = userLogs.sort(function (a, b) {
return a.time < b.time ? -1 : 1;
});
}
// function closePage() {
// tabStore.closeTabByKey('/dashboard/task_look_preview/detail?processId=' + processId, router);
// }
// 解析组件获取图斑组件
const chooseLayer = ref<string>("")
const geomfield = ref<string>("");
function findValue(obj, targetKey) {
for (var key in obj) {
if (typeof obj[key] === 'object') {
// 如果当前值是对象则递归调用findValue
var result = findValue(obj[key], targetKey);
if (result !== undefined && result == 'MapGeom') {
return result;
}
} else if (key === targetKey && obj[key] == 'MapGeom') {
// 如果当前键等于目标键,则返回对应的值
chooseLayer.value = obj['mapSetData'].chooseLayer;
geomfield.value = obj['field']
return obj[key];
}
}
}
function getFormSuccess(formData){
if(mapConfig.value.isShowMap){
handlerShowGeomtrys(designerData.formCurrentNode, formData);
}
}
async function handlerShowGeomtrys(currentNode,formData) {
findValue(currentNode.authFields,"component");
let layer: string = chooseLayer.value;
if (!layer) {
createMessage.error('图斑未绑定图层服务!');
return;
}
let geomfiledValue = geomfield.value;
let gids = '';
try {
geomfiledValue = geomfiledValue.toLowerCase();
gids = formData[geomfiledValue];
// 根据ids获取图斑
if (gids) {
try {
let getGeomPrams = {
TableName: layer,
FieldName: 'gid',
FieldValue: gids,
page: 1,
limit: 999,
key: null,
};
getGeom(getGeomPrams).then((res) => {
let geoms = [];
if (res) {
if (res.items?.length > 0) {
res.items.forEach((item, index) => {
let geom = {
key: item.gid,
mapgeom: item.geometry,
};
geoms.push(geom);
});
}
// MapboxComponent.value.handlerDraw(status,mapgemoList.value, false);
MapboxComponent.value.handlerDraw('Details', geoms, false);
} else {
createMessage.error('当前数据没有图斑!');
}
});
} catch (e) {
createMessage.error('当前数据没有图斑!');
}
} else {
createMessage.error('当前数据没有图斑!');
}
} catch {
createMessage.error('获取图斑数据失败!');
}
}
function onMapboxLoad() {
}
// 图片预览
const isShowImagePreview = ref<Boolean>(false);
const closeImagePreview = ()=>{
isShowImagePreview.value = false;
}
const globalImagePreviewUrl=ref<String>();
const formFileStore = userFormFileStore();
const formFileState = storeToRefs(formFileStore);
watch(formFileState.url, (newValue, oldValue) => {
isShowImagePreview.value = true;
globalImagePreviewUrl.value = newValue;
});
onBeforeMount(() => {
getDetailInfo();
});
</script>
<style lang="less" scoped>
::v-deep .ant-tabs-nav-wrap {
padding-left: 10px;
}
::v-deep .ant-layout {
height: 100%;
background-color: @component-background;
}
::v-deep .ant-layout-sider-children {
border-left: 1px solid rgba(5, 5, 5, 0.06);
}
::v-deep .ant-divider-vertical {
height: 100%;
}
.info-box {
display: inline-block;
width: 300px;
position: absolute;
right: 0;
margin-top: 40px;
}
.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 {
height: 100%;
.btn-box {
padding: 10px;
justify-content: flex-end;
display: flex;
}
}
::v-deep .vben-page-wrapper-content {
height: 100%;
margin: 0 0 0 16px;
}
.form-box {
width: 480px;
}
.approval-column {
padding: 10px;
}
::v-deep .ant-layout .ant-layout-sider {
padding-left: 10px;
background-color: @component-background;
flex: 0 0 360px !important;
max-width: 360px !important;
min-width: 360px !important;
width: 360px !important;
}
::v-deep .vben-page-wrapper .vben-page-wrapper-content {
height: 98%;
}
.l-task-btns {
.ant-btn {
margin: 0;
margin-top: 8px;
margin-right: 8px;
}
}
::v-deep .ant-modal-footer {
display: none !important;
height: 0px !important;
}
::v-deep .ant-layout-footer {
padding: 0px 20px !important;
overflow: auto !important;
}
.form-container {
float: left;
width: 60%;
}
.maper-container {
float: left;
width: 40%;
padding: 20px;
height: 100%;
}
.l-from-body {
padding: 10px 30px;
}
::v-deep .ant-layout-footer {
background-color: @component-background;
height: 230px;
width: 100%;
position: fixed;
bottom: 0;
left: 0;
.ant-tabs {
height: 230px;
}
.ant-tabs-nav {
}
.ant-tabs-content-holder {
height: 200px;
padding-bottom: 10px;
width: 100%;
overflow: auto;
}
}
</style>