655 lines
20 KiB
Vue
655 lines
20 KiB
Vue
<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>
|