init
This commit is contained in:
100
src/flow/designer/api/jsonflow/index.ts
Normal file
100
src/flow/designer/api/jsonflow/index.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import request from "/@/utils/request"
|
||||
|
||||
export function predictFlow(obj?: Object, query?: Object) {
|
||||
return request({
|
||||
url: '/jsonflow/run-flow/predict',
|
||||
method: 'post',
|
||||
data: obj,
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function delFlowInfo(obj: any) {
|
||||
return request({
|
||||
url: '/jsonflow/run-flow/del/flow/info',
|
||||
method: 'delete',
|
||||
data: obj
|
||||
})
|
||||
}
|
||||
|
||||
export function getNodesByIdType(id, flowType, isEdit) {
|
||||
// flowType: 0 模板 1 实例
|
||||
// viewType: 0 查看 1 编辑
|
||||
if (flowType === '1') return getNodesByFlowInstId(id, isEdit)
|
||||
else return getNodesByDefFlowId(id)
|
||||
}
|
||||
|
||||
export function getNodesByDefFlowId(id) {
|
||||
return request({
|
||||
url: '/jsonflow/def-flow/nodes/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getNodesByFlowInstId(id, isEdit) {
|
||||
return request({
|
||||
url: '/jsonflow/run-flow/nodes/' + id + "/" + isEdit,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addObjByDefFlowId(obj) {
|
||||
return request({
|
||||
url: '/jsonflow/def-flow',
|
||||
method: 'post',
|
||||
data: obj
|
||||
})
|
||||
}
|
||||
|
||||
export function addObjByFlowInstId(obj) {
|
||||
return request({
|
||||
url: '/jsonflow/run-flow/flow-inst-id',
|
||||
method: 'post',
|
||||
data: obj
|
||||
})
|
||||
}
|
||||
|
||||
export function listRunFlowsByDefFlowId(defFlowId, version) {
|
||||
return request({
|
||||
url: '/jsonflow/run-flow/def-flow-id/' + defFlowId + "/" + version,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function listDefFlowByFlowKey(flowKey) {
|
||||
return request({
|
||||
url: '/jsonflow/def-flow/flow-key/' + flowKey,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function listFlowApplicationByFlowKey(flowKey) {
|
||||
return request({
|
||||
url: '/order/flow-application/flow-key/' + flowKey,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchComment(query) {
|
||||
return request({
|
||||
url: '/jsonflow/comment/comment/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchRunJobs(flowInstId) {
|
||||
return request({
|
||||
url: '/jsonflow/run-job/list/' + flowInstId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchRunRejects(flowInstId) {
|
||||
return request({
|
||||
url: '/jsonflow/run-reject/list/' + flowInstId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
76
src/flow/designer/assets/style/flow-area.scss
Normal file
76
src/flow/designer/assets/style/flow-area.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
.child-ul-wrapper {
|
||||
padding-left: 1px !important;
|
||||
}
|
||||
|
||||
.jf-wrap-paper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
//position: relative;
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#jfDragWrapPaper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jsonflow-navigator{
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
right: 8px;
|
||||
border: #ccc solid 1px;
|
||||
overflow: hidden;
|
||||
|
||||
.minimap-view{
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 2px;
|
||||
border: 2px dotted #999;
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
|
||||
.jf-wrap-paper-active {
|
||||
background-color: #e4e4e4;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.container-scale {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, .65);
|
||||
}
|
||||
|
||||
/*缩放按钮*/
|
||||
.el-button--small.is-circle {
|
||||
padding: 5px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.horizontal-line-x {
|
||||
position: absolute;
|
||||
//width: 5000px;
|
||||
height: 1px;
|
||||
background: #409EFF;
|
||||
//margin-left: -2500px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vertical-line-y {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
//height: 5000px;
|
||||
background: #409EFF;
|
||||
//margin-top: -2500px;
|
||||
display: none;
|
||||
}
|
||||
63
src/flow/designer/assets/style/flow-attr.scss
Normal file
63
src/flow/designer/assets/style/flow-attr.scss
Normal file
@@ -0,0 +1,63 @@
|
||||
.flow-attr {
|
||||
/*属性面板*/
|
||||
.el-form-item {
|
||||
margin: 0 15px 10px!important;
|
||||
}
|
||||
|
||||
/*属性面板在一行*/
|
||||
.el-form--label-top .el-form-item__label{
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
padding: 0 0 10px!important;
|
||||
}
|
||||
|
||||
/*tab选中样式*/
|
||||
.el-tabs__active-bar {
|
||||
background-color: revert;
|
||||
}
|
||||
|
||||
/*tab头居中*/
|
||||
.el-tabs__header{
|
||||
margin: 8px 20px!important;
|
||||
}
|
||||
|
||||
.el-form-item__content {
|
||||
.el-select {
|
||||
width: 303px!important;
|
||||
}
|
||||
}
|
||||
|
||||
.input-attr {
|
||||
width: 303px;
|
||||
|
||||
.el-input-group__prepend {
|
||||
background-color: #F5F7FA;
|
||||
width: 97px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.flow-config-attr {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.flow-param-attr {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.audit-endpoint {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 200px;
|
||||
}
|
||||
|
||||
.audit-endpoint-extract {
|
||||
position: absolute;
|
||||
bottom: 9px;
|
||||
left: 150px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
93
src/flow/designer/assets/style/flow-designer.scss
Normal file
93
src/flow/designer/assets/style/flow-designer.scss
Normal file
@@ -0,0 +1,93 @@
|
||||
.flow-container {
|
||||
height: 100%;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.select-area {
|
||||
position: relative;
|
||||
z-index: 1001;
|
||||
box-shadow: 0 3px 5px #ddd;
|
||||
width: 54px;
|
||||
background: #fff;
|
||||
padding-top: 6px;
|
||||
.el-row-tab {
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
height: 26px;
|
||||
line-height: 24px;
|
||||
margin-top: 7px;
|
||||
margin-left: 17px;
|
||||
}
|
||||
/*左侧菜单栏*/
|
||||
.el-row {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-option {
|
||||
background: #fff;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-shadow: 0 3px 5px #ddd;
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
&__tools {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
width: 570px;
|
||||
|
||||
.el-select__wrapper {
|
||||
border-radius: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-button {
|
||||
height: 30px;
|
||||
border-radius: 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-button+.el-button {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.el-input__wrapper {
|
||||
height: 30px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
.el-input__inner {
|
||||
width: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-view-option {
|
||||
background: #fff;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
&__tools {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.header-option-button {
|
||||
border: 0;
|
||||
padding: 8px 8px;
|
||||
}
|
||||
|
||||
.flow-content {
|
||||
background: #fafafa;
|
||||
height: 100%;
|
||||
border: 1px dashed rgba(170, 170, 170, 0.7);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
3
src/flow/designer/assets/style/flow-paper.css
Normal file
3
src/flow/designer/assets/style/flow-paper.css
Normal file
File diff suppressed because one or more lines are too long
15
src/flow/designer/assets/svges/index.ts
Normal file
15
src/flow/designer/assets/svges/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import {nodeJobSvgIcons as nodeJobPath} from "./path";
|
||||
|
||||
// SVG ICON图标
|
||||
export const nodeJobSvgIcons = {
|
||||
serial: nodeJobPath.serial,
|
||||
serialGate: nodeJobPath.serialGate
|
||||
,parallel: nodeJobPath.parallel
|
||||
,parallelGate: nodeJobPath.parallelGate
|
||||
,job: nodeJobPath.job
|
||||
,virtual: '/flow/menu/virtual-icon.svg'
|
||||
,startMenu: '/flow/menu/start.svg'
|
||||
,endMenu: '/flow/menu/end.svg'
|
||||
,xLaneMenu: '/flow/menu/x-lane.svg'
|
||||
,yLaneMenu: '/flow/menu/y-lane.svg'
|
||||
}
|
||||
17
src/flow/designer/assets/svges/path.ts
Normal file
17
src/flow/designer/assets/svges/path.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// SVG ICON图标
|
||||
export const nodeJobSvgIcons = {
|
||||
start: "/flow/icons/start-icon.svg"
|
||||
,arrow: "/flow/icons/arrow-icon.svg"
|
||||
,serial: "/flow/icons/serial-icon.svg"
|
||||
,serialGate: "/flow/icons/serialGate.svg"
|
||||
,parallel: "/flow/icons/parallel-icon.svg"
|
||||
,parallelGate: "/flow/icons/parallelGate.svg"
|
||||
,linkIcon: "/flow/icons/link-icon.svg"
|
||||
,job: "/flow/icons/job-icon.svg"
|
||||
,virtual: "/flow/icons/virtual-icon.svg"
|
||||
,success: "/flow/icons/success.svg"
|
||||
,warning: "/flow/icons/warning.svg"
|
||||
,loading: "/flow/icons/loading.svg"
|
||||
}
|
||||
|
||||
window._shapesSvgPath = nodeJobSvgIcons
|
||||
138
src/flow/designer/components/flow-area-view.vue
Normal file
138
src/flow/designer/components/flow-area-view.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div id="jfDragWrapPaper">
|
||||
<div
|
||||
id="jfWrapPaper"
|
||||
class="jf-wrap-paper"
|
||||
>
|
||||
<div id="jsonflowMainPaper"></div>
|
||||
</div>
|
||||
<div id="minimapPaperView" class="jsonflow-navigator"></div>
|
||||
<div class="container-scale">
|
||||
<el-button icon="ZoomIn" circle size="small" type="default" @click="methods.enlargePaper"></el-button>
|
||||
<span>{{ data.container.scaleShow }}% </span>
|
||||
<el-button icon="ZoomOut" circle size="small" type="default" @click="methods.narrowPaper"></el-button>
|
||||
</div>
|
||||
<vue-context-menu
|
||||
:contextMenuData="data.nodeContMenuData"
|
||||
>
|
||||
</vue-context-menu>
|
||||
<vue-context-menu
|
||||
:contextMenuData="data.linkContMenuData"
|
||||
>
|
||||
</vue-context-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowAreaView">
|
||||
import {flowConfig} from "../config/flow-config";
|
||||
import {utils} from "../utils/common";
|
||||
import {deepClone} from "/@/utils/other";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {hideVueContextmenuName} from "/@/flow/utils";
|
||||
|
||||
// 引入组件
|
||||
const VueContextMenu = defineAsyncComponent(() => import('../../components/contextmenu/index.vue'));
|
||||
const {t} = useI18n();
|
||||
const $emit = defineEmits(["initJsonFlowView"]);
|
||||
const props = defineProps({
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: {},
|
||||
}
|
||||
});
|
||||
const data = reactive({
|
||||
container: {
|
||||
scaleShow: utils.mul(flowConfig.defaultStyle.containerScale.init, 100)
|
||||
},
|
||||
linkContMenuData: deepClone(flowConfig.contextMenu.linkView),
|
||||
nodeContMenuData: deepClone(flowConfig.contextMenu.nodeView)
|
||||
})
|
||||
|
||||
const methods = {
|
||||
// 画布放大
|
||||
enlargePaper() {
|
||||
data.container.scaleShow = window._jfOperate.zoomOut();
|
||||
},
|
||||
// 画布缩小
|
||||
narrowPaper() {
|
||||
let zoomIn = window._jfOperate.zoomIn();
|
||||
data.container.scaleShow = parseInt(zoomIn)
|
||||
},
|
||||
// 节点click事件
|
||||
showNodeClickMenu(currSelect, e) {
|
||||
// TODO 业务侧替换其他内容
|
||||
methods.showNodeContMenu(currSelect, e)
|
||||
},
|
||||
// 节点hover事件
|
||||
showNodeContMenu(currSelect, e) {
|
||||
if (validateNull(currSelect)) {
|
||||
currSelect = props.currSelect
|
||||
}
|
||||
if (Object.keys(currSelect).length === 0) return
|
||||
// 计算节点信息
|
||||
methods.updateNodeContMenuData(currSelect)
|
||||
let event = window.event || e;
|
||||
event.preventDefault();
|
||||
hideVueContextmenuName()
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
data.nodeContMenuData.axis = {x, y};
|
||||
},
|
||||
updateNodeContMenuData(currSelect) {
|
||||
let nodeNameBtnName = flowConfig.contextMenu.nodeView.menulists[0].btnName;
|
||||
let text;
|
||||
if (!currSelect.attributes.attrs.label) text = currSelect.attrs.label.text
|
||||
else text = currSelect.attributes.attrs.label.text
|
||||
data.nodeContMenuData.menulists[0].btnName = nodeNameBtnName + text
|
||||
data.nodeContMenuData.menulists[1].btnName = currSelect.attributes.startTime
|
||||
data.nodeContMenuData.menulists[2].btnName = currSelect.attributes.userRoleName
|
||||
data.nodeContMenuData.menulists[3].btnName = currSelect.attributes.userName
|
||||
data.nodeContMenuData.menulists[4].btnName = currSelect.attributes.remark
|
||||
},
|
||||
// 连接click事件
|
||||
showLinkClickMenu(currSelect, e) {
|
||||
// TODO 业务侧替换其他内容
|
||||
methods.showLinkContMenu(currSelect, e)
|
||||
},
|
||||
// 连接线hover事件
|
||||
showLinkContMenu(currSelect, e) {
|
||||
if (validateNull(currSelect)) {
|
||||
currSelect = props.currSelect
|
||||
}
|
||||
if (Object.keys(currSelect).length === 0) return
|
||||
// 计算连线条件
|
||||
let varKeyVal = currSelect.attributes.attrs.cdata.attrs.varKeyVal;
|
||||
hideVueContextmenuName()
|
||||
if (!varKeyVal) return
|
||||
let btnName = flowConfig.contextMenu.linkView.menulists[0].btnName;
|
||||
data.linkContMenuData.menulists[0].btnName = btnName + varKeyVal
|
||||
|
||||
let event = window.event || e;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
data.linkContMenuData.axis = {x, y};
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
$emit("initJsonFlowView");
|
||||
})
|
||||
});
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
showNodeContMenu: methods.showNodeContMenu,
|
||||
showNodeClickMenu: methods.showNodeClickMenu,
|
||||
showLinkContMenu: methods.showLinkContMenu,
|
||||
showLinkClickMenu: methods.showLinkClickMenu,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../assets/style/flow-area.scss";
|
||||
@import "../assets/style/flow-paper.css";
|
||||
</style>
|
||||
384
src/flow/designer/components/flow-area.vue
Normal file
384
src/flow/designer/components/flow-area.vue
Normal file
@@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<div id="jfDragWrapPaper">
|
||||
<div id="jfWrapPaper"
|
||||
class="jf-wrap-paper"
|
||||
>
|
||||
<div id="jsonflowMainPaper" @dragover="methods.allowDrop" @drop="methods.drop"></div>
|
||||
<div class="horizontal-line-x"></div>
|
||||
<div class="vertical-line-y"></div>
|
||||
</div>
|
||||
<div id="minimapPaperView" class="jsonflow-navigator"></div>
|
||||
<div class="container-scale">
|
||||
<el-button icon="ZoomIn" circle size="small" type="default"
|
||||
@click="methods.enlargePaper"></el-button>
|
||||
<span>{{ data.container.scaleShow }}% </span>
|
||||
<el-button icon="ZoomOut" circle size="small" type="default"
|
||||
@click="methods.narrowPaper"></el-button>
|
||||
</div>
|
||||
<!-- 选择连接的节点 -->
|
||||
<el-dialog
|
||||
v-model="data.showSetConnectNode" v-if="data.showSetConnectNode"
|
||||
top="20px"
|
||||
width="50%"
|
||||
title="请选择连接到的节点"
|
||||
append-to-body>
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="170px">
|
||||
<el-form-item label="连接到的节点">
|
||||
<el-select class="input-attr" placeholder="请选择连接到的节点" style="width: 80%!important;"
|
||||
@change="methods.doConnectNode"
|
||||
v-model="data.toFlowNodeId"
|
||||
filterable clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.flowNodeIds"
|
||||
:key="item.id"
|
||||
:label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>从当前节点连接到目标节点</template>
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 选择连线的起始节点 -->
|
||||
<el-dialog
|
||||
v-model="data.showLinkFlowNodeIds" v-if="data.showLinkFlowNodeIds"
|
||||
top="20px"
|
||||
width="50%"
|
||||
:title="'请选择连接到的' + (data.modifyPointType === '0' ? '起点' : '终点')"
|
||||
append-to-body>
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="170px">
|
||||
<el-form-item label="起始节点(可修改)" v-if="data.modifyPointType ==='0'">
|
||||
<el-select class="input-attr" style="width: 80%!important;"
|
||||
v-model="data.fromFlowNodeId"
|
||||
@change="methods.changeLinkFlowNodeIds('0')"
|
||||
filterable clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.fromFlowNodeIds"
|
||||
:key="item.id"
|
||||
:label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="目标节点(可修改)" v-if="data.modifyPointType ==='1'">
|
||||
<el-select class="input-attr" style="width: 80%!important;"
|
||||
v-model="data.toFlowNodeId"
|
||||
@change="methods.changeLinkFlowNodeIds('1')"
|
||||
filterable clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.toFlowNodeIds"
|
||||
:key="item.id"
|
||||
:label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
<vue-context-menu
|
||||
:contextMenuData="data.paperContMenuData"
|
||||
@flowInfo="methods.flowInfo"
|
||||
@paste="methods.paste"
|
||||
>
|
||||
</vue-context-menu>
|
||||
<vue-context-menu
|
||||
:contextMenuData="data.nodeContMenuData"
|
||||
@setNodeAttr="methods.setNodeAttr('0')"
|
||||
@copyNode="methods.copyNode"
|
||||
@deleteNode="methods.deleteNode"
|
||||
@setConnectNode="methods.setConnectNode"
|
||||
>
|
||||
</vue-context-menu>
|
||||
<vue-context-menu
|
||||
:contextMenuData="data.nodeConnectMenuData"
|
||||
@setSerialNode="methods.setSerialNode"
|
||||
@setSerialGate="methods.setSerialGate"
|
||||
@setParallelNode="methods.setParallelNode"
|
||||
@setParallelGate="methods.setParallelGate"
|
||||
@setConnectNode="methods.setConnectNode"
|
||||
>
|
||||
</vue-context-menu>
|
||||
<vue-context-menu
|
||||
:contextMenuData="data.linkContMenuData"
|
||||
@deleteLink="methods.deleteLink"
|
||||
@setLinkAttr="methods.setNodeAttr('1')"
|
||||
@modifySourceNode="methods.handleLinkFlowNodeIds('0')"
|
||||
@modifyTargetNode="methods.handleLinkFlowNodeIds('1')"
|
||||
>
|
||||
</vue-context-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowArea">
|
||||
import {flowConfig} from "../config/flow-config";
|
||||
import {utils} from "../utils/common";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage, useMessageBox} from "/@/hooks/message";
|
||||
import {notifyLeft} from "/@/flow";
|
||||
import {CommonNodeType, HighNodeType} from "../config/type";
|
||||
import {hideVueContextmenuName} from "/@/flow/utils";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {changeLinkFlowNodeIds, handleLinkFlowNodeIds, validateNodeType} from "./index";
|
||||
|
||||
// 引入组件
|
||||
const VueContextMenu = defineAsyncComponent(() => import('../../components/contextmenu/index.vue'));
|
||||
|
||||
const {t} = useI18n();
|
||||
const {proxy} = getCurrentInstance();
|
||||
const $message = useMessage();
|
||||
const $emit = defineEmits(["removeEleTools", "showAttrConfig", "initJsonFlow"]);
|
||||
const props = defineProps({
|
||||
dragInfo: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: {},
|
||||
}
|
||||
});
|
||||
const data = reactive({
|
||||
container: {
|
||||
scaleShow: utils.mul(flowConfig.defaultStyle.containerScale.init, 100)
|
||||
},
|
||||
paperContMenuData: flowConfig.contextMenu.container,
|
||||
nodeContMenuData: flowConfig.contextMenu.node,
|
||||
nodeConnectMenuData: flowConfig.contextMenu.nodeConnect,
|
||||
linkContMenuData: flowConfig.contextMenu.link,
|
||||
clipboard: {},
|
||||
showSetConnectNode: false,
|
||||
showLinkFlowNodeIds: false,
|
||||
toFlowNodeId: null,
|
||||
flowNodeIds: [],
|
||||
modifyPointType: null,
|
||||
fromFlowNodeId: null,
|
||||
fromFlowNodeIds: [],
|
||||
toFlowNodeIds: []
|
||||
})
|
||||
const methods = {
|
||||
allowDrop(e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
drop(e) {
|
||||
// 增加节点
|
||||
window._jfOperate.dropNewNode(e, props.dragInfo, true);
|
||||
},
|
||||
// 画布放大
|
||||
enlargePaper() {
|
||||
data.container.scaleShow = window._jfOperate.zoomOut();
|
||||
},
|
||||
// 画布缩小
|
||||
narrowPaper() {
|
||||
let zoomIn = window._jfOperate.zoomIn();
|
||||
data.container.scaleShow = parseInt(zoomIn)
|
||||
},
|
||||
// 画布右健
|
||||
showPaperContMenu(e) {
|
||||
let event = window.event || e;
|
||||
|
||||
event.preventDefault();
|
||||
hideVueContextmenuName()
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
data.paperContMenuData.axis = {x, y};
|
||||
},
|
||||
// 流程图信息
|
||||
flowInfo() {
|
||||
$message.info(
|
||||
"当前流程图中有 " +
|
||||
window._jfGraph.getElements().length +
|
||||
" 个节点,有 " +
|
||||
window._jfGraph.getLinks().length +
|
||||
" 条连线。"
|
||||
);
|
||||
},
|
||||
handleFlowNodeIds() {
|
||||
data.flowNodeIds = []
|
||||
let models = window._jfGraph.getElements();
|
||||
if (validateNull(models)) return
|
||||
models.forEach(each => {
|
||||
if (!validateNodeType(each)) return
|
||||
if (props.currSelect.id !== each.id) {
|
||||
let id = each.id
|
||||
let nodeName = each.attributes.attrs.label.text + "(ID:" + id + ")"
|
||||
data.flowNodeIds.push({id, nodeName})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 粘贴
|
||||
paste() {
|
||||
let e = window.event;
|
||||
let b = Object.keys(data.clipboard).length === 0;
|
||||
if (b) {
|
||||
$message.info("请将鼠标放节点上, 右键菜单复制节点");
|
||||
hideVueContextmenuName()
|
||||
return
|
||||
}
|
||||
let newNode = data.clipboard.clone()
|
||||
window._jfOperate.pasteNode(newNode, e);
|
||||
data.clipboard = {}
|
||||
hideVueContextmenuName()
|
||||
},
|
||||
// 节点右键
|
||||
showNodeContMenu(e) {
|
||||
let event = window.event || e;
|
||||
|
||||
event.preventDefault();
|
||||
hideVueContextmenuName()
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
data.nodeContMenuData.axis = {x, y};
|
||||
},
|
||||
// 复制节点
|
||||
copyNode() {
|
||||
data.clipboard = {};
|
||||
if (methods.validateCurrSelect("0")) {
|
||||
return
|
||||
}
|
||||
data.clipboard = props.currSelect;
|
||||
hideVueContextmenuName()
|
||||
},
|
||||
// 删除节点
|
||||
deleteNode() {
|
||||
if (methods.validateCurrSelect("0")) {
|
||||
return
|
||||
}
|
||||
props.currSelect.remove()
|
||||
$emit("removeEleTools");
|
||||
},
|
||||
setNodeAttr(type) {
|
||||
if (methods.validateCurrSelect(type)) {
|
||||
return
|
||||
}
|
||||
$emit("showAttrConfig", true);
|
||||
},
|
||||
// 连接线右键
|
||||
showLinkContMenu(e) {
|
||||
let event = window.event || e;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
hideVueContextmenuName()
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
data.linkContMenuData.axis = {x, y};
|
||||
},
|
||||
// 删除线
|
||||
deleteLink() {
|
||||
if (methods.validateCurrSelect("1")) {
|
||||
return
|
||||
}
|
||||
props.currSelect.remove()
|
||||
$emit("removeEleTools");
|
||||
},
|
||||
validateCurrSelect(type) {
|
||||
let b = Object.keys(props.currSelect).length === 0;
|
||||
if (b !== true) return false
|
||||
if (type === '0') {
|
||||
notifyLeft('请先选择节点', 'warning')
|
||||
} else {
|
||||
notifyLeft('请先移动到连线上方', 'warning')
|
||||
}
|
||||
return true
|
||||
},
|
||||
// 节点连接右键
|
||||
showNodeConnectMenu(params, e) {
|
||||
let event = window.event || e;
|
||||
|
||||
hideVueContextmenuName()
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
data.nodeConnectMenuData.axis = {x, y};
|
||||
data.nodeConnectMenuData.params = params;
|
||||
},
|
||||
setSerialNode() {
|
||||
methods.connectAction({belongTo: "commonNodes", type: CommonNodeType.SERIAL})
|
||||
},
|
||||
setParallelNode() {
|
||||
methods.connectAction({belongTo: "commonNodes", type: CommonNodeType.PARALLEL})
|
||||
},
|
||||
setSerialGate() {
|
||||
methods.connectAction({belongTo: "highNodes", type: CommonNodeType.SERIAL})
|
||||
},
|
||||
setParallelGate() {
|
||||
methods.connectAction({belongTo: "highNodes", type: CommonNodeType.PARALLEL})
|
||||
},
|
||||
setConnectNode() {
|
||||
if (methods.hideValidateCurrSelect("0")) {
|
||||
return
|
||||
}
|
||||
methods.handleFlowNodeIds()
|
||||
data.toFlowNodeId = null
|
||||
data.showSetConnectNode = true
|
||||
},
|
||||
doConnectNode(val) {
|
||||
if (methods.hideValidateCurrSelect("0")) {
|
||||
return
|
||||
}
|
||||
let simpleMode = window._flowConfig.globalConfig.isSimpleMode;
|
||||
if (simpleMode !== '1') {
|
||||
data.nodeConnectMenuData.params = {view: {model: props.currSelect}}
|
||||
}
|
||||
useMessageBox()
|
||||
.confirm('是否确认连接到当前选中的节点?')
|
||||
.then(() => {
|
||||
let params = data.nodeConnectMenuData.params;
|
||||
params.toFlowNodeId = val
|
||||
window._jfOperate.doConnectNode(params)
|
||||
data.showSetConnectNode = false
|
||||
if (simpleMode !== '1') {
|
||||
notifyLeft('专业模式不会自动调整连线轨迹,有必要时请手动调整', 'warning', 3000)
|
||||
}
|
||||
})
|
||||
},
|
||||
connectAction(dragInfo) {
|
||||
if (methods.hideValidateCurrSelect("0")) {
|
||||
return
|
||||
}
|
||||
let params = data.nodeConnectMenuData.params;
|
||||
window._jfOperate.connectAction(params, dragInfo)
|
||||
},
|
||||
hideValidateCurrSelect(type) {
|
||||
hideVueContextmenuName()
|
||||
return methods.validateCurrSelect(type);
|
||||
},
|
||||
changeLinkFlowNodeIds(type) {
|
||||
if (methods.hideValidateCurrSelect("1")) {
|
||||
return
|
||||
}
|
||||
changeLinkFlowNodeIds(data, props)
|
||||
data.showLinkFlowNodeIds = false
|
||||
},
|
||||
handleLinkFlowNodeIds(type) {
|
||||
if (methods.hideValidateCurrSelect("1")) {
|
||||
return
|
||||
}
|
||||
data.modifyPointType = type
|
||||
handleLinkFlowNodeIds(data, props)
|
||||
data.showLinkFlowNodeIds = true
|
||||
},
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
$emit("initJsonFlow");
|
||||
})
|
||||
});
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
showPaperContMenu: methods.showPaperContMenu,
|
||||
showNodeContMenu: methods.showNodeContMenu,
|
||||
showNodeConnectMenu: methods.showNodeConnectMenu,
|
||||
showLinkContMenu: methods.showLinkContMenu,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../assets/style/flow-area.scss";
|
||||
@import "../assets/style/flow-paper.css";
|
||||
</style>
|
||||
1303
src/flow/designer/components/flow-attr.vue
Normal file
1303
src/flow/designer/components/flow-attr.vue
Normal file
File diff suppressed because it is too large
Load Diff
411
src/flow/designer/components/flow-clazz.vue
Normal file
411
src/flow/designer/components/flow-clazz.vue
Normal file
@@ -0,0 +1,411 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="160px">
|
||||
|
||||
<el-form-item label="监听类">
|
||||
<el-input class="input-attr" :placeholder="props.clazzPlaceholder" v-model="data.clazz.clazz" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="data.clazz.httpUrl"
|
||||
@blur="methods.handleHttpUrlBlur" clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="data.clazz.httpMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip content="点击可设置Http请求的参数信息" placement="bottom">
|
||||
<el-button type="primary" size="small" round style="margin-left: 10px"
|
||||
@click="methods.openHttpUrlParams(true)">
|
||||
参数
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="触发时机">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.clazz.methods" multiple
|
||||
clearable placeholder="多个方法名称, 英文逗号分隔, 顺序从左到右">
|
||||
<el-option
|
||||
v-for="(item, index) in props.addType === '0' && props.currSelect.attributes.attrs.cdata.attrs.isAutoAudit === '1' ?
|
||||
props.flowMethods.slice(3) : props.flowMethods"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider v-if="!data.moreInter">
|
||||
<el-button type="primary" link @click="methods.showMoreSetting()"
|
||||
style="margin-left: 10px; font-size: 14px">
|
||||
{{ data.moreInter ? '隐藏更多' : '更多配置' }}
|
||||
</el-button>
|
||||
</el-divider>
|
||||
|
||||
<template v-if="data.moreInter">
|
||||
<div style="margin: 10px 13px">
|
||||
<span style="color: red;font-size: 14px">注: 监听事件允许设置生效条件,用于控制在某种条件下才会执行</span>
|
||||
</div>
|
||||
<el-form-item label="条件模式">
|
||||
<el-radio-group style="width: 313px" @change="methods.handleClazzValType" :disabled="data.existData"
|
||||
v-model="data.clazz.valType">
|
||||
<el-radio v-for="(item, index) in DIC_PROP.VAL_TYPE.slice(2, 5)" :key="index" :label="item.value" style="width: 75px">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>若无法切换模式,请先清空监听事件列表</template>
|
||||
<el-icon><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="data.tableFieldData" v-if="data.clazz.valType === '0'"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="data.clazz.varKeyVal" @change="methods.handleVarKeyVal"
|
||||
clearable
|
||||
filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="data.clazz.operator"
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.varValOperator"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="data.clazz.varVal" clearable/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-form-item label="SpEL表达式" v-if="data.clazz.valType === '1'">
|
||||
<el-input class="input-attr" v-model="data.clazz.varKeyVal" clearable @blur="methods.handleClazzVarKeyVal"/>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>{{ PROP_CONST.TEXT_DESC.condSpELExplain }}</template>
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="函数表达式" v-if="data.clazz.valType === '2'">
|
||||
<el-input class="input-attr" v-model="data.clazz.varKeyVal" placeholder="请输入函数表达式" clearable @blur="methods.handleClazzVarKeyVal"/>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>{{ PROP_CONST.TEXT_DESC.condMethodExplain1 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain2 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain3 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain4 }}
|
||||
</template>
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="监听备注">
|
||||
<el-input class="input-attr" type="textarea" v-model="data.clazz.remark"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="监听排序">
|
||||
<el-input-number class="input-attr" v-model="data.clazz.sort" :min="1"></el-input-number>
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
|
||||
<el-button type="primary" round style="margin-left: 185px; margin-top: 30px; margin-bottom: 30px; width: 200px" @click="methods.addFlowNodeClazz(props.addType)">
|
||||
{{ data.clazz.isSelectedRow ? '修改完成': '添加事件' }}
|
||||
</el-button>
|
||||
<el-divider>已添加监听事件列表(点击行可再次修改)</el-divider>
|
||||
<el-empty description="监听事件列表为空" style="margin: 10px 230px" v-if="!data.existData">
|
||||
</el-empty>
|
||||
<el-table :data="data.tableData" border style="width: 100%" max-height="500" v-else
|
||||
highlight-current-row @current-change="methods.handleCurrentChange" ref="tableDataRef">
|
||||
<el-table-column type="index" label="操作" width="55">
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle @click="methods.handleClazzDelete(scope.$index, scope.row, props.addType)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="clazz" :label="t('flowClazz.clazz')" width="130" show-overflow-tooltip/>
|
||||
<el-table-column prop="httpUrl" :label="t('flowClazz.httpUrl')" width="130" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column prop="methods" label="触发时机" width="130" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="props.flowMethods" :value="scope.row.methods"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varKeyVal" label="函数表达式" width="130" show-overflow-tooltip v-if="data.clazz.valType === '2'"/>
|
||||
<el-table-column prop="varKeyVal" label="SpEL表达式" width="130" show-overflow-tooltip v-if="data.clazz.valType === '1'"/>
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" width="130" show-overflow-tooltip v-if="data.clazz.valType === '0'">
|
||||
<template #default="scope">
|
||||
<convert-group-name :options="data.allFieldPerms" :value="scope.row.varKeyVal"
|
||||
:valueKey="'prop'" :showKey="'label'"></convert-group-name>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" width="100" show-overflow-tooltip v-if="data.clazz.valType === '0'">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="DIC_PROP.OPERATOR" :value="scope.row.operator"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" width="100" show-overflow-tooltip v-if="data.clazz.valType === '0'"/>
|
||||
<el-table-column prop="remark" :label="t('flowClazz.remark')" width="70" show-overflow-tooltip/>
|
||||
<el-table-column prop="sort" :label="t('flowClazz.sort')" width="70" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
</el-form>
|
||||
|
||||
<el-drawer
|
||||
class="flow-attr-drawer"
|
||||
title="Http请求的参数信息"
|
||||
direction="rtl"
|
||||
append-to-body
|
||||
:size="630" v-if="data.httpUrlParamsVisible"
|
||||
v-model="data.httpUrlParamsVisible">
|
||||
<el-form label-position="left" class="flow-attr flow-param-attr" label-width="150px">
|
||||
<flow-http-param ref="flowHttpParam" :currFlowForm="props.currFlowForm" :httpParam="data.clazz"
|
||||
:flowData="props.flowData"></flow-http-param>
|
||||
</el-form>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowClazz">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {rule, validateNull} from "/@/utils/validate";
|
||||
import {deepClone} from "/@/utils/other";
|
||||
import {DIC_PROP} from "/@/flow/support/dict-prop";
|
||||
import {buildSysFieldsFormOption} from "../../utils/form-perm";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const FlowHttpParam = defineAsyncComponent(() => import('./flow-http-param.vue'));
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
clazzPlaceholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
flowMethods: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
addType: {
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
});
|
||||
|
||||
const clazzData = {
|
||||
clazz: null,
|
||||
httpUrl: null,
|
||||
httpMethod: 'GET',
|
||||
httpParams: null,
|
||||
methods: null,
|
||||
valType: null,
|
||||
varKeyVal: null,
|
||||
operator: null,
|
||||
varVal: null,
|
||||
remark: null,
|
||||
sort: 1,
|
||||
}
|
||||
const data = reactive({
|
||||
tableFieldData: [],
|
||||
allFieldPerms: [],
|
||||
formFieldPerms: [],
|
||||
clazz: deepClone(clazzData),
|
||||
httpUrlParamsVisible: false,
|
||||
moreInter: false,
|
||||
existData: false,
|
||||
tableData: []
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
methods.changeTabPane(props.currSelect)
|
||||
})
|
||||
|
||||
const methods = {
|
||||
openHttpUrlParams(bool) {
|
||||
if (!data.clazz.httpUrl) {
|
||||
$message.warning("请先输入【Http请求地址】")
|
||||
return
|
||||
}
|
||||
data.httpUrlParamsVisible = bool
|
||||
},
|
||||
handleHttpUrlBlur() {
|
||||
if (!data.clazz.httpUrl) {
|
||||
data.clazz.httpParams = []
|
||||
return;
|
||||
}
|
||||
},
|
||||
handleCurrentChange(row) {
|
||||
if (!row) return
|
||||
data.clazz = row
|
||||
data.clazz.isSelectedRow = true
|
||||
},
|
||||
handleVarKeyVal(varKeyVal) {
|
||||
let dots = varKeyVal.split('.').length - 1;
|
||||
if (dots === 2) {
|
||||
data.varValOperator = DIC_PROP.OPERATOR.slice(6)
|
||||
} else {
|
||||
data.varValOperator = DIC_PROP.OPERATOR
|
||||
}
|
||||
},
|
||||
onAddItem(){
|
||||
if (validateNull(data.formFieldPerms)) {
|
||||
buildSysFieldsFormOption(data, props, $message)
|
||||
}
|
||||
if (data.tableFieldData.length > 0) return
|
||||
let obj = {varKeyVal: '', operator: '', varVal: ''};
|
||||
data.tableFieldData.push(obj);
|
||||
},
|
||||
addFlowNodeClazz(type) {
|
||||
let clazzes = type === '0' ? props.currSelect.attributes.attrs.cdata.attrs.clazzes : props.flowData.attrs.clazzes;
|
||||
if (!data.clazz.clazz && !data.clazz.httpUrl) {
|
||||
$message.warning("请填写 监听类 或者 Http请求地址")
|
||||
return
|
||||
}
|
||||
if (validateNull(data.clazz.methods)) {
|
||||
$message.warning("触发时机不能为空")
|
||||
return
|
||||
}
|
||||
if (!validateNull(clazzes) && !data.clazz.isSelectedRow) {
|
||||
if (data.clazz.clazz) {
|
||||
let b = methods.validateClazzHttpUrl(clazzes, 'clazz', '监听类');
|
||||
if (b) return;
|
||||
} else {
|
||||
let b = methods.validateClazzHttpUrl(clazzes, 'httpUrl', 'Http请求地址');
|
||||
if (b) return;
|
||||
}
|
||||
}
|
||||
if (data.clazz.clazz && data.clazz.httpUrl) {
|
||||
$message.error("监听类 与 Http请求地址不能同时存在")
|
||||
return;
|
||||
}
|
||||
if (data.clazz.isSelectedRow) {
|
||||
data.clazz.isSelectedRow = false
|
||||
proxy.$refs.tableDataRef.setCurrentRow(null)
|
||||
data.clazz = deepClone(clazzData);
|
||||
} else {
|
||||
let clazz = deepClone(data.clazz);
|
||||
if (type === '0') props.currSelect.attributes.attrs.cdata.attrs.clazzes.unshift(clazz)
|
||||
else props.flowData.attrs.clazzes.unshift(clazz)
|
||||
methods.validateClazzData()
|
||||
}
|
||||
},
|
||||
validateClazzHttpUrl(clazzes, key, errMsg){
|
||||
let find = clazzes.find(f => f[key] === data.clazz[key]);
|
||||
if (find) {
|
||||
$message.warning("请勿重复添加 " + errMsg)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
handleClazzDelete(index: number, row: any, type: string){
|
||||
if (type === '0') props.currSelect.attributes.attrs.cdata.attrs.clazzes.splice(index, 1)
|
||||
else props.flowData.attrs.clazzes.splice(index, 1)
|
||||
methods.validateClazzData()
|
||||
},
|
||||
handleClazzValType(type?) {
|
||||
if (!type) {
|
||||
type = methods.initCurrVarKeyVal()
|
||||
}
|
||||
if (type === DIC_PROP.VAL_TYPE[2].value) {
|
||||
data.varValOperator = DIC_PROP.OPERATOR
|
||||
methods.onAddItem()
|
||||
} else {
|
||||
data.varValOperator = []
|
||||
}
|
||||
data.clazz.varKeyVal = null
|
||||
data.clazz.operator = null
|
||||
data.clazz.varVal = null
|
||||
},
|
||||
handleClazzVarKeyVal() {
|
||||
let val = data.clazz.varKeyVal
|
||||
if (!val) return
|
||||
let valType = data.clazz.valType;
|
||||
if (valType === DIC_PROP.VAL_TYPE[3].value && val.indexOf("#") === -1) {
|
||||
data.clazz.varKeyVal = null
|
||||
$message.warning("当选择SpEL模式时, SpEL表达式必须符合SpEL格式")
|
||||
} else if (valType === DIC_PROP.VAL_TYPE[4].value && val.indexOf("#") === -1) {
|
||||
data.clazz.varKeyVal = null
|
||||
$message.warning("当选择专业模式时, 函数表达式必须符合规定的格式")
|
||||
}
|
||||
},
|
||||
showMoreSetting() {
|
||||
data.moreInter = !data.moreInter
|
||||
},
|
||||
validateClazzData() {
|
||||
let clazzes = props.addType === '0' ? props.currSelect.attributes.attrs.cdata.attrs.clazzes : props.flowData.attrs.clazzes;
|
||||
if (!clazzes) {
|
||||
if (props.addType === '0') props.currSelect.attributes.attrs.cdata.attrs.clazzes = []
|
||||
else props.flowData.attrs.clazzes = []
|
||||
}
|
||||
data.tableData.splice(0, data.tableData.length);
|
||||
if (props.addType === '0') {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.clazzes.forEach(each => data.tableData.push(each))
|
||||
} else {
|
||||
props.flowData.attrs.clazzes.forEach(each => data.tableData.push(each))
|
||||
}
|
||||
data.existData = !validateNull(data.tableData)
|
||||
},
|
||||
initCurrVarKeyVal() {
|
||||
if (data.tableData.length > 0) {
|
||||
data.clazz.valType = data.tableData[0].valType
|
||||
}
|
||||
data.clazz.methods = []
|
||||
return data.clazz.valType
|
||||
},
|
||||
changeTabPane(val) {
|
||||
methods.validateClazzData()
|
||||
methods.handleClazzValType()
|
||||
}
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.currSelect,
|
||||
(val) => {
|
||||
if (Object.keys(val).length === 0) {
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
527
src/flow/designer/components/flow-con-rule.vue
Normal file
527
src/flow/designer/components/flow-con-rule.vue
Normal file
@@ -0,0 +1,527 @@
|
||||
<template>
|
||||
<el-form-item label="起始节点(可修改)">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.fromFlowNodeId"
|
||||
@change="methods.changeLinkFlowNodeIds('0')"
|
||||
filterable clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.fromFlowNodeIds"
|
||||
:key="item.id"
|
||||
:label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="目标节点(可修改)">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.toFlowNodeId"
|
||||
@change="methods.changeLinkFlowNodeIds('1')"
|
||||
filterable clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.toFlowNodeIds"
|
||||
:key="item.id"
|
||||
:label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="条件组关系">
|
||||
<el-switch
|
||||
v-model="data.cond.groupsType" @change="methods.changeGroupsType"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="条件模式">
|
||||
<el-radio-group @change="methods.handleCondValType" :disabled="data.existData"
|
||||
v-model="data.cond.valType">
|
||||
<el-radio v-for="(item, index) in DIC_PROP.VAL_TYPE.slice(2, 6)" :key="index" :label="item.value"
|
||||
style="width: 56px">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>若无法切换模式,请先清空条件组列表</template>
|
||||
<el-icon style="margin-left: 30px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider>组内条件配置</el-divider>
|
||||
|
||||
<template v-if="data.cond.valType === '0'">
|
||||
<el-form-item label="组内条件关系">
|
||||
<el-switch
|
||||
v-model="data.cond.groupType"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="data.cond.condGroup"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" label="操作" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="methods.onAddItem(true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle @click="methods.handleCondDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal" @change="methods.handleVarKeyVal(scope.row)"
|
||||
clearable
|
||||
filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.operator" @change="methods.handleVarKeyVal(scope.row)"
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.varValOperator"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.varVal" clearable/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<el-form-item label="SpEL表达式" v-if="data.cond.valType === '1'">
|
||||
<el-input class="input-attr" v-model="data.cond.varKeyVal" placeholder="请输入SpEL表达式" clearable @blur="methods.handleCondVarKeyVal"/>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>{{ PROP_CONST.TEXT_DESC.condSpELExplain }}</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="函数表达式" v-if="data.cond.valType === '2'">
|
||||
<el-input class="input-attr" v-model="data.cond.varKeyVal" placeholder="请输入函数表达式" clearable @blur="methods.handleCondVarKeyVal"/>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>{{ PROP_CONST.TEXT_DESC.condMethodExplain1 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain2 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain3 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain4 }}
|
||||
</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<div v-if="data.cond.valType === '2'" style="margin: 10px 13px">
|
||||
<span style="color: #409EFF;font-size: 14px">注: 当前函数表达式的返回值为字符串 1 ( 满足 ) 或 0 ( 不满足 )</span>
|
||||
</div>
|
||||
|
||||
<template v-if="data.cond.valType === '3'">
|
||||
<el-form-item label="Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="data.cond.varKeyVal"
|
||||
@blur="methods.handleCondVarKeyVal" clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="data.cond.httpMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip content="点击可设置Http请求的参数信息" placement="bottom">
|
||||
<el-button type="primary" size="small" round style="margin-left: 10px"
|
||||
@click="methods.openHttpUrlParams()">
|
||||
{{ data.httpUrlParamsVisible ? '清空' : '参数' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<flow-http-param ref="flowHttpParam" :currFlowForm="props.currFlowForm" :flowData="props.flowData"
|
||||
:httpParam="props.currSelect.attributes.attrs.cdata.attrs"
|
||||
:httpParamType="DIC_PROP.PARAM_RULE_TYPE[1].value"
|
||||
v-if="data.httpUrlParamsVisible">
|
||||
</flow-http-param>
|
||||
</template>
|
||||
|
||||
<template v-if="data.cond.valType === '0'">
|
||||
<el-button type="primary" round style="margin-left: 185px; margin-top: 30px; margin-bottom: 30px; width: 200px"
|
||||
@click="methods.addFlowNodeCondGroup()">
|
||||
{{ data.oldCurrentRow ? '修改完成': '添加条件组' }}
|
||||
</el-button>
|
||||
<el-divider>已添加条件组列表(点击行可再次修改)</el-divider>
|
||||
<el-empty description="条件组列表为空" style="margin: 10px 230px" v-if="!data.existData">
|
||||
</el-empty>
|
||||
|
||||
<template v-for="(item, index) in data.condGroups" v-else
|
||||
:key="index">
|
||||
|
||||
<el-collapse v-model="data.collapse">
|
||||
<el-collapse-item :name="index">
|
||||
<template #title>
|
||||
{{ '条件组 ' + (index + 1) }}
|
||||
|
||||
<el-icon style="margin-left: 10px" @click="methods.handleCondGroupDelete(index)">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</template>
|
||||
|
||||
<el-form-item label="组内条件关系">
|
||||
<el-switch
|
||||
v-model="item.groupType" @change="methods.changeGroupType(item, index)"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="item.condGroup" border style="width: 100%" max-height="500"
|
||||
highlight-current-row @current-change="methods.handleCurrentChange" :ref="'tableDataRef' + index">
|
||||
|
||||
<el-table-column type="index" label="操作" width="80">
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleSingleCondDelete(scope.$index, scope.row, index)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<convert-group-name :options="data.allFieldPerms"
|
||||
:value="scope.row.varKeyVal"
|
||||
:valueKey="'prop'" :showKey="'label'"></convert-group-name>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="DIC_PROP.OPERATOR" :value="scope.row.operator"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowConRule">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {rule, validateNull} from "/@/utils/validate";
|
||||
import {deepClone} from "/@/utils/other";
|
||||
import {DIC_PROP} from "/@/flow/support/dict-prop";
|
||||
import {buildSysFieldsFormOption} from "../../utils/form-perm";
|
||||
import {PROP_CONST} from "../../support/prop-const";
|
||||
import {changeLinkFlowNodeIds, handleLinkFlowNodeIds} from "./index";
|
||||
|
||||
const {proxy} = getCurrentInstance();
|
||||
const FlowHttpParam = defineAsyncComponent(() => import('./flow-http-param.vue'));
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const $emit = defineEmits(["hideAttrConfig"]);
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
attrConfigVisible: null
|
||||
});
|
||||
|
||||
const condData = {
|
||||
httpMethod: 'GET',
|
||||
groupsType: '0',
|
||||
condGroup: [],
|
||||
groupType: '0',
|
||||
valType: '0',
|
||||
varKeyVal: null,
|
||||
operator: null,
|
||||
varVal: null,
|
||||
}
|
||||
|
||||
const data = reactive({
|
||||
collapse: [0],
|
||||
allFieldPerms: [],
|
||||
formFieldPerms: [],
|
||||
cond: deepClone(condData),
|
||||
httpUrlParamsVisible: false,
|
||||
oldCurrentRow: null,
|
||||
condGroups: [],
|
||||
existData: false,
|
||||
modifyPointType: null,
|
||||
fromFlowNodeId: null,
|
||||
fromFlowNodeIds: [],
|
||||
toFlowNodeId: null,
|
||||
toFlowNodeIds: []
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
methods.changeTabPane(props.currSelect)
|
||||
})
|
||||
|
||||
const methods = {
|
||||
openHttpUrlParams() {
|
||||
if (!data.cond.varKeyVal) {
|
||||
$message.warning("请先输入【Http请求地址】")
|
||||
return
|
||||
}
|
||||
if (data.httpUrlParamsVisible) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpParams = []
|
||||
data.httpUrlParamsVisible = false
|
||||
} else {
|
||||
data.httpUrlParamsVisible = true
|
||||
}
|
||||
},
|
||||
handleCurrentChange(row) {
|
||||
if (!row) return
|
||||
let condGroupsRow;
|
||||
for (let i = 0; i < data.condGroups.length; i++) {
|
||||
let index = data.condGroups[i].condGroup.indexOf(row);
|
||||
if (index !== -1) {
|
||||
condGroupsRow = data.condGroups[i];
|
||||
}
|
||||
}
|
||||
// 先清空之前选中的其他条件组
|
||||
if (data.oldCurrentRow !== condGroupsRow) {
|
||||
let oldIndex = data.condGroups.indexOf(data.oldCurrentRow);
|
||||
if (oldIndex !== -1) {
|
||||
proxy.$refs['tableDataRef' + oldIndex][0].setCurrentRow(null)
|
||||
}
|
||||
}
|
||||
data.cond = condGroupsRow
|
||||
data.oldCurrentRow = condGroupsRow
|
||||
},
|
||||
handleVarKeyVal(row) {
|
||||
let dots = row.varKeyVal.split('.').length - 1;
|
||||
if (dots === 2) {
|
||||
let find = DIC_PROP.OPERATOR.slice(6).find(f => f.value === row.operator);
|
||||
if (!find) {
|
||||
$message.warning("子表单的字段只能选择包含或不包含")
|
||||
row.operator = null
|
||||
}
|
||||
}
|
||||
},
|
||||
changeGroupsType(groupsType) {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.attrs.condGroups;
|
||||
if (validateNull(condGroups)) return
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.forEach(each => {
|
||||
each.groupsType = groupsType
|
||||
})
|
||||
methods.validateCondData()
|
||||
},
|
||||
changeGroupType(item, index) {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.attrs.condGroups;
|
||||
if (validateNull(condGroups)) return
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups[index].groupType = item.groupType
|
||||
methods.validateCondData()
|
||||
},
|
||||
onAddItem(isAdd) {
|
||||
if (validateNull(data.formFieldPerms)) {
|
||||
buildSysFieldsFormOption(data, props, $message)
|
||||
}
|
||||
if (data.cond.condGroup.length > 0) {
|
||||
let find = data.cond.condGroup.find(f => !f.varKeyVal || !f.operator || !f.varVal);
|
||||
if (find) {
|
||||
let b = !find.varKeyVal || !find.operator || !find.varVal;
|
||||
if (isAdd && b) {
|
||||
$message.warning("请先填写 表单字段 或 运算符 或 值")
|
||||
return
|
||||
}
|
||||
}
|
||||
if (!isAdd) data.cond.condGroup.splice(0, data.cond.condGroup.length);
|
||||
}
|
||||
let obj = {varKeyVal: '', operator: '', varVal: ''};
|
||||
data.cond.condGroup.push(obj);
|
||||
},
|
||||
addFlowNodeCondGroup() {
|
||||
if (validateNull(data.cond.condGroup)) {
|
||||
$message.warning("请先添加组内条件")
|
||||
return
|
||||
}
|
||||
let valType = data.cond.valType;
|
||||
let find = data.cond.condGroup.find(f => !f.varKeyVal || !f.operator || !f.varVal);
|
||||
if (find) {
|
||||
if (valType === DIC_PROP.VAL_TYPE[2].value) {
|
||||
if (!find.varKeyVal || !find.operator || !find.varVal) {
|
||||
$message.warning("表单字段 或 运算符 或 值 不能为空")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.oldCurrentRow) {
|
||||
// 先清空之前选中
|
||||
let index = data.condGroups.indexOf(data.cond);
|
||||
if (index !== -1) {
|
||||
proxy.$refs['tableDataRef' + index][0].setCurrentRow(null)
|
||||
}
|
||||
data.oldCurrentRow = null
|
||||
data.cond = deepClone(condData);
|
||||
} else {
|
||||
let cond = deepClone(data.cond);
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.unshift(cond)
|
||||
methods.validateCondData()
|
||||
methods.updateCondVarKeyVal(true)
|
||||
}
|
||||
},
|
||||
handleCondGroupDelete(index: number) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.splice(index, 1)
|
||||
methods.validateCondData()
|
||||
},
|
||||
handleSingleCondDelete(index: number, row: any, groupIndex) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups[groupIndex].condGroup.splice(index, 1)
|
||||
if (validateNull(props.currSelect.attributes.attrs.cdata.attrs.condGroups[groupIndex].condGroup)) {
|
||||
methods.handleCondGroupDelete(groupIndex)
|
||||
}
|
||||
methods.validateCondData()
|
||||
},
|
||||
handleCondDelete(index: number, row: any) {
|
||||
data.cond.condGroup.splice(index, 1)
|
||||
},
|
||||
handleCondValType(type?) {
|
||||
if (type) {
|
||||
data.cond.varKeyVal = null
|
||||
methods.updateCondVarKeyVal(false)
|
||||
}
|
||||
if (!type) {
|
||||
type = methods.initCurrVarKeyVal()
|
||||
}
|
||||
if (type === DIC_PROP.VAL_TYPE[2].value) {
|
||||
data.varValOperator = DIC_PROP.OPERATOR
|
||||
methods.onAddItem(false)
|
||||
} else {
|
||||
data.varValOperator = []
|
||||
}
|
||||
data.cond.operator = null
|
||||
data.cond.varVal = null
|
||||
},
|
||||
handleCondVarKeyVal() {
|
||||
let val = data.cond.varKeyVal
|
||||
let valType = data.cond.valType;
|
||||
if (!val) {
|
||||
methods.updateCondVarKeyVal(false)
|
||||
return
|
||||
}
|
||||
if (valType === DIC_PROP.VAL_TYPE[2].value) return
|
||||
if (valType === DIC_PROP.VAL_TYPE[3].value && val.indexOf("#") === -1) {
|
||||
data.cond.varKeyVal = null
|
||||
$message.warning("当选择SpEL模式时, SpEL表达式必须符合SpEL格式")
|
||||
return;
|
||||
} else if (valType === DIC_PROP.VAL_TYPE[4].value && val.indexOf("#") === -1) {
|
||||
data.cond.varKeyVal = null
|
||||
$message.warning("当选择专业模式时, 函数表达式必须符合规定的格式")
|
||||
return;
|
||||
}
|
||||
methods.updateCondVarKeyVal(true)
|
||||
},
|
||||
updateCondVarKeyVal(isSave) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.valType = data.cond.valType
|
||||
if (isSave) {
|
||||
if (data.cond.valType === DIC_PROP.VAL_TYPE[2].value) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.varKeyVal = PROP_CONST.VAR_KEY_VAL.link
|
||||
} else {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.varKeyVal = data.cond.varKeyVal
|
||||
}
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpMethod = data.cond.httpMethod
|
||||
} else {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.varKeyVal = null
|
||||
props.currSelect.attributes.attrs.cdata.attrs.varKeyValName = null
|
||||
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups = []
|
||||
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpParams = []
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpMethod = null
|
||||
data.httpUrlParamsVisible = false
|
||||
}
|
||||
},
|
||||
validateCondData() {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.attrs.condGroups;
|
||||
if (!condGroups) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups = []
|
||||
}
|
||||
data.condGroups.splice(0, data.condGroups.length);
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.forEach(each => data.condGroups.push(each))
|
||||
data.existData = !validateNull(data.condGroups)
|
||||
},
|
||||
initCurrVarKeyVal() {
|
||||
data.cond.valType = props.currSelect.attributes.attrs.cdata.attrs.valType
|
||||
if (data.condGroups.length <= 0) {
|
||||
data.cond.varKeyVal = props.currSelect.attributes.attrs.cdata.attrs.varKeyVal
|
||||
let httpMethod = props.currSelect.attributes.attrs.cdata.attrs.httpMethod
|
||||
if (httpMethod) data.cond.httpMethod = httpMethod
|
||||
} else {
|
||||
data.cond.groupsType = data.condGroups[0].groupsType
|
||||
}
|
||||
let httpParams = props.currSelect.attributes.attrs.cdata.attrs.httpParams;
|
||||
if (!validateNull(httpParams)) {
|
||||
data.httpUrlParamsVisible = true
|
||||
}
|
||||
return data.cond.valType
|
||||
},
|
||||
handleLinkFlowNodeIds() {
|
||||
handleLinkFlowNodeIds(data, props)
|
||||
},
|
||||
changeLinkFlowNodeIds(type) {
|
||||
data.modifyPointType = type
|
||||
changeLinkFlowNodeIds(data, props, methods, $emit)
|
||||
},
|
||||
changeTabPane(val) {
|
||||
methods.validateCondData()
|
||||
methods.handleCondValType()
|
||||
methods.handleLinkFlowNodeIds()
|
||||
}
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.currSelect,
|
||||
(val) => {
|
||||
if (Object.keys(val).length === 0 || !props.attrConfigVisible) {
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
125
src/flow/designer/components/flow-curr-job.vue
Normal file
125
src/flow/designer/components/flow-curr-job.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<el-table :data="props.currSelect.attributes.attrs.cdata.defJob.currRunJobs" style="width: 100%">
|
||||
<el-table-column type="index" :label="t('createTable.index')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="onAddItem"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle @click="handleDelete(scope.$index, scope.row)"
|
||||
:disabled="scope.row.isConfigJob === '1'"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sort" :label="t('runJob.sort')" show-overflow-tooltip width="70">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.sort" :placeholder="t('runJob.inputSortTip')"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="jobName" :label="t('runJob.jobName')" show-overflow-tooltip width="150">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.jobName" :placeholder="t('runJob.inputJobNameTip')"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="jobType" :label="t('runJob.jobType')" show-overflow-tooltip width="100">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.jobType" :placeholder="t('runJob.inputJobTypeTip')" clearable filterable
|
||||
@change="handleRoleType(scope.row)">
|
||||
<el-option v-for="(item, index) in DIC_PROP.JOB_USER_NONE_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="roleId" :label="t('runJob.roleId')" show-overflow-tooltip width="130">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="请输入名称进行模糊搜索" placement="top">
|
||||
<el-select v-model="scope.row.roleId" :placeholder="t('runJob.inputRoleIdTip')" clearable filterable
|
||||
remote :remote-method="(query) => remoteMethodAll(query, scope.row.jobType)" :reserve-keyword="false">
|
||||
<el-option v-for="(item, index) in dicData.users" :key="index" :label="item.name" :value="item.userId"
|
||||
v-if="scope.row.jobType === DIC_PROP.JOB_USER_TYPE[0].value"></el-option>
|
||||
<el-option v-for="(item, index) in dicData.roles" :key="index" :label="item.roleName" :value="item.roleId"
|
||||
v-if="scope.row.jobType === DIC_PROP.JOB_USER_TYPE[1].value"></el-option>
|
||||
<el-option v-for="(item, index) in dicData.posts" :key="index" :label="item.postName" :value="item.postId"
|
||||
v-if="scope.row.jobType === DIC_PROP.JOB_USER_TYPE[2].value"></el-option>
|
||||
<el-option v-for="(item, index) in dicData.depts" :key="index" :label="item.name" :value="item.deptId"
|
||||
v-if="scope.row.jobType === DIC_PROP.JOB_USER_TYPE[3].value"></el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="userId" :label="t('runJob.userId')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<convert-name :options="dicData.userId" :value="scope.row.userId"
|
||||
:valueKey="'userId'" :showKey="'name'"></convert-name>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="startTime" :label="t('runJob.startTime')" show-overflow-tooltip/>
|
||||
<el-table-column prop="status" :label="t('runJob.status')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="DIC_PROP.NODE_STATUS" :value="scope.row.status"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowCurrJob">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {onFormLoadedUrl, onLoadDicUrl, remoteMethodAllByKey} from "../../components/convert-name/convert";
|
||||
import {handleChangeJobType} from "../../index";
|
||||
import {DIC_PROP} from "../../support/dict-prop";
|
||||
import {validateNull} from "../../../utils/validate";
|
||||
import {PROP_CONST} from "../../support/prop-const";
|
||||
|
||||
const {proxy} = getCurrentInstance();
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
// 定义字典
|
||||
const dicData = reactive({});
|
||||
const onLoad = onLoadDicUrl();
|
||||
const onFormLoaded = onFormLoadedUrl({key: "userId"}, ...PROP_CONST.LOAD_USER_ROLE);
|
||||
onMounted(async () => {
|
||||
// await onLoad(dicData);
|
||||
await onFormLoadedCurrRunJobs()
|
||||
})
|
||||
|
||||
const onAddItem = () => {
|
||||
let jobName = props.currSelect.attributes.attrs.cdata.defJob.jobName;
|
||||
let obj = {sort: 1, jobName: jobName, jobType: DIC_PROP.JOB_USER_NONE_TYPE[0].value, roleId: null, userId: null,
|
||||
startTime: null, status: DIC_PROP.NODE_STATUS[0].value};
|
||||
props.currSelect.attributes.attrs.cdata.defJob.currRunJobs.push(obj);
|
||||
}
|
||||
|
||||
const handleDelete = (index: number, row: any) => {
|
||||
let currRunJobs = props.currSelect.attributes.attrs.cdata.defJob.currRunJobs;
|
||||
if (currRunJobs.length === 1) {
|
||||
useMessage().warning("当前节点参与者至少需存在一个参与者");
|
||||
return
|
||||
}
|
||||
props.currSelect.attributes.attrs.cdata.defJob.currRunJobs.splice(index, 1)
|
||||
}
|
||||
|
||||
function remoteMethodAll(query: string, jobType) {
|
||||
remoteMethodAllByKey(onLoad, dicData, query, jobType)
|
||||
}
|
||||
|
||||
function onFormLoadedCurrRunJobs() {
|
||||
let currRunJobs = props.currSelect.attributes.attrs.cdata.defJob.currRunJobs
|
||||
if (validateNull(currRunJobs)) return
|
||||
onFormLoaded(dicData, currRunJobs)
|
||||
}
|
||||
|
||||
function handleRoleType(row) {
|
||||
handleChangeJobType(dicData, row)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
207
src/flow/designer/components/flow-form-http.vue
Normal file
207
src/flow/designer/components/flow-form-http.vue
Normal file
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="160px">
|
||||
<el-form-item label="查询表单Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="props.flowData.attrs.queryOrder"
|
||||
clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="props.flowData.attrs.queryMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content>查询表单信息接口(可输入全路径或相对路径)</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="更新表单Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="props.flowData.attrs.updateOrder"
|
||||
clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="props.flowData.attrs.updateMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content>更新表单信息接口(可输入全路径或相对路径)</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider>关联表单Http请求头</el-divider>
|
||||
|
||||
<el-table :data="data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value)"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" :label="t('jfI18n.operate')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle
|
||||
@click="methods.onAddItem(DIC_PROP.PARAM_FROM[0].value, true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleHttpUrlDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="targetProp" :label="t('jfAttr.requestHeader')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.targetProp" :placeholder="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value ? scope.row.varKeyVal : null"
|
||||
clearable></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="paramValType" :label="t('jfAttr.paramValType')" width="145px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.paramValType" clearable>
|
||||
<el-option v-for="(item, index) in DIC_PROP.SYS_PARAM_VAL_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('jfAttr.sysVarKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal"
|
||||
v-if="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value"
|
||||
clearable filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
|
||||
<el-input v-else v-model="scope.row.varKeyVal" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
</el-form>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowHttpParam">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {handleFieldProp} from "../../utils/form-perm";
|
||||
import {DIC_PROP} from "../../support/dict-prop";
|
||||
import {PROP_CONST} from "../../support/prop-const";
|
||||
import {deepClone} from "/@/utils/other";
|
||||
|
||||
const {proxy} = getCurrentInstance();
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
attrConfigVisible: null
|
||||
});
|
||||
|
||||
const data = reactive({
|
||||
allFieldPerms: [],
|
||||
formFieldPerms: [],
|
||||
httpParams: [],
|
||||
paramType: '0',
|
||||
})
|
||||
|
||||
// 定义字典
|
||||
onMounted(async () => {
|
||||
if (!props.attrConfigVisible) return
|
||||
methods.changeTabPane()
|
||||
})
|
||||
|
||||
const methods = {
|
||||
listFormFieldPerms() {
|
||||
if (validateNull(data.formFieldPerms)) {
|
||||
let formFieldPerms = deepClone(PROP_CONST.SYS_FIELDS);
|
||||
handleFieldProp(formFieldPerms, null)
|
||||
data.allFieldPerms = [{label: '系统字段', options: formFieldPerms}]
|
||||
}
|
||||
},
|
||||
onAddItem(paramFrom, isAdd) {
|
||||
methods.listFormFieldPerms()
|
||||
let value = DIC_PROP.PARAM_VAL_TYPE[0].value;
|
||||
if (data.httpParams.length > 0) {
|
||||
let find = data.httpParams.filter(f => f.paramFrom === paramFrom).find(f => !f.varKeyVal || (f.paramValType !== value && !f.targetProp));
|
||||
if (find) {
|
||||
if (isAdd) {
|
||||
if (!find.varKeyVal) {
|
||||
$message.warning("请先填写 表单字段")
|
||||
return
|
||||
}
|
||||
if (find.paramValType !== value && !find.targetProp) {
|
||||
$message.warning("请先填写 请求头")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isAdd) data.httpParams.splice(0, data.httpParams.length);
|
||||
}
|
||||
let obj = {paramFrom: paramFrom, varKeyVal: null, paramValType: value, targetProp: null};
|
||||
data.httpParams.push(obj);
|
||||
methods.changeHttpUrlParams()
|
||||
},
|
||||
handleHttpUrlDelete(index: number, row: any) {
|
||||
let splice = data.httpParams.filter(f => f.paramFrom === row.paramFrom);
|
||||
splice.splice(index, 1);
|
||||
data.httpParams = splice
|
||||
methods.changeHttpUrlParams()
|
||||
},
|
||||
validateHttpUrlData() {
|
||||
// 兼容老版本
|
||||
let httpParams = props.flowData.attrs.orderParams;
|
||||
if (!httpParams) {
|
||||
props.flowData.attrs.orderParams = []
|
||||
}
|
||||
let queryMethod = props.flowData.attrs.queryMethod;
|
||||
if (!queryMethod) props.flowData.attrs.queryMethod = 'GET'
|
||||
let updateMethod = props.flowData.attrs.updateMethod;
|
||||
if (!updateMethod) props.flowData.attrs.updateMethod = 'PUT'
|
||||
data.httpParams = props.flowData.attrs.orderParams
|
||||
},
|
||||
changeHttpUrlParams() {
|
||||
props.flowData.attrs.orderParams = data.httpParams
|
||||
},
|
||||
changeTabPane() {
|
||||
methods.validateHttpUrlData()
|
||||
methods.listFormFieldPerms()
|
||||
}
|
||||
}
|
||||
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.attrConfigVisible,
|
||||
(val) => {
|
||||
if (!val) return
|
||||
methods.changeTabPane()
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
295
src/flow/designer/components/flow-form-perm.vue
Normal file
295
src/flow/designer/components/flow-form-perm.vue
Normal file
@@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<el-form v-if="methods.validateNode(props.currSelect)"
|
||||
label-position="left" class="flow-config-attr" label-width="130px">
|
||||
|
||||
<el-form-item label="全部只读或可编辑" prop="formPermType">
|
||||
<el-tooltip placement="top">
|
||||
<template #content>1、对当前节点表单的字段全部只读 或 全部可编辑。默认全部可编辑
|
||||
<br/> 2、可在下方进一步约束权限,如这里选择全部只读,下方配置某些字段可编辑
|
||||
</template>
|
||||
<el-radio-group v-model="props.currSelect.attributes.attrs.cdata.attrs.formPermType">
|
||||
<el-radio v-for="(item, index) in DIC_PROP.ALL_FORM_PERM_TYPE" :key="index" :label="item.value" style="width: 135px">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip placement="top" v-if="props.currSelect.attributes.attrs.cdata.attrs.formPermType">
|
||||
<template #content>清空后可在下方单个字段配置权限或业务侧自行判断</template>
|
||||
<el-button text type="primary" icon="delete" @click="props.currSelect.attributes.attrs.cdata.attrs.formPermType = null">
|
||||
清空
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider>请选择表单名称</el-divider>
|
||||
<el-form-item label="PC待办页面">
|
||||
<el-tooltip placement="top">
|
||||
<template #content>若下拉选项为空或没有期望的表单,请先在节点属性-PC待办页面选择</template>
|
||||
<el-select class="input-attr"
|
||||
v-model="props.currSelect.attributes.attrs.cdata.attrs.formId"
|
||||
@change="methods.changeNodeFormId"
|
||||
clearable filterable placeholder="请选择节点属性-PC待办页面">
|
||||
<template v-for="(item, index) in props.formIds">
|
||||
<el-option
|
||||
v-if="methods.filterNodeFormId(item)"
|
||||
:key="index"
|
||||
:label="item.formName+' V'+item.version"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-button @click="methods.addFormPermission" type="primary" round v-if="props.isShowAdd"
|
||||
style="margin-left: 10px;">新增字段
|
||||
</el-button>
|
||||
<el-button @click="methods.resetFormPerm" type="primary" size="small" round v-if="!props.isShowAdd"
|
||||
style="margin-left: 10px;">重置权限
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider>参与者可以操作表单字段权限</el-divider>
|
||||
<el-empty description="表单字段权限列表为空" style="margin: 10px 230px" v-if="validateNull(data.formFieldPerms)">
|
||||
</el-empty>
|
||||
<el-form-item v-for="(item, index) in data.formFieldPerms" v-else
|
||||
:label="item.label"
|
||||
:key="index">
|
||||
<el-input style="width: 131px; margin-right: 10px" v-model="item.label" v-if="props.isShowAdd"></el-input>
|
||||
<el-input style="width: 131px; margin-right: 10px" v-model="item.prop" v-if="props.isShowAdd"></el-input>
|
||||
<el-radio-group v-model="item.permType">
|
||||
<el-radio v-for="(item, index) in DIC_PROP.FORM_PERM_TYPE" :key="index"
|
||||
:disabled="props.currSelect.attributes.attrs.cdata.attrs.formPermType === item.value"
|
||||
:label="item.value" style="width: 86px">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-button @click.prevent="methods.removeFormPermission(item.prop)" type="primary" size="small" round>
|
||||
删除
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowFormPerm">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {parseWithFunctions, validateRunFlow} from "../../index";
|
||||
import {buildFieldPerms, handleFormFieldPerms} from "../../utils/form-perm";
|
||||
import {CommonNodeType, HighNodeType} from "../config/type";
|
||||
import {listFormOption} from "/@/api/jsonflow/form-option";
|
||||
import {DIC_PROP} from "../../support/dict-prop";
|
||||
import {deepClone} from "/@/utils/other";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
formIds: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
isShowAdd: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const data = reactive({
|
||||
formFieldPerms: [],
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
methods.changeTabPane(props.currSelect)
|
||||
})
|
||||
|
||||
const methods = {
|
||||
validateCurrSelectAttrs(currSelect?) {
|
||||
if (!currSelect) currSelect = props.currSelect;
|
||||
if (validateNull(currSelect.attributes)) return false
|
||||
return true
|
||||
},
|
||||
validateNode(currSelect) {
|
||||
if (!methods.validateCurrSelectAttrs()) return false;
|
||||
let type = currSelect.attributes.attrs.cdata.type;
|
||||
return type === CommonNodeType.START || type === CommonNodeType.END || type === CommonNodeType.SERIAL || type === CommonNodeType.PARALLEL || type === HighNodeType.VIRTUAL
|
||||
},
|
||||
filterNodeFormId(item) {
|
||||
let pcTodoUrl = props.currSelect.attributes.attrs.cdata.attrs.pcTodoUrl
|
||||
if (!validateNull(pcTodoUrl)) {
|
||||
return pcTodoUrl.includes(item.id)
|
||||
} else return false
|
||||
},
|
||||
changeNodeFormId(value) {
|
||||
if (!methods.validateNode(props.currSelect)) return;
|
||||
if (!value) {
|
||||
methods.clearPermData()
|
||||
return
|
||||
}
|
||||
data.formFieldPerms = []
|
||||
let find = props.formIds.find(f => f.id === value);
|
||||
if (validateNull(find.formInfo)) {
|
||||
methods.handleFormFieldPerms(find)
|
||||
} else {
|
||||
let formInfo = parseWithFunctions(find.formInfo, true)
|
||||
buildFieldPerms(data.formFieldPerms, formInfo.widgetList);
|
||||
}
|
||||
methods.setNodeAttrsFormFieldPerms()
|
||||
},
|
||||
handleFormFieldPerms(find) {
|
||||
// 无需前缀
|
||||
let isReturn = handleFormFieldPerms(data, $message, find, '');
|
||||
if (isReturn) return
|
||||
if (find.isCurrForm === '1' && !validateNull(find.formFieldPerms)) {
|
||||
methods.buildCustomFormPerm(find.formFieldPerms)
|
||||
return;
|
||||
}
|
||||
// 已配置或全部字段
|
||||
methods.handleCustomFormPerm(find.id, null, props.flowData.attrs.id , props.currSelect.id)
|
||||
},
|
||||
initNodeFormId() {
|
||||
if (Object.keys(props.currSelect).length === 0) return
|
||||
if (!methods.validateNode(props.currSelect)) return;
|
||||
let formId = props.currSelect.attributes.attrs.cdata.attrs.formId;
|
||||
if (!formId) {
|
||||
methods.clearPermData()
|
||||
return
|
||||
}
|
||||
// formId必存在权限
|
||||
data.formFieldPerms = props.currSelect.attributes.attrs.cdata.attrs.formFieldPerms;
|
||||
methods.initAddFormPermission(formId)
|
||||
},
|
||||
async initAddFormPermission(formId) {
|
||||
let find = props.formIds.find(f => f.id === formId);
|
||||
if (!find) return
|
||||
let formFieldPerms = []
|
||||
if (find.type === DIC_PROP.FORM_TYPE[1].value) {
|
||||
if (find.isCurrForm === '1') {
|
||||
formFieldPerms = find.formFieldPerms
|
||||
} else {
|
||||
formFieldPerms = await methods.reqCustomFormPerm(formId, DIC_PROP.FORM_DATA_TYPE[0].value, null, null)
|
||||
}
|
||||
}
|
||||
if (find.type !== DIC_PROP.FORM_TYPE[1].value) {
|
||||
if (!validateNull(find.formInfo)) {
|
||||
let formInfo = parseWithFunctions(find.formInfo, true)
|
||||
buildFieldPerms(formFieldPerms, formInfo.widgetList);
|
||||
}
|
||||
}
|
||||
if (validateNull(formFieldPerms)) return
|
||||
formFieldPerms.forEach(each => {
|
||||
let index = data.formFieldPerms.findIndex(f => f.propId ? each.propId === f.propId : each.prop === f.prop);
|
||||
if (index !== -1) {
|
||||
let exist = data.formFieldPerms[index]
|
||||
data.formFieldPerms.splice(index, 1);
|
||||
each.permType = exist.permType
|
||||
data.formFieldPerms.splice(index, 0, each);
|
||||
return
|
||||
}
|
||||
data.formFieldPerms.push(each)
|
||||
})
|
||||
},
|
||||
removeFormPermission(prop) {
|
||||
if (data.formFieldPerms.length === 0) return
|
||||
data.formFieldPerms = data.formFieldPerms.filter(f => f.prop !== prop)
|
||||
methods.setNodeAttrsFormFieldPerms()
|
||||
},
|
||||
setNodeAttrsFormFieldPerms() {
|
||||
// 相同引用
|
||||
props.currSelect.attributes.attrs.cdata.attrs.formFieldPerms = data.formFieldPerms
|
||||
},
|
||||
addFormPermission() {
|
||||
let formId = props.currSelect.attributes.attrs.cdata.attrs.formId;
|
||||
if (!formId) {
|
||||
$message.warning("请先选择表单名称")
|
||||
return
|
||||
}
|
||||
if (!data.formFieldPerms) data.formFieldPerms = []
|
||||
let number = data.formFieldPerms.length + 1;
|
||||
data.formFieldPerms.unshift({
|
||||
prop: 'propName' + number,
|
||||
label: '请输入字段名称'
|
||||
})
|
||||
methods.setNodeAttrsFormFieldPerms()
|
||||
},
|
||||
async reqCustomFormPerm(formId, type, defFlowId, flowNodeId) {
|
||||
if (!type) type = DIC_PROP.FORM_DATA_TYPE[1].value
|
||||
// 判断流程实例独立配置
|
||||
let flowInstId = validateRunFlow(props);
|
||||
let resp = await listFormOption({
|
||||
type: type, formType: DIC_PROP.FORM_TYPE[1].value, formId: formId,
|
||||
flowInstId: flowInstId, defFlowId: defFlowId, flowNodeId: flowNodeId
|
||||
}).catch(() => {
|
||||
$message.error("获取系统表单字段权限失败");
|
||||
})
|
||||
return resp.data
|
||||
},
|
||||
async handleCustomFormPerm(formId, type, defFlowId, flowNodeId) {
|
||||
let formFieldPerms = await methods.reqCustomFormPerm(formId, type, defFlowId, flowNodeId)
|
||||
methods.buildCustomFormPerm(formFieldPerms)
|
||||
},
|
||||
buildCustomFormPerm(formFieldPerms) {
|
||||
if (!validateNull(formFieldPerms)) {
|
||||
// 不影响表单设计信息
|
||||
data.formFieldPerms = deepClone(formFieldPerms)
|
||||
methods.setNodeAttrsFormFieldPerms()
|
||||
} else {
|
||||
methods.clearPermData()
|
||||
$message.warning("当前选择的系统表单无字段信息,请先在表单设计中录入")
|
||||
}
|
||||
},
|
||||
resetFormPerm(){
|
||||
let formId = props.currSelect.attributes.attrs.cdata.attrs.formId;
|
||||
if (!formId) {
|
||||
$message.warning("请先选择表单名称")
|
||||
return
|
||||
}
|
||||
methods.clearPermData()
|
||||
let find = props.formIds.find(f => f.id === formId);
|
||||
if (find.type === DIC_PROP.FORM_TYPE[1].value) {
|
||||
if (find.isCurrForm === '1' && !validateNull(find.formFieldPerms)) {
|
||||
methods.buildCustomFormPerm(find.formFieldPerms)
|
||||
} else {
|
||||
methods.handleCustomFormPerm(formId, DIC_PROP.FORM_DATA_TYPE[0].value, null, null)
|
||||
}
|
||||
} else {
|
||||
methods.changeNodeFormId(formId)
|
||||
}
|
||||
},
|
||||
clearPermData() {
|
||||
data.formFieldPerms = []
|
||||
delete props.currSelect.attributes.attrs.cdata.attrs.formFieldPerms
|
||||
},
|
||||
changeTabPane(val) {
|
||||
methods.initNodeFormId()
|
||||
}
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.currSelect,
|
||||
(val) => {
|
||||
if (Object.keys(val).length === 0) {
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
352
src/flow/designer/components/flow-http-param.vue
Normal file
352
src/flow/designer/components/flow-http-param.vue
Normal file
@@ -0,0 +1,352 @@
|
||||
<template>
|
||||
|
||||
<el-divider>请求头</el-divider>
|
||||
<el-table :data="data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value)"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" :label="t('jfI18n.operate')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle
|
||||
@click="methods.onAddItem(DIC_PROP.PARAM_FROM[0].value, true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleHttpUrlDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="targetProp" :label="t('jfAttr.requestHeader')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.targetProp" :placeholder="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value ? scope.row.varKeyVal : null"
|
||||
clearable></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="paramValType" :label="t('jfAttr.paramValType')" width="145px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.paramValType" clearable>
|
||||
<el-option v-for="(item, index) in DIC_PROP.PARAM_VAL_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('jfAttr.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal"
|
||||
v-if="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value"
|
||||
clearable filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
|
||||
<el-input v-else v-model="scope.row.varKeyVal" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<el-divider>请求参数</el-divider>
|
||||
|
||||
<el-form-item label="参数类型 :">
|
||||
<el-radio-group v-model="data.paramType">
|
||||
<el-radio v-for="(item, index) in DIC_PROP.PARAM_TYPES" :key="index" :label="item.value"
|
||||
style="width: 56px" @change="methods.handleParamType">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content> 表示以指定的【参数类型】传递【请求参数】 </template>
|
||||
<el-icon style="margin-left: 20px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value)"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" :label="t('jfI18n.operate')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle
|
||||
@click="methods.onAddItem(DIC_PROP.PARAM_FROM[1].value, true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleHttpUrlDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="targetProp" :label="t('jfAttr.requestParam')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.targetProp" :placeholder="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value ? scope.row.varKeyVal : null"
|
||||
clearable></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="paramValType" :label="t('jfAttr.paramValType')" width="145px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.paramValType" clearable>
|
||||
<el-option v-for="(item, index) in DIC_PROP.PARAM_VAL_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('jfAttr.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal"
|
||||
v-if="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value"
|
||||
clearable filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
|
||||
<el-input v-else v-model="scope.row.varKeyVal" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<el-divider>返回值</el-divider>
|
||||
|
||||
<div v-if="props.httpParamType === DIC_PROP.PARAM_RULE_TYPE[0].value" style="margin: 10px 13px">
|
||||
<span style="color: #409EFF;font-size: 14px">注: 当前Http请求的返回值可以为对象 或 数组,{{ PROP_CONST.TEXT_DESC.condMethodExplain5 }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="props.httpParamType === DIC_PROP.PARAM_RULE_TYPE[8].value" style="margin: 10px 13px">
|
||||
<span style="color: #409EFF;font-size: 14px">注: 当前Http请求的返回值可以为对象 或 数组,{{ PROP_CONST.TEXT_DESC.condMethodExplain6 }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="props.httpParamType === DIC_PROP.PARAM_RULE_TYPE[1].value" style="margin: 10px 13px">
|
||||
<span style="color: #409EFF;font-size: 14px">注: 当前Http请求的返回值为字符串 1 ( 满足 ) 或 0 ( 不满足 )</span>
|
||||
</div>
|
||||
|
||||
<el-table :data="data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[2].value)"
|
||||
v-if="props.httpParamType !== DIC_PROP.PARAM_RULE_TYPE[0].value && props.httpParamType !== DIC_PROP.PARAM_RULE_TYPE[1].value
|
||||
&& props.httpParamType !== DIC_PROP.PARAM_RULE_TYPE[8].value"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" :label="t('jfI18n.operate')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle
|
||||
@click="methods.onAddItem(DIC_PROP.PARAM_FROM[2].value, true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleHttpUrlDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="targetProp" :label="t('jfAttr.returnParam')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.targetProp"
|
||||
:placeholder="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value ? scope.row.varKeyVal : null"
|
||||
clearable></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="paramValType" :label="t('jfAttr.paramValType')" width="145px">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.paramValType"
|
||||
:active-value="DIC_PROP.PARAM_VAL_TYPE[0].value"
|
||||
:active-text="DIC_PROP.PARAM_VAL_TYPE[0].label"
|
||||
:inactive-value="DIC_PROP.PARAM_VAL_TYPE[2].value"
|
||||
:inactive-text="DIC_PROP.PARAM_VAL_TYPE[2].label"
|
||||
inline-prompt>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal"
|
||||
clearable filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowHttpParam">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {buildSysFieldsFormOption} from "../../utils/form-perm";
|
||||
import {DIC_PROP} from "../../support/dict-prop";
|
||||
|
||||
const {proxy} = getCurrentInstance();
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
httpParam: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
httpParamType: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const data = reactive({
|
||||
allFieldPerms: [],
|
||||
formFieldPerms: [],
|
||||
httpParams: [],
|
||||
paramType: '0',
|
||||
})
|
||||
|
||||
// 定义字典
|
||||
onMounted(async () => {
|
||||
methods.changeTabPane(props.httpParam)
|
||||
})
|
||||
|
||||
const methods = {
|
||||
initParamType() {
|
||||
let find = data.httpParams.find(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value);
|
||||
if (find) data.paramType = find.paramType
|
||||
},
|
||||
handleParamType(val) {
|
||||
let splice = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value);
|
||||
splice.forEach(each => each.paramType = val)
|
||||
let res = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value);
|
||||
let res2 = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[2].value);
|
||||
splice.push(...res)
|
||||
splice.push(...res2)
|
||||
data.httpParams = splice
|
||||
methods.changeHttpUrlParams()
|
||||
},
|
||||
listFormFieldPerms() {
|
||||
if (validateNull(data.formFieldPerms)) {
|
||||
buildSysFieldsFormOption(data, props, $message)
|
||||
}
|
||||
},
|
||||
onAddItem(paramFrom, isAdd) {
|
||||
methods.listFormFieldPerms()
|
||||
let value = DIC_PROP.PARAM_VAL_TYPE[0].value;
|
||||
if (data.httpParams.length > 0) {
|
||||
let find = data.httpParams.filter(f => f.paramFrom === paramFrom).find(f => !f.varKeyVal || (f.paramValType !== value && !f.targetProp));
|
||||
if (find) {
|
||||
if (isAdd) {
|
||||
if (!find.varKeyVal) {
|
||||
$message.warning("请先填写 表单字段")
|
||||
return
|
||||
}
|
||||
if (find.paramValType !== value && !find.targetProp) {
|
||||
if (DIC_PROP.PARAM_FROM[0].value === paramFrom) {
|
||||
$message.warning("请先填写 请求头")
|
||||
} else if (DIC_PROP.PARAM_FROM[1].value === paramFrom) {
|
||||
$message.warning("请先填写 请求参数")
|
||||
} else {
|
||||
$message.warning("请先填写 返回值")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isAdd) data.httpParams.splice(0, data.httpParams.length);
|
||||
}
|
||||
let obj = {paramFrom: paramFrom, varKeyVal: null, paramValType: value, targetProp: null};
|
||||
if (paramFrom === DIC_PROP.PARAM_FROM[1].value) {
|
||||
obj.paramType = data.paramType
|
||||
}
|
||||
data.httpParams.push(obj);
|
||||
methods.changeHttpUrlParams()
|
||||
},
|
||||
handleHttpUrlDelete(index: number, row: any) {
|
||||
let splice = data.httpParams.filter(f => f.paramFrom === row.paramFrom);
|
||||
splice.splice(index, 1);
|
||||
if (DIC_PROP.PARAM_FROM[0].value === row.paramFrom) {
|
||||
let res = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value);
|
||||
let res2 = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[2].value);
|
||||
splice.push(...res)
|
||||
splice.push(...res2)
|
||||
} else if (DIC_PROP.PARAM_FROM[1].value === row.paramFrom) {
|
||||
let res = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value);
|
||||
let res2 = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[2].value);
|
||||
splice.push(...res)
|
||||
splice.push(...res2)
|
||||
} else if (DIC_PROP.PARAM_FROM[2].value === row.paramFrom) {
|
||||
let res = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value);
|
||||
let res2 = data.httpParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value);
|
||||
splice.push(...res)
|
||||
splice.push(...res2)
|
||||
}
|
||||
data.httpParams = splice
|
||||
methods.changeHttpUrlParams()
|
||||
},
|
||||
validateHttpUrlData() {
|
||||
// 兼容老版本
|
||||
let httpParams = props.httpParam.httpParams;
|
||||
if (!httpParams) {
|
||||
props.httpParam.httpParams = []
|
||||
}
|
||||
data.httpParams = props.httpParam.httpParams
|
||||
},
|
||||
changeHttpUrlParams() {
|
||||
props.httpParam.httpParams = data.httpParams
|
||||
},
|
||||
changeTabPane(val) {
|
||||
methods.validateHttpUrlData()
|
||||
methods.listFormFieldPerms()
|
||||
methods.initParamType()
|
||||
}
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.httpParam,
|
||||
(val) => {
|
||||
if (Object.keys(val).length === 0) {
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
360
src/flow/designer/components/flow-method.vue
Normal file
360
src/flow/designer/components/flow-method.vue
Normal file
@@ -0,0 +1,360 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs class="flow-attr"
|
||||
v-model="data.activeKey">
|
||||
<el-tab-pane name="flow-method">
|
||||
<template #label>
|
||||
<div>
|
||||
<el-icon style="vertical-align: middle;margin-right: 3px">
|
||||
<User/>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle;">选择审批对象</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="170px">
|
||||
|
||||
<div style="margin: 5px 20px">
|
||||
<span style="color: red;font-size: 14px">注: 当前审批对象可自定义任意扩展(只需写好接口即可), 满足您分配参与者复杂的场景</span>
|
||||
</div>
|
||||
|
||||
<el-divider> 审批对象设置 </el-divider>
|
||||
|
||||
<el-form-item label="审批对象类型">
|
||||
<el-radio-group style="width: 283px" @change="methods.handleUserKeyValFrom"
|
||||
v-model="data.userKeyValFrom">
|
||||
<el-radio v-for="(item, index) in DIC_PROP.FLOW_METHOD_TYPE" :key="index" :label="item.value"
|
||||
:disabled="item.value === '-1'">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="data.userKeyValFrom === '0'">
|
||||
<div style="margin-left: 15px">※ 发起人本人将作为审批人</div>
|
||||
</template>
|
||||
|
||||
<template v-if="data.userKeyValFrom === '1'">
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="谁的主管">
|
||||
<el-tooltip content="请输入用户名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.whoseLeader" @change="methods.changeWhoseLeader"
|
||||
clearable filterable
|
||||
remote :remote-method="remoteMethod" :reserve-keyword="false">
|
||||
<template v-for="(item, index) in dicData.users" :key="index">
|
||||
<el-option :label="item.name"
|
||||
:value="item.userId">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="用于指定哪个用户的部门主管">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="指定主管">
|
||||
<div>
|
||||
<span><{{ data.whoseLeaderName }} 用户>的第  </span>
|
||||
<el-input-number :min="1" :max="20" :step="1" style="width: 150px"
|
||||
v-model="data.leaderLevel"></el-input-number>
|
||||
<span>  级主管</span>
|
||||
<div style="color: #409EFF; font-size: small;">👉 指定主管为 第 {{ data.leaderLevel }} 级主管</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="提取规则">
|
||||
<el-radio-group style="width: 283px"
|
||||
v-model="data.levelExtract">
|
||||
<el-radio v-for="(item, index) in EXTRACTS.SINGLE_EXTRACT" :key="index" :label="item.value">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="data.userKeyValFrom === '2'">
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="谁的主管">
|
||||
<el-tooltip content="请输入用户名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.whoseLeader" @change="methods.changeWhoseLeader"
|
||||
clearable filterable
|
||||
remote :remote-method="remoteMethod" :reserve-keyword="false">
|
||||
<template v-for="(item, index) in dicData.users" :key="index">
|
||||
<el-option :label="item.name"
|
||||
:value="item.userId">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="用于指定哪个用户的部门主管">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="审批终点">
|
||||
<el-radio-group style="width: 200px" v-model="data.auditEndpoint">
|
||||
<el-radio label="0">直到最上层主管</el-radio>
|
||||
<el-radio label="1">不超过<{{ data.whoseLeaderName }} 用户>的</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="audit-endpoint">
|
||||
第 <el-input-number :min="1" :max="20" :step="1" style="width: 80px" controls-position="right"
|
||||
v-model="data.leaderLevel"></el-input-number> 级主管
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="依次审批顺序">
|
||||
<el-tooltip content="当节点属性【多人审批方式】为依次审批时,审批顺序由选择的顺序决定" placement="bottom">
|
||||
<el-radio-group style="width: 200px" v-model="data.seqAuditSort">
|
||||
<el-radio label="0">下级到上级</el-radio>
|
||||
<el-radio label="1">上级到下级</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tooltip>
|
||||
|
||||
<el-button v-if="data.seqAuditSort" text type="primary" icon="delete" @click="data.seqAuditSort = null">
|
||||
清空
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="提取规则">
|
||||
<el-radio-group style="width: 283px"
|
||||
v-model="data.levelExtract">
|
||||
<el-radio v-for="(item, index) in EXTRACTS.MULTI_EXTRACT" :key="index" :label="item.value">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-tooltip placement="top" content="必须保证最终至少存在一个主管">
|
||||
<el-icon class="audit-endpoint-extract"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="data.userKeyValFrom === '3'">
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="哪个部门">
|
||||
<el-tooltip content="请输入部门名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.appointDeptId"
|
||||
clearable filterable
|
||||
remote :remote-method="remoteMethodDept" :reserve-keyword="false">
|
||||
<template v-for="(item, index) in dicData.depts" :key="index">
|
||||
<el-option :label="item.name"
|
||||
:value="item.deptId">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="用于指定哪个部门的主管">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="提取规则">
|
||||
<el-radio-group style="width: 283px"
|
||||
v-model="data.levelExtract">
|
||||
<el-radio v-for="(item, index) in EXTRACTS.DEPT_EXTRACT" :key="index" :label="item.value">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template v-if="data.userKeyValFrom === '4'">
|
||||
<el-divider> </el-divider>
|
||||
<el-form-item label="表单字段">
|
||||
<el-select v-model="data.userKeyVal"
|
||||
clearable
|
||||
filterable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.formFieldPerms"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<el-button
|
||||
type="primary" round style="margin-left: 185px; margin-top: 50px; width: 200px"
|
||||
@click="methods.confirmMethods">
|
||||
确定
|
||||
</el-button>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="flow-rule">
|
||||
<template #label>
|
||||
<div>
|
||||
<el-icon style="vertical-align: middle;margin-right: 3px">
|
||||
<Setting/>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle;">设置审批规则</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="150px">
|
||||
<flow-user-rule :currSelect="props.currSelect" :currFlowForm="props.currFlowForm" :flowData="props.flowData"></flow-user-rule>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane name="flow-curr-job" v-if="methods.validateNodeJobCurrJob()">
|
||||
<template #label>
|
||||
<div>
|
||||
<el-icon style="vertical-align: middle;margin-right: 3px">
|
||||
<Setting/>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle;">节点参与者列表</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="150px">
|
||||
<flow-curr-job :currSelect="props.currSelect"></flow-curr-job>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowMethod">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {onFormLoadedUrl, onLoadDicUrl, remoteMethodByKey} from "/@/flow/components/convert-name/convert";
|
||||
import {validateListFormOption} from "../../utils/form-perm";
|
||||
import {parseUserKeyValName, revParseUserKeyValName, revParseWhoseLeaderName} from "./index";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const FlowUserRule = defineAsyncComponent(() => import('./flow-user-rule.vue'));
|
||||
const FlowCurrJob = defineAsyncComponent(() => import('./flow-curr-job.vue'));
|
||||
const $emit = defineEmits(["openFlowMethods"]);
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const EXTRACTS = {
|
||||
SINGLE_EXTRACT: [{
|
||||
label: '无主管时由上级主管代审批',
|
||||
value: '0'
|
||||
}, {
|
||||
label: '无主管时[报错]处理',
|
||||
value: '1'
|
||||
}],
|
||||
MULTI_EXTRACT: [{
|
||||
label: '无主管时由上级主管代审批,直到满足等级的人数',
|
||||
value: '0'
|
||||
}, {
|
||||
label: '无主管时[按空]处理',
|
||||
value: '1'
|
||||
}],
|
||||
DEPT_EXTRACT: [{
|
||||
label: '无主管时由上级主管代审批',
|
||||
value: '0'
|
||||
}, {
|
||||
label: '无主管时[报错]处理',
|
||||
value: '1'
|
||||
}],
|
||||
}
|
||||
const data = reactive({
|
||||
activeKey: 'flow-method',
|
||||
formFieldPerms: [],
|
||||
userKeyValFrom: '1',
|
||||
whoseLeader: null,
|
||||
whoseLeaderName: '请先指定',
|
||||
leaderLevel: 1,
|
||||
auditEndpoint: '0',
|
||||
seqAuditSort: null,
|
||||
levelExtract: '0',
|
||||
appointDeptId: null,
|
||||
userKeyVal: null,
|
||||
})
|
||||
|
||||
// 定义字典
|
||||
const dicData = reactive({});
|
||||
const onLoad = onLoadDicUrl();
|
||||
const onFormLoaded = onFormLoadedUrl({key: "users", field: "whoseLeader"}, {key: "depts", field: "appointDeptId"});
|
||||
onMounted(async () => {
|
||||
// await onLoad(dicData);
|
||||
|
||||
methods.changeTabPane(props.currSelect)
|
||||
})
|
||||
|
||||
function remoteMethodDept(query: string) {
|
||||
remoteMethodByKey(query, onLoad, dicData, 'deptName', "depts")
|
||||
}
|
||||
|
||||
async function remoteMethod(query: string) {
|
||||
await remoteMethodByKey(query, onLoad, dicData, 'userName', "users")
|
||||
revParseWhoseLeaderName(data, dicData)
|
||||
}
|
||||
|
||||
const methods = {
|
||||
handleUserKeyValFrom(type) {
|
||||
if (type !== '4' || !validateNull(data.formFieldPerms)) return
|
||||
validateListFormOption(data, props, $message)
|
||||
},
|
||||
confirmMethods() {
|
||||
parseUserKeyValName(props, data, methods)
|
||||
$emit("openFlowMethods", false);
|
||||
},
|
||||
$message(type) {
|
||||
if (type === 'whoseLeader') $message.warning('请选择谁的主管');
|
||||
if (type === 'appointDeptId') $message.warning('请选择指定部门');
|
||||
},
|
||||
changeWhoseLeader(userId) {
|
||||
if (!userId) {
|
||||
data.whoseLeaderName = '请先指定'
|
||||
return
|
||||
}
|
||||
data.whoseLeaderName = dicData.users.find(f => f.userId === userId).name;
|
||||
},
|
||||
validateNodeJobCurrJob() {
|
||||
return !validateNull(props.currSelect.attributes) && props.currSelect.attributes.attrs.cdata.defJob
|
||||
&& !validateNull(props.currSelect.attributes.attrs.cdata.defJob.currRunJobs);
|
||||
},
|
||||
async changeTabPane(val) {
|
||||
if (Object.keys(val).length === 0) {
|
||||
data.activeKey = ''
|
||||
return
|
||||
}
|
||||
// 反解析出已配置项
|
||||
await revParseUserKeyValName(props, data, dicData, methods)
|
||||
await onFormLoaded(dicData, data)
|
||||
revParseWhoseLeaderName(data, dicData)
|
||||
},
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.currSelect,
|
||||
(val) => {
|
||||
if (validateNull(val) || Object.keys(val).length === 0) {
|
||||
data.activeKey = ''
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
810
src/flow/designer/components/flow-node-route.vue
Normal file
810
src/flow/designer/components/flow-node-route.vue
Normal file
@@ -0,0 +1,810 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-tabs class="flow-attr"
|
||||
v-model="data.activeKey">
|
||||
<el-tab-pane name="flow-rule">
|
||||
<template #label>
|
||||
<div>
|
||||
<el-icon style="vertical-align: middle;margin-right: 3px">
|
||||
<Setting/>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle;">设置路由规则</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form label-position="left" class="flow-config-attr" label-width="150px">
|
||||
<div style="margin: 5px 15px"><span
|
||||
style="color: red;font-size: 14px">注:可根据接口返回值 或 表单数据的字段值,配置对应的路由动作(可自定义随意扩展)</span>
|
||||
</div>
|
||||
<el-form-item label="条件组关系">
|
||||
<el-switch
|
||||
v-model="data.cond.groupsType" @change="methods.changeGroupsType"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且" disabled>
|
||||
</el-switch>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>一个组决定一个路由动作。多条件组满足时只有【开启下一节点】和【驳回到其他节点】可以累加路由动作</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="路由规则模式">
|
||||
<el-radio-group style="width: 313px" @change="methods.handleCondValType" :disabled="data.existData"
|
||||
v-model="data.cond.valType">
|
||||
<el-radio v-for="(item, index) in [DIC_PROP.VAL_TYPE[2], DIC_PROP.VAL_TYPE[4], DIC_PROP.VAL_TYPE[5]]" :key="index" :label="item.value"
|
||||
style="width: 75px">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>若无法切换模式,请先清空条件组列表</template>
|
||||
<el-icon>
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider>组内条件配置</el-divider>
|
||||
|
||||
<template v-if="data.cond.valType === '0'">
|
||||
<el-form-item label="组内条件关系">
|
||||
<el-switch
|
||||
v-model="data.cond.groupType"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="data.cond.condGroup"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" label="操作" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="methods.onAddItem(true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle @click="methods.handleCondDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal" @change="methods.handleVarKeyVal(scope.row)"
|
||||
clearable
|
||||
filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.operator" @change="methods.handleVarKeyVal(scope.row)"
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.varValOperator"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.varVal" clearable/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-form-item label="路由动作">
|
||||
<el-select v-model="data.cond.routeAction" @change="methods.changeRouteAction(data.cond)">
|
||||
<el-option v-for="(item, index) in DIC_PROP.ROUTE_ACTIONS" :key="index" :disabled="item.value.indexOf('_define_') !== -1"
|
||||
:label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="路由到哪个节点" v-if="data.cond.routeAction === DIC_PROP.ROUTE_ACTIONS[1].value">
|
||||
<el-select class="input-attr" v-model="data.cond.toFlowNodeId"
|
||||
clearable filterable>
|
||||
<template v-for="(item, index) in data.toFlowNodeIds" :key="index">
|
||||
<el-option :label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
|
||||
<el-tooltip placement="top" content="组内条件满足时,路由到哪个节点(注意:若节点参与者为空,可指定默认的参与者)">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="data.cond.routeAction === DIC_PROP.ROUTE_ACTIONS[1].value">
|
||||
<el-form-item label="参与者类型">
|
||||
<el-tooltip placement="top" content="若节点参与者为空,可指定默认的参与者">
|
||||
<el-select v-model="data.cond.jobType" @change="methods.changeJobType(data.cond)" clearable>
|
||||
<el-option v-for="(item, index) in DIC_PROP.JOB_USER_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个人来审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[0].value">
|
||||
<el-tooltip content="请输入用户名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.cond.roleId"
|
||||
clearable filterable
|
||||
remote :remote-method="methodsRemote.remoteMethodUser2" :reserve-keyword="false">
|
||||
<template v-for="(item, index) in dicData.users2" :key="index">
|
||||
<el-option :label="item.name"
|
||||
:value="item.userId">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个人来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个角色审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[1].value">
|
||||
<el-tooltip content="请输入角色名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="data.cond.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodRole2" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.roles2"
|
||||
:key="index"
|
||||
:label="item.roleName"
|
||||
:value="item.roleId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个角色来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个岗位审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[2].value">
|
||||
<el-tooltip content="请输入岗位名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="data.cond.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodPost2" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.posts2"
|
||||
:key="index"
|
||||
:label="item.postName"
|
||||
:value="item.postId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个岗位来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个部门审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[3].value">
|
||||
<el-tooltip content="请输入部门名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="data.cond.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodDept2" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.depts2"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="item.deptId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个部门审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<el-form-item label="驳回到哪个节点" v-if="data.cond.routeAction === DIC_PROP.ROUTE_ACTIONS[3].value">
|
||||
<el-select class="input-attr" v-model="data.cond.toFlowNodeId"
|
||||
clearable filterable>
|
||||
<template v-for="(item, index) in data.toFlowNodeIds" :key="index">
|
||||
<el-option :label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
|
||||
<el-tooltip placement="top" content="组内条件满足时,驳回到哪个节点(注意:必须是已审批过的节点)">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
|
||||
<el-form-item label="函数表达式" v-if="data.cond.valType === '2'">
|
||||
<el-input class="input-attr" v-model="data.cond.varKeyVal" placeholder="请输入函数表达式" clearable @blur="methods.handleCondVarKeyVal"/>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content>采用表达式取值 ( 以下两种方式均支持自定义任意扩展 ), 值可以为对象 或 数组, 满足您复杂路由的场景:
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condUserExplain }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain3 }}, 返回值可以为对象 或 数组,{{ PROP_CONST.TEXT_DESC.condMethodExplain6 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain4 }}
|
||||
</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<div v-if="data.cond.valType === '2'" style="margin: 10px 13px">
|
||||
<span style="color: #409EFF;font-size: 14px">注: 当前函数表达式的返回值可以为对象 或 数组,{{ PROP_CONST.TEXT_DESC.condMethodExplain6 }}</span>
|
||||
</div>
|
||||
|
||||
<template v-if="data.cond.valType === '3'">
|
||||
<el-form-item label="Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="data.cond.varKeyVal"
|
||||
@blur="methods.handleCondVarKeyVal" clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="data.cond.httpMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip content="点击可设置Http请求的参数信息" placement="bottom">
|
||||
<el-button type="primary" size="small" round style="margin-left: 10px"
|
||||
@click="methods.openHttpUrlParams()">
|
||||
{{ data.httpUrlParamsVisible ? '清空' : '参数' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<flow-http-param ref="flowHttpParam" :currFlowForm="props.currFlowForm" :flowData="props.flowData"
|
||||
:httpParam="props.currSelect.attributes.attrs.cdata.attrs"
|
||||
:httpParamType="DIC_PROP.PARAM_RULE_TYPE[8].value"
|
||||
v-if="data.httpUrlParamsVisible"></flow-http-param>
|
||||
</template>
|
||||
|
||||
<template v-if="data.cond.valType === '0'">
|
||||
<el-button type="primary" round style="margin-left: 185px; margin-top: 30px; margin-bottom: 30px; width: 200px" @click="methods.addFlowNodeCondGroup()">
|
||||
{{ data.oldCurrentRow ? '修改完成': '添加条件组' }}
|
||||
</el-button>
|
||||
<el-divider>已添加条件组列表(点击行可再次修改)</el-divider>
|
||||
<el-empty description="条件组列表为空" style="margin: 10px 230px" v-if="!data.existData">
|
||||
</el-empty>
|
||||
|
||||
<template v-for="(item, index) in data.condGroups" v-else
|
||||
:key="index">
|
||||
|
||||
<el-collapse v-model="data.collapse">
|
||||
<el-collapse-item :name="index">
|
||||
<template #title>
|
||||
{{ '条件组 ' + (index + 1) }}
|
||||
|
||||
<el-icon style="margin-left: 10px" @click="methods.handleCondGroupDelete(index)">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</template>
|
||||
|
||||
<el-form-item label="组内条件关系">
|
||||
<el-switch
|
||||
v-model="item.groupType" @change="methods.changeGroupType(item, index)"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="item.condGroup" border style="width: 100%; margin-bottom: 10px" max-height="500"
|
||||
highlight-current-row @current-change="methods.handleCurrentChange" :ref="'tableDataRef' + index">
|
||||
|
||||
<el-table-column type="index" label="操作" width="80">
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleSingleCondDelete(scope.$index, scope.row, index)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<convert-group-name :options="data.allFieldPerms"
|
||||
:value="scope.row.varKeyVal"
|
||||
:valueKey="'prop'" :showKey="'label'"></convert-group-name>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="DIC_PROP.OPERATOR" :value="scope.row.operator"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
|
||||
<el-form-item label="路由动作">
|
||||
<el-select v-model="item.routeAction" @change="methods.changeRouteAction(item)">
|
||||
<el-option v-for="(item, index) in DIC_PROP.ROUTE_ACTIONS" :key="index" :disabled="item.value.indexOf('_define_') !== -1"
|
||||
:label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="路由到哪个节点" v-if="item.routeAction === DIC_PROP.ROUTE_ACTIONS[1].value">
|
||||
<el-select class="input-attr" v-model="item.toFlowNodeId"
|
||||
clearable filterable>
|
||||
<template v-for="(item, index) in data.toFlowNodeIds" :key="index">
|
||||
<el-option :label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
|
||||
<el-tooltip placement="top" content="组内条件满足时,路由到哪个节点(注意:若节点参与者为空,可指定默认的参与者)">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="item.routeAction === DIC_PROP.ROUTE_ACTIONS[1].value">
|
||||
<el-form-item label="参与者类型">
|
||||
<el-tooltip placement="top" content="若节点参与者为空,可指定默认的参与者">
|
||||
<el-select v-model="item.jobType" @change="methods.changeJobType(item)" clearable>
|
||||
<el-option v-for="(item, index) in DIC_PROP.JOB_USER_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个人来审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[0].value">
|
||||
<el-tooltip content="请输入用户名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr"
|
||||
v-model="item.roleId"
|
||||
clearable filterable
|
||||
remote :remote-method="methodsRemote.remoteMethodUser" :reserve-keyword="false">
|
||||
<template v-for="(item, index) in dicData.users" :key="index">
|
||||
<el-option :label="item.name"
|
||||
:value="item.userId">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个人来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个角色审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[1].value">
|
||||
<el-tooltip content="请输入角色名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="item.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodRole" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.roles"
|
||||
:key="index"
|
||||
:label="item.roleName"
|
||||
:value="item.roleId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个角色来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个岗位审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[2].value">
|
||||
<el-tooltip content="请输入岗位名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="item.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodPost" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.posts"
|
||||
:key="index"
|
||||
:label="item.postName"
|
||||
:value="item.postId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个岗位来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个部门审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[3].value">
|
||||
<el-tooltip content="请输入部门名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="item.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodDept" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.depts"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="item.deptId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个部门审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<el-form-item label="驳回到哪个节点" v-if="item.routeAction === DIC_PROP.ROUTE_ACTIONS[3].value">
|
||||
<el-select class="input-attr" v-model="item.toFlowNodeId"
|
||||
clearable filterable>
|
||||
<template v-for="(item, index) in data.toFlowNodeIds" :key="index">
|
||||
<el-option :label="item.nodeName"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
|
||||
<el-tooltip placement="top" content="组内条件满足时,驳回到哪个节点(注意:必须是已审批过的节点)">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</template>
|
||||
</template>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowMethod">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {rule, validateNull} from "/@/utils/validate";
|
||||
import {deepClone} from "/@/utils/other";
|
||||
import {DIC_PROP} from "/@/flow/support/dict-prop";
|
||||
import {buildSysFieldsFormOption} from "../../utils/form-perm";
|
||||
import {
|
||||
onFormLoadedUrl,
|
||||
onLoadDicUrl,
|
||||
initRemoteMethodAllByKey
|
||||
} from "../../components/convert-name/convert";
|
||||
import {PROP_CONST} from "../../support/prop-const";
|
||||
import {handleChangeJobType} from "../../index";
|
||||
import {validateNodeType} from "./index";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const FlowHttpParam = defineAsyncComponent(() => import('./flow-http-param.vue'));
|
||||
const $emit = defineEmits(["openFlowRoutes"]);
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const condData = {
|
||||
httpMethod: 'GET',
|
||||
roleId: null,
|
||||
jobType: null,
|
||||
routeAction: null,
|
||||
toFlowNodeId: null,
|
||||
groupsType: '1',
|
||||
condGroup: [],
|
||||
groupType: '0',
|
||||
valType: '0',
|
||||
varKeyVal: null,
|
||||
operator: null,
|
||||
varVal: null,
|
||||
}
|
||||
|
||||
const data = reactive({
|
||||
activeKey: 'flow-rule',
|
||||
collapse: [0],
|
||||
allFieldPerms: [],
|
||||
formFieldPerms: [],
|
||||
cond: deepClone(condData),
|
||||
httpUrlParamsVisible: false,
|
||||
oldCurrentRow: null,
|
||||
condGroups: [],
|
||||
toFlowNodeIds: [],
|
||||
existData: false,
|
||||
})
|
||||
|
||||
// 定义字典
|
||||
const dicData = reactive({});
|
||||
const onLoad = onLoadDicUrl();
|
||||
const onFormLoaded = onFormLoadedUrl(...PROP_CONST.LOAD_USER_ROLE);
|
||||
onMounted(async () => {
|
||||
// await onLoad(dicData);
|
||||
|
||||
methods.changeTabPane(props.currSelect)
|
||||
})
|
||||
|
||||
const methodsRemote = initRemoteMethodAllByKey(onLoad, dicData)
|
||||
|
||||
const methods = {
|
||||
changeJobType(item) {
|
||||
handleChangeJobType(dicData, item)
|
||||
},
|
||||
onFormLoaded() {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.attrs.condGroups
|
||||
if (validateNull(condGroups)) return
|
||||
onFormLoaded(dicData, condGroups)
|
||||
},
|
||||
changeRouteAction(item) {
|
||||
// 切换清空
|
||||
let b = item.routeAction === DIC_PROP.ROUTE_ACTIONS[1].value;
|
||||
if(!b && item.routeAction !== DIC_PROP.ROUTE_ACTIONS[3].value) {
|
||||
data.cond.toFlowNodeId = null
|
||||
}
|
||||
},
|
||||
openHttpUrlParams() {
|
||||
if (!data.cond.varKeyVal) {
|
||||
$message.warning("请先输入【Http请求地址】")
|
||||
return
|
||||
}
|
||||
if (data.httpUrlParamsVisible) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpParams = []
|
||||
data.httpUrlParamsVisible = false
|
||||
} else {
|
||||
data.httpUrlParamsVisible = true
|
||||
}
|
||||
},
|
||||
handleCurrentChange(row) {
|
||||
if (!row) return
|
||||
let condGroupsRow;
|
||||
for (let i = 0; i < data.condGroups.length; i++) {
|
||||
let index = data.condGroups[i].condGroup.indexOf(row);
|
||||
if (index !== -1) {
|
||||
condGroupsRow = data.condGroups[i];
|
||||
}
|
||||
}
|
||||
// 先清空之前选中的其他条件组
|
||||
if (data.oldCurrentRow !== condGroupsRow) {
|
||||
let oldIndex = data.condGroups.indexOf(data.oldCurrentRow);
|
||||
if (oldIndex !== -1) {
|
||||
proxy.$refs['tableDataRef' + oldIndex][0].setCurrentRow(null)
|
||||
}
|
||||
}
|
||||
data.cond = condGroupsRow
|
||||
data.oldCurrentRow = condGroupsRow
|
||||
},
|
||||
handleVarKeyVal(row) {
|
||||
let dots = row.varKeyVal.split('.').length - 1;
|
||||
if (dots === 2) {
|
||||
let find = DIC_PROP.OPERATOR.slice(6).find(f => f.value === row.operator);
|
||||
if (!find && row.operator) {
|
||||
$message.warning("子表单的字段只能选择包含或不包含")
|
||||
row.operator = null
|
||||
}
|
||||
}
|
||||
},
|
||||
changeGroupsType(groupsType) {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.attrs.condGroups;
|
||||
if (validateNull(condGroups)) return
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.forEach(each => {
|
||||
each.groupsType = groupsType
|
||||
})
|
||||
methods.validateCondData()
|
||||
},
|
||||
changeGroupType(item, index) {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.attrs.condGroups;
|
||||
if (validateNull(condGroups)) return
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups[index].groupType = item.groupType
|
||||
methods.validateCondData()
|
||||
},
|
||||
onAddItem(isAdd) {
|
||||
if (validateNull(data.formFieldPerms)) {
|
||||
buildSysFieldsFormOption(data, props, $message)
|
||||
}
|
||||
if (data.cond.condGroup.length > 0) {
|
||||
let find = data.cond.condGroup.find(f => !f.varKeyVal || !f.operator || !f.varVal);
|
||||
if (find) {
|
||||
let b = !find.varKeyVal || !find.operator || !find.varVal;
|
||||
if (isAdd && b) {
|
||||
$message.warning("请先填写 表单字段 或 运算符 或 值")
|
||||
return
|
||||
}
|
||||
}
|
||||
if (!isAdd) data.cond.condGroup.splice(0, data.cond.condGroup.length);
|
||||
}
|
||||
let obj = {varKeyVal: '', operator: '', varVal: ''};
|
||||
data.cond.condGroup.push(obj);
|
||||
},
|
||||
addFlowNodeCondGroup() {
|
||||
if (validateNull(data.cond.condGroup)) {
|
||||
$message.warning("请先添加组内条件")
|
||||
return
|
||||
}
|
||||
let valType = data.cond.valType;
|
||||
let find = data.cond.condGroup.find(f => !f.varKeyVal || !f.operator || !f.varVal);
|
||||
if (find) {
|
||||
if (valType === DIC_PROP.VAL_TYPE[2].value) {
|
||||
if (!find.varKeyVal || !find.operator || !find.varVal) {
|
||||
$message.warning("表单字段 或 运算符 或 值 不能为空")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!methods.validateCondGroupAttrs()) return;
|
||||
if (data.oldCurrentRow) {
|
||||
// 先清空之前选中
|
||||
let index = data.condGroups.indexOf(data.cond);
|
||||
if (index !== -1) {
|
||||
proxy.$refs['tableDataRef' + index][0].setCurrentRow(null)
|
||||
}
|
||||
data.oldCurrentRow = null
|
||||
data.cond = deepClone(condData);
|
||||
} else {
|
||||
let cond = deepClone(data.cond);
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.push(cond)
|
||||
methods.validateCondData()
|
||||
methods.updateCondVarKeyVal(true)
|
||||
}
|
||||
methods.onFormLoaded()
|
||||
},
|
||||
validateCondGroupAttrs() {
|
||||
if (!data.cond.routeAction) {
|
||||
$message.warning("路由动作 不能为空")
|
||||
return false
|
||||
}
|
||||
// 校验动作类型参数
|
||||
let b = data.cond.routeAction === DIC_PROP.ROUTE_ACTIONS[1].value;
|
||||
if(b || data.cond.routeAction === DIC_PROP.ROUTE_ACTIONS[3].value) {
|
||||
if (!data.cond.toFlowNodeId) {
|
||||
$message.warning("路由到哪个节点 不能为空")
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
handleCondGroupDelete(index: number) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.splice(index, 1)
|
||||
methods.validateCondData()
|
||||
},
|
||||
handleSingleCondDelete(index: number, row: any, groupIndex) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups[groupIndex].condGroup.splice(index, 1)
|
||||
if (validateNull(props.currSelect.attributes.attrs.cdata.attrs.condGroups[groupIndex].condGroup)) {
|
||||
methods.handleCondGroupDelete(groupIndex)
|
||||
}
|
||||
methods.validateCondData()
|
||||
},
|
||||
handleCondDelete(index: number, row: any) {
|
||||
data.cond.condGroup.splice(index, 1)
|
||||
},
|
||||
handleCondValType(type?) {
|
||||
if (type) {
|
||||
data.cond.varKeyVal = null
|
||||
methods.updateCondVarKeyVal(false)
|
||||
}
|
||||
if (!type) {
|
||||
type = methods.initCurrVarKeyVal()
|
||||
}
|
||||
if (type === DIC_PROP.VAL_TYPE[2].value) {
|
||||
data.varValOperator = DIC_PROP.OPERATOR
|
||||
methods.onAddItem(false)
|
||||
} else {
|
||||
data.varValOperator = []
|
||||
}
|
||||
data.cond.operator = null
|
||||
data.cond.varVal = null
|
||||
},
|
||||
handleCondVarKeyVal() {
|
||||
let val = data.cond.varKeyVal
|
||||
let valType = data.cond.valType;
|
||||
if (!val) {
|
||||
methods.updateCondVarKeyVal(false)
|
||||
return
|
||||
}
|
||||
if (valType === DIC_PROP.VAL_TYPE[2].value) return
|
||||
if (valType === DIC_PROP.VAL_TYPE[4].value && val.indexOf("#") === -1) {
|
||||
data.cond.varKeyVal = null
|
||||
$message.warning("当选择专业模式时, 函数表达式必须符合规定的格式")
|
||||
return;
|
||||
}
|
||||
methods.updateCondVarKeyVal(true)
|
||||
},
|
||||
updateCondVarKeyVal(isSave) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.valType = data.cond.valType
|
||||
if (isSave) {
|
||||
if (data.cond.valType === DIC_PROP.VAL_TYPE[2].value) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.routeKeyVal = PROP_CONST.VAR_KEY_VAL.route
|
||||
props.currSelect.attributes.attrs.cdata.attrs.routeKeyValName = PROP_CONST.VAR_KEY_VAL.routeName
|
||||
} else {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.routeKeyVal = data.cond.varKeyVal
|
||||
}
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpMethod = data.cond.httpMethod
|
||||
} else {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.routeKeyVal = null
|
||||
props.currSelect.attributes.attrs.cdata.attrs.routeKeyValName = null
|
||||
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups = []
|
||||
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpParams = []
|
||||
props.currSelect.attributes.attrs.cdata.attrs.httpMethod = null
|
||||
data.httpUrlParamsVisible = false
|
||||
}
|
||||
},
|
||||
validateCondData() {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.attrs.condGroups;
|
||||
if (!condGroups) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups = []
|
||||
}
|
||||
data.condGroups.splice(0, data.condGroups.length);
|
||||
props.currSelect.attributes.attrs.cdata.attrs.condGroups.forEach(each => data.condGroups.push(each))
|
||||
data.existData = !validateNull(data.condGroups)
|
||||
},
|
||||
initCurrVarKeyVal() {
|
||||
data.cond.valType = props.currSelect.attributes.attrs.cdata.attrs.valType
|
||||
if (data.condGroups.length <= 0) {
|
||||
data.cond.varKeyVal = props.currSelect.attributes.attrs.cdata.attrs.routeKeyVal
|
||||
let httpMethod = props.currSelect.attributes.attrs.cdata.attrs.httpMethod
|
||||
if (httpMethod) data.cond.httpMethod = httpMethod
|
||||
}
|
||||
let httpParams = props.currSelect.attributes.attrs.cdata.attrs.httpParams;
|
||||
if (!validateNull(httpParams)) {
|
||||
data.httpUrlParamsVisible = true
|
||||
}
|
||||
return data.cond.valType
|
||||
},
|
||||
handleFlowNodeIds() {
|
||||
data.toFlowNodeIds = []
|
||||
let models = window._jfGraph.getElements();
|
||||
if (validateNull(models)) return
|
||||
models.forEach(each => {
|
||||
if (!validateNodeType(each)) return
|
||||
if (props.currSelect.id !== each.id) {
|
||||
let id = each.id
|
||||
let nodeName = each.attributes.attrs.label.text
|
||||
data.toFlowNodeIds.push({id, nodeName})
|
||||
}
|
||||
})
|
||||
},
|
||||
changeTabPane(val) {
|
||||
methods.validateCondData()
|
||||
methods.handleCondValType()
|
||||
methods.handleFlowNodeIds()
|
||||
methods.onFormLoaded()
|
||||
}
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.currSelect,
|
||||
(val) => {
|
||||
if (Object.keys(val).length === 0) {
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
361
src/flow/designer/components/flow-sub-param.vue
Normal file
361
src/flow/designer/components/flow-sub-param.vue
Normal file
@@ -0,0 +1,361 @@
|
||||
<template>
|
||||
<el-form label-position="left" class="flow-attr flow-param-attr" label-width="200px">
|
||||
|
||||
<el-divider>关联子流程Http接口</el-divider>
|
||||
|
||||
<el-form-item label="保存子流程表单Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="props.currSelect.attributes.attrs.cdata.attrs.startSubFlow"
|
||||
clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="props.currSelect.attributes.attrs.cdata.attrs.startSubMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content>启动子流程时更新子流程表单接口(可输入全路径或相对路径)</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="更新子流程表单Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="props.currSelect.attributes.attrs.cdata.attrs.restartSubFlow"
|
||||
clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="props.currSelect.attributes.attrs.cdata.attrs.restartSubMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content>重入或重启子流程时更新子流程表单接口(可输入全路径或相对路径)</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
<el-form-item label="更新父流程表单Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="props.currSelect.attributes.attrs.cdata.attrs.backParFlow"
|
||||
clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="props.currSelect.attributes.attrs.cdata.attrs.backParMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content>返回父流程时更新父流程表单接口(可输入全路径或相对路径)</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider>关联子流程Http请求头</el-divider>
|
||||
|
||||
<el-table :data="data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value)"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" :label="t('jfI18n.operate')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle
|
||||
@click="methods.onAddItem(DIC_PROP.PARAM_FROM[0].value, true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleSubFlowDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="targetProp" :label="t('jfAttr.requestHeader')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.targetProp" :placeholder="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value ? scope.row.varKeyVal : null"
|
||||
clearable></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="paramValType" :label="t('jfAttr.paramValType')" width="145px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.paramValType" clearable>
|
||||
<el-option v-for="(item, index) in DIC_PROP.PARAM_VAL_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('jfAttr.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal"
|
||||
v-if="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value"
|
||||
clearable filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
|
||||
<el-input v-else v-model="scope.row.varKeyVal" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<el-divider>父流程传参到子流程</el-divider>
|
||||
|
||||
<el-table :data="data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value)"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" :label="t('jfI18n.operate')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle
|
||||
@click="methods.onAddItem(DIC_PROP.PARAM_FROM[1].value, true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleSubFlowDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('jfAttr.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal"
|
||||
v-if="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value"
|
||||
clearable filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
|
||||
<el-input v-else v-model="scope.row.varKeyVal" clearable> </el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="paramValType" :label="t('jfAttr.paramValType')" width="145px">
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.paramValType" clearable>
|
||||
<el-option v-for="(item, index) in DIC_PROP.PARAM_VAL_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="targetProp" :label="t('jfAttr.subVarKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.targetProp" :placeholder="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value ? scope.row.varKeyVal : null"
|
||||
clearable></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-divider>子流程回参到父流程</el-divider>
|
||||
|
||||
<el-table :data="data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[2].value)"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" :label="t('jfI18n.operate')" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle
|
||||
@click="methods.onAddItem(DIC_PROP.PARAM_FROM[2].value, true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleSubFlowDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="targetProp" :label="t('jfAttr.subVarKeyVal2')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.targetProp"
|
||||
:placeholder="scope.row.paramValType === DIC_PROP.PARAM_VAL_TYPE[0].value ? scope.row.varKeyVal : null"
|
||||
clearable></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="paramValType" :label="t('jfAttr.paramValType')" width="145px">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.paramValType"
|
||||
:active-value="DIC_PROP.PARAM_VAL_TYPE[0].value"
|
||||
:active-text="DIC_PROP.PARAM_VAL_TYPE[0].label"
|
||||
:inactive-value="DIC_PROP.PARAM_VAL_TYPE[2].value"
|
||||
:inactive-text="DIC_PROP.PARAM_VAL_TYPE[2].label"
|
||||
inline-prompt>
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal"
|
||||
clearable filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowSubParam">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {buildSysFieldsFormOption} from "../../utils/form-perm";
|
||||
import {DIC_PROP} from "../../support/dict-prop";
|
||||
|
||||
const {proxy} = getCurrentInstance();
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const data = reactive({
|
||||
allFieldPerms: [],
|
||||
formFieldPerms: [],
|
||||
subFlowParams: [],
|
||||
})
|
||||
|
||||
// 定义字典
|
||||
onMounted(async () => {
|
||||
methods.changeTabPane(props.currSelect)
|
||||
})
|
||||
|
||||
const methods = {
|
||||
listFormFieldPerms() {
|
||||
if (validateNull(data.formFieldPerms)) {
|
||||
buildSysFieldsFormOption(data, props, $message)
|
||||
}
|
||||
},
|
||||
onAddItem(paramFrom, isAdd) {
|
||||
methods.listFormFieldPerms()
|
||||
let value = DIC_PROP.PARAM_VAL_TYPE[0].value;
|
||||
if (data.subFlowParams.length > 0) {
|
||||
let find = data.subFlowParams.filter(f => f.paramFrom === paramFrom).find(f => !f.varKeyVal || (f.paramValType !== value && !f.targetProp));
|
||||
if (find) {
|
||||
if (isAdd) {
|
||||
if (!find.varKeyVal) {
|
||||
$message.warning("请先填写 表单字段")
|
||||
return
|
||||
}
|
||||
if (find.paramValType !== value && !find.targetProp) {
|
||||
if (DIC_PROP.PARAM_FROM[0].value === paramFrom) {
|
||||
$message.warning("请先填写 请求头")
|
||||
} else {
|
||||
$message.warning("请先填写 子流程表单字段")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isAdd) data.subFlowParams.splice(0, data.subFlowParams.length);
|
||||
}
|
||||
let obj = {paramFrom: paramFrom, varKeyVal: null, paramValType: value, targetProp: null};
|
||||
data.subFlowParams.push(obj);
|
||||
methods.changeSubFlowParams()
|
||||
},
|
||||
handleSubFlowDelete(index: number, row: any) {
|
||||
let splice = data.subFlowParams.filter(f => f.paramFrom === row.paramFrom);
|
||||
splice.splice(index, 1);
|
||||
if (DIC_PROP.PARAM_FROM[0].value === row.paramFrom) {
|
||||
let res = data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value);
|
||||
let res2 = data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[2].value);
|
||||
splice.push(...res)
|
||||
splice.push(...res2)
|
||||
} else if (DIC_PROP.PARAM_FROM[1].value === row.paramFrom) {
|
||||
let res = data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value);
|
||||
let res2 = data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[2].value);
|
||||
splice.push(...res)
|
||||
splice.push(...res2)
|
||||
} else if (DIC_PROP.PARAM_FROM[2].value === row.paramFrom) {
|
||||
let res = data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[0].value);
|
||||
let res2 = data.subFlowParams.filter(f => f.paramFrom === DIC_PROP.PARAM_FROM[1].value);
|
||||
splice.push(...res)
|
||||
splice.push(...res2)
|
||||
}
|
||||
data.subFlowParams = splice
|
||||
methods.changeSubFlowParams()
|
||||
},
|
||||
validateSubFlowData() {
|
||||
// 兼容老版本
|
||||
let subFlowParams = props.currSelect.attributes.attrs.cdata.attrs.subFlowParams;
|
||||
if (!subFlowParams) {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.subFlowParams = []
|
||||
}
|
||||
let startSubMethod = props.currSelect.attributes.attrs.cdata.attrs.startSubMethod;
|
||||
if (!startSubMethod) props.currSelect.attributes.attrs.cdata.attrs.startSubMethod = 'POST'
|
||||
let restartSubMethod = props.currSelect.attributes.attrs.cdata.attrs.restartSubMethod;
|
||||
if (!restartSubMethod) props.currSelect.attributes.attrs.cdata.attrs.restartSubMethod = 'PUT'
|
||||
let backParMethod = props.currSelect.attributes.attrs.cdata.attrs.backParMethod;
|
||||
if (!backParMethod) props.currSelect.attributes.attrs.cdata.attrs.backParMethod = 'PUT'
|
||||
|
||||
data.subFlowParams = props.currSelect.attributes.attrs.cdata.attrs.subFlowParams
|
||||
},
|
||||
changeSubFlowParams() {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.subFlowParams = data.subFlowParams
|
||||
},
|
||||
changeTabPane(val) {
|
||||
methods.validateSubFlowData()
|
||||
methods.listFormFieldPerms()
|
||||
}
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.currSelect,
|
||||
(val) => {
|
||||
if (Object.keys(val).length === 0) {
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
666
src/flow/designer/components/flow-user-rule.vue
Normal file
666
src/flow/designer/components/flow-user-rule.vue
Normal file
@@ -0,0 +1,666 @@
|
||||
<template>
|
||||
<el-form-item label="条件组关系">
|
||||
<el-switch
|
||||
v-model="data.cond.groupsType" @change="methods.changeGroupsType"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且" disabled>
|
||||
</el-switch>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>一个组决定一个参与者。多条件组满足则累加参与者</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="审批规则模式">
|
||||
<el-radio-group style="width: 313px" @change="methods.handleCondValType" :disabled="data.existData"
|
||||
v-model="data.cond.valType">
|
||||
<el-radio v-for="(item, index) in [DIC_PROP.VAL_TYPE[2], DIC_PROP.VAL_TYPE[4], DIC_PROP.VAL_TYPE[5]]" :key="index" :label="item.value"
|
||||
style="width: 75px">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>若无法切换模式,请先清空条件组列表</template>
|
||||
<el-icon>
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider>组内条件配置</el-divider>
|
||||
|
||||
<template v-if="data.cond.valType === '0'">
|
||||
<el-form-item label="组内条件关系">
|
||||
<el-switch
|
||||
v-model="data.cond.groupType"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="data.cond.condGroup"
|
||||
border style="width: 100%; margin-bottom: 10px" max-height="500">
|
||||
|
||||
<el-table-column type="index" label="操作" width="80">
|
||||
<template #header>
|
||||
<el-button icon="Plus" size="small" type="primary" circle @click="methods.onAddItem(true)"></el-button>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle @click="methods.handleCondDelete(scope.$index, scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.varKeyVal" @change="methods.handleVarKeyVal(scope.row)"
|
||||
clearable
|
||||
filterable>
|
||||
<el-option-group
|
||||
v-for="(group, index) in data.allFieldPerms"
|
||||
:key="index"
|
||||
:label="group.label">
|
||||
<el-option
|
||||
v-for="(item, index) in group.options"
|
||||
:disabled="item.prop.indexOf('_define_') !== -1"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.prop">
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-select v-model="scope.row.operator" @change="methods.handleVarKeyVal(scope.row)"
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="(item, index) in data.varValOperator"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.varVal" clearable/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-form-item label="参与者类型">
|
||||
<el-select v-model="data.cond.jobType" @change="methods.changeJobType(data.cond)">
|
||||
<el-option v-for="(item, index) in DIC_PROP.JOB_USER_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个人来审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[0].value">
|
||||
<el-tooltip content="请输入用户名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr"
|
||||
v-model="data.cond.roleId"
|
||||
clearable filterable
|
||||
remote :remote-method="methodsRemote.remoteMethodUser2" :reserve-keyword="false">
|
||||
<template v-for="(item, index) in dicData.users2" :key="index">
|
||||
<el-option :label="item.name"
|
||||
:value="item.userId">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个人来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个角色审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[1].value">
|
||||
<el-tooltip content="请输入角色名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="data.cond.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodRole2" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.roles2"
|
||||
:key="index"
|
||||
:label="item.roleName"
|
||||
:value="item.roleId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个角色来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个岗位审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[2].value">
|
||||
<el-tooltip content="请输入岗位名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="data.cond.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodPost2" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.posts2"
|
||||
:key="index"
|
||||
:label="item.postName"
|
||||
:value="item.postId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个岗位来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个部门审批" v-if="data.cond.jobType === DIC_PROP.JOB_USER_TYPE[3].value">
|
||||
<el-tooltip content="请输入部门名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="data.cond.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodDept2" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.depts2"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="item.deptId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个部门审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
</template>
|
||||
|
||||
<el-form-item label="函数表达式" v-if="data.cond.valType === '2'">
|
||||
<el-input class="input-attr" v-model="data.cond.varKeyVal" placeholder="请输入函数表达式" clearable @blur="methods.handleCondVarKeyVal"/>
|
||||
|
||||
<el-tooltip placement="top">
|
||||
<template #content>采用表达式取值 ( 以下两种方式均支持自定义任意扩展 ), 值可以为对象 或 数组, 满足您分配参与者复杂的场景:
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condUserExplain }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain3 }}, 返回值可以为对象 或 数组,{{ PROP_CONST.TEXT_DESC.condMethodExplain5 }}
|
||||
<br />{{ PROP_CONST.TEXT_DESC.condMethodExplain4 }}
|
||||
</template>
|
||||
<el-icon style="margin-left: 10px">
|
||||
<QuestionFilled/>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<div v-if="data.cond.valType === '2'" style="margin: 10px 13px">
|
||||
<span style="color: #409EFF;font-size: 14px">注: 当前函数表达式的返回值可以为对象 或 数组,{{ PROP_CONST.TEXT_DESC.condMethodExplain5 }}</span>
|
||||
</div>
|
||||
|
||||
<template v-if="data.cond.valType === '3'">
|
||||
<el-form-item label="Http请求地址">
|
||||
<el-input class="input-attr" placeholder="可输入全路径或相对路径" v-model="data.cond.varKeyVal"
|
||||
@blur="methods.handleCondVarKeyVal" clearable>
|
||||
<template #prepend>
|
||||
<el-select v-model="data.cond.httpMethod">
|
||||
<el-option v-for="(item, index) in DIC_PROP.HTTP_METHODS" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip content="点击可设置Http请求的参数信息" placement="bottom">
|
||||
<el-button type="primary" size="small" round style="margin-left: 10px"
|
||||
@click="methods.openHttpUrlParams()">
|
||||
{{ data.httpUrlParamsVisible ? '清空' : '参数' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<flow-http-param ref="flowHttpParam" :currFlowForm="props.currFlowForm" :flowData="props.flowData"
|
||||
:httpParam="props.currSelect.attributes.attrs.cdata.defJob"
|
||||
:httpParamType="DIC_PROP.PARAM_RULE_TYPE[0].value"
|
||||
v-if="data.httpUrlParamsVisible"></flow-http-param>
|
||||
</template>
|
||||
|
||||
<template v-if="data.cond.valType === '0'">
|
||||
<el-tooltip content="当节点属性【多人审批方式】为依次审批时,审批顺序由下方条件组的顺序决定" placement="bottom">
|
||||
<el-button type="primary" round style="margin-left: 185px; margin-top: 30px; margin-bottom: 30px; width: 200px" @click="methods.addFlowNodeCondGroup()">
|
||||
{{ data.oldCurrentRow ? '修改完成': '添加条件组' }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-divider>已添加条件组列表(点击行可再次修改)</el-divider>
|
||||
<el-empty description="条件组列表为空" style="margin: 10px 230px" v-if="!data.existData">
|
||||
</el-empty>
|
||||
|
||||
<template v-for="(item, index) in data.condGroups" v-else
|
||||
:key="index">
|
||||
|
||||
<el-collapse v-model="data.collapse">
|
||||
<el-collapse-item :name="index">
|
||||
<template #title>
|
||||
{{ '条件组 ' + (index + 1) }}
|
||||
|
||||
<el-icon style="margin-left: 10px" @click="methods.handleCondGroupDelete(index)">
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</template>
|
||||
|
||||
<el-form-item label="组内条件关系">
|
||||
<el-switch
|
||||
v-model="item.groupType" @change="methods.changeGroupType(item, index)"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
inactive-text="或"
|
||||
active-text="且">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-table :data="item.condGroup" border style="width: 100%; margin-bottom: 10px" max-height="500"
|
||||
highlight-current-row @current-change="methods.handleCurrentChange" :ref="'tableDataRef' + index">
|
||||
|
||||
<el-table-column type="index" label="操作" width="80">
|
||||
<template #default="scope">
|
||||
<el-button icon="Minus" size="small" type="danger" circle
|
||||
@click="methods.handleSingleCondDelete(scope.$index, scope.row, index)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varKeyVal" :label="t('flowClazz.varKeyVal')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<convert-group-name :options="data.allFieldPerms"
|
||||
:value="scope.row.varKeyVal"
|
||||
:valueKey="'prop'" :showKey="'label'"></convert-group-name>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operator" :label="t('flowClazz.operator')" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<dict-tag :options="DIC_PROP.OPERATOR" :value="scope.row.operator"></dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="varVal" :label="t('flowClazz.varVal')" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
|
||||
<el-form-item label="参与者类型">
|
||||
<el-select v-model="item.jobType" @change="methods.changeJobType(item)">
|
||||
<el-option v-for="(item, index) in DIC_PROP.JOB_USER_TYPE" :key="index" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个人来审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[0].value">
|
||||
<el-tooltip content="请输入用户名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr"
|
||||
v-model="item.roleId"
|
||||
clearable filterable
|
||||
remote :remote-method="methodsRemote.remoteMethodUser" :reserve-keyword="false">
|
||||
<template v-for="(item, index) in dicData.users" :key="index">
|
||||
<el-option :label="item.name"
|
||||
:value="item.userId">
|
||||
</el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个人来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个角色审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[1].value">
|
||||
<el-tooltip content="请输入角色名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="item.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodRole" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.roles"
|
||||
:key="index"
|
||||
:label="item.roleName"
|
||||
:value="item.roleId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个角色来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个岗位审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[2].value">
|
||||
<el-tooltip content="请输入岗位名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="item.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodPost" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.posts"
|
||||
:key="index"
|
||||
:label="item.postName"
|
||||
:value="item.postId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个岗位来审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="哪个部门审批" v-if="item.jobType === DIC_PROP.JOB_USER_TYPE[3].value">
|
||||
<el-tooltip content="请输入部门名称进行模糊搜索" placement="top">
|
||||
<el-select class="input-attr" v-model="item.roleId"
|
||||
filterable
|
||||
clearable
|
||||
remote :remote-method="methodsRemote.remoteMethodDept" :reserve-keyword="false">
|
||||
<el-option
|
||||
v-for="(item, index) in dicData.depts"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
:value="item.deptId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
<el-tooltip placement="top" content="组内条件满足时,由哪个部门审批">
|
||||
<el-icon style="margin-left: 10px"><QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowUserRule">
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {rule, validateNull} from "/@/utils/validate";
|
||||
import {deepClone} from "/@/utils/other";
|
||||
import {DIC_PROP} from "/@/flow/support/dict-prop";
|
||||
import {buildSysFieldsFormOption} from "../../utils/form-perm";
|
||||
import {onFormLoadedUrl, onLoadDicUrl, initRemoteMethodAllByKey} from "../../components/convert-name/convert";
|
||||
import {PROP_CONST} from "../../support/prop-const";
|
||||
import {handleChangeJobType} from "../../index";
|
||||
|
||||
const {proxy} = getCurrentInstance();
|
||||
const FlowHttpParam = defineAsyncComponent(() => import('./flow-http-param.vue'));
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const props = defineProps({
|
||||
currFlowForm: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
currSelect: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const condData = {
|
||||
httpMethod: 'GET',
|
||||
roleId: null,
|
||||
jobType: null,
|
||||
groupsType: '1',
|
||||
condGroup: [],
|
||||
groupType: '0',
|
||||
valType: '0',
|
||||
varKeyVal: null,
|
||||
operator: null,
|
||||
varVal: null,
|
||||
}
|
||||
|
||||
const data = reactive({
|
||||
collapse: [0],
|
||||
allFieldPerms: [],
|
||||
formFieldPerms: [],
|
||||
cond: deepClone(condData),
|
||||
httpUrlParamsVisible: false,
|
||||
oldCurrentRow: null,
|
||||
condGroups: [],
|
||||
existData: false
|
||||
})
|
||||
|
||||
// 定义字典
|
||||
const dicData = reactive({});
|
||||
const onLoad = onLoadDicUrl();
|
||||
const onFormLoaded = onFormLoadedUrl(...PROP_CONST.LOAD_USER_ROLE);
|
||||
onMounted(async () => {
|
||||
// await onLoad(dicData);
|
||||
|
||||
methods.changeTabPane(props.currSelect)
|
||||
})
|
||||
|
||||
const methodsRemote = initRemoteMethodAllByKey(onLoad, dicData)
|
||||
|
||||
const methods = {
|
||||
changeJobType(item) {
|
||||
handleChangeJobType(dicData, item)
|
||||
},
|
||||
onFormLoaded() {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.defJob.condGroups
|
||||
if (validateNull(condGroups)) return
|
||||
onFormLoaded(dicData, condGroups)
|
||||
},
|
||||
openHttpUrlParams() {
|
||||
if (!data.cond.varKeyVal) {
|
||||
$message.warning("请先输入【Http请求地址】")
|
||||
return
|
||||
}
|
||||
if (data.httpUrlParamsVisible) {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.httpParams = []
|
||||
data.httpUrlParamsVisible = false
|
||||
} else {
|
||||
data.httpUrlParamsVisible = true
|
||||
}
|
||||
},
|
||||
handleCurrentChange(row) {
|
||||
if (!row) return
|
||||
let condGroupsRow;
|
||||
for (let i = 0; i < data.condGroups.length; i++) {
|
||||
let index = data.condGroups[i].condGroup.indexOf(row);
|
||||
if (index !== -1) {
|
||||
condGroupsRow = data.condGroups[i];
|
||||
}
|
||||
}
|
||||
// 先清空之前选中的其他条件组
|
||||
if (data.oldCurrentRow !== condGroupsRow) {
|
||||
let oldIndex = data.condGroups.indexOf(data.oldCurrentRow);
|
||||
if (oldIndex !== -1) {
|
||||
proxy.$refs['tableDataRef' + oldIndex][0].setCurrentRow(null)
|
||||
}
|
||||
}
|
||||
data.cond = condGroupsRow
|
||||
data.oldCurrentRow = condGroupsRow
|
||||
},
|
||||
handleVarKeyVal(row) {
|
||||
let dots = row.varKeyVal.split('.').length - 1;
|
||||
if (dots === 2) {
|
||||
let find = DIC_PROP.OPERATOR.slice(6).find(f => f.value === row.operator);
|
||||
if (!find && row.operator) {
|
||||
$message.warning("子表单的字段只能选择包含或不包含")
|
||||
row.operator = null
|
||||
}
|
||||
}
|
||||
},
|
||||
changeGroupsType(groupsType) {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.defJob.condGroups;
|
||||
if (validateNull(condGroups)) return
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups.forEach(each => {
|
||||
each.groupsType = groupsType
|
||||
})
|
||||
methods.validateCondData()
|
||||
},
|
||||
changeGroupType(item, index) {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.defJob.condGroups;
|
||||
if (validateNull(condGroups)) return
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups[index].groupType = item.groupType
|
||||
methods.validateCondData()
|
||||
},
|
||||
onAddItem(isAdd) {
|
||||
if (validateNull(data.formFieldPerms)) {
|
||||
buildSysFieldsFormOption(data, props, $message)
|
||||
}
|
||||
if (data.cond.condGroup.length > 0) {
|
||||
let find = data.cond.condGroup.find(f => !f.varKeyVal || !f.operator || !f.varVal);
|
||||
if (find) {
|
||||
let b = !find.varKeyVal || !find.operator || !find.varVal;
|
||||
if (isAdd && b) {
|
||||
$message.warning("请先填写 表单字段 或 运算符 或 值")
|
||||
return
|
||||
}
|
||||
}
|
||||
if (!isAdd) data.cond.condGroup.splice(0, data.cond.condGroup.length);
|
||||
}
|
||||
let obj = {varKeyVal: '', operator: '', varVal: ''};
|
||||
data.cond.condGroup.push(obj);
|
||||
},
|
||||
addFlowNodeCondGroup() {
|
||||
if (validateNull(data.cond.condGroup)) {
|
||||
$message.warning("请先添加组内条件")
|
||||
return
|
||||
}
|
||||
let valType = data.cond.valType;
|
||||
let find = data.cond.condGroup.find(f => !f.varKeyVal || !f.operator || !f.varVal);
|
||||
if (find) {
|
||||
if (valType === DIC_PROP.VAL_TYPE[2].value) {
|
||||
if (!find.varKeyVal || !find.operator || !find.varVal) {
|
||||
$message.warning("表单字段 或 运算符 或 值 不能为空")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!data.cond.roleId) {
|
||||
$message.warning("参与者 不能为空")
|
||||
return
|
||||
}
|
||||
if (data.oldCurrentRow) {
|
||||
// 先清空之前选中
|
||||
let index = data.condGroups.indexOf(data.cond);
|
||||
if (index !== -1) {
|
||||
proxy.$refs['tableDataRef' + index][0].setCurrentRow(null)
|
||||
}
|
||||
data.oldCurrentRow = null
|
||||
data.cond = deepClone(condData);
|
||||
} else {
|
||||
let cond = deepClone(data.cond);
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups.push(cond)
|
||||
methods.validateCondData()
|
||||
methods.updateCondVarKeyVal(true)
|
||||
}
|
||||
methods.onFormLoaded()
|
||||
},
|
||||
handleCondGroupDelete(index: number) {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups.splice(index, 1)
|
||||
methods.validateCondData()
|
||||
},
|
||||
handleSingleCondDelete(index: number, row: any, groupIndex) {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups[groupIndex].condGroup.splice(index, 1)
|
||||
if (validateNull(props.currSelect.attributes.attrs.cdata.defJob.condGroups[groupIndex].condGroup)) {
|
||||
methods.handleCondGroupDelete(groupIndex)
|
||||
}
|
||||
methods.validateCondData()
|
||||
},
|
||||
handleCondDelete(index: number, row: any) {
|
||||
data.cond.condGroup.splice(index, 1)
|
||||
},
|
||||
handleCondValType(type?) {
|
||||
if (type) {
|
||||
data.cond.varKeyVal = null
|
||||
methods.updateCondVarKeyVal(false)
|
||||
}
|
||||
if (!type) {
|
||||
type = methods.initCurrVarKeyVal()
|
||||
}
|
||||
if (type === DIC_PROP.VAL_TYPE[2].value) {
|
||||
data.varValOperator = DIC_PROP.OPERATOR
|
||||
methods.onAddItem(false)
|
||||
} else {
|
||||
data.varValOperator = []
|
||||
}
|
||||
data.cond.operator = null
|
||||
data.cond.varVal = null
|
||||
},
|
||||
handleCondVarKeyVal() {
|
||||
let val = data.cond.varKeyVal
|
||||
let valType = data.cond.valType;
|
||||
if (!val) {
|
||||
methods.updateCondVarKeyVal(false)
|
||||
return
|
||||
}
|
||||
if (valType === DIC_PROP.VAL_TYPE[2].value) return
|
||||
if (valType === DIC_PROP.VAL_TYPE[4].value && val.indexOf("#") === -1) {
|
||||
data.cond.varKeyVal = null
|
||||
$message.warning("当选择专业模式时, 函数表达式必须符合规定的格式")
|
||||
return;
|
||||
}
|
||||
methods.updateCondVarKeyVal(true)
|
||||
},
|
||||
updateCondVarKeyVal(isSave) {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.valType = data.cond.valType
|
||||
if (isSave) {
|
||||
if (data.cond.valType === DIC_PROP.VAL_TYPE[2].value) {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.userKeyVal = PROP_CONST.VAR_KEY_VAL.person
|
||||
props.currSelect.attributes.attrs.cdata.defJob.userKeyValName = PROP_CONST.VAR_KEY_VAL.personName
|
||||
} else {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.userKeyVal = data.cond.varKeyVal
|
||||
}
|
||||
props.currSelect.attributes.attrs.cdata.defJob.httpMethod = data.cond.httpMethod
|
||||
} else {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.userKeyVal = null
|
||||
props.currSelect.attributes.attrs.cdata.defJob.userKeyValName = null
|
||||
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups = []
|
||||
|
||||
props.currSelect.attributes.attrs.cdata.defJob.httpParams = []
|
||||
props.currSelect.attributes.attrs.cdata.defJob.httpMethod = null
|
||||
data.httpUrlParamsVisible = false
|
||||
}
|
||||
},
|
||||
validateCondData() {
|
||||
let condGroups = props.currSelect.attributes.attrs.cdata.defJob.condGroups;
|
||||
if (!condGroups) {
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups = []
|
||||
}
|
||||
data.condGroups.splice(0, data.condGroups.length);
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups.forEach(each => data.condGroups.push(each))
|
||||
data.existData = !validateNull(data.condGroups)
|
||||
},
|
||||
initCurrVarKeyVal() {
|
||||
data.cond.valType = props.currSelect.attributes.attrs.cdata.defJob.valType
|
||||
if (data.condGroups.length <= 0) {
|
||||
data.cond.varKeyVal = props.currSelect.attributes.attrs.cdata.defJob.userKeyVal
|
||||
let httpMethod = props.currSelect.attributes.attrs.cdata.defJob.httpMethod
|
||||
if (httpMethod) data.cond.httpMethod = httpMethod
|
||||
}
|
||||
let httpParams = props.currSelect.attributes.attrs.cdata.defJob.httpParams;
|
||||
if (!validateNull(httpParams)) {
|
||||
data.httpUrlParamsVisible = true
|
||||
}
|
||||
return data.cond.valType
|
||||
},
|
||||
changeTabPane(val) {
|
||||
methods.validateCondData()
|
||||
methods.handleCondValType()
|
||||
methods.onFormLoaded()
|
||||
}
|
||||
}
|
||||
// 监听双向绑定
|
||||
watch(
|
||||
() => props.currSelect,
|
||||
(val) => {
|
||||
if (Object.keys(val).length === 0) {
|
||||
return
|
||||
}
|
||||
methods.changeTabPane(val)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/style/flow-attr.scss';
|
||||
</style>
|
||||
252
src/flow/designer/components/index.ts
Normal file
252
src/flow/designer/components/index.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import {DIC_PROP} from "/@/flow/support/dict-prop";
|
||||
import {PROP_CONST} from "/@/flow/support/prop-const";
|
||||
import {CommonNodeType, HighNodeType} from "/@/flow/designer/config/type";
|
||||
import {notifyLeft} from "/@/flow";
|
||||
import {useMessageBox} from "/@/hooks/message";
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
import {gateAttr, linkAttr, syncJobAttr, syncNodeAttr} from "/@/flow/designer/config/attr-config";
|
||||
import {setPropsNullValue} from "/@/flow/support/common";
|
||||
import {validateListFormOption} from "/@/flow/utils/form-perm";
|
||||
|
||||
/**
|
||||
* 常用工具类
|
||||
*
|
||||
* @author luolin
|
||||
*/
|
||||
// 反解析名称时未加载该常量
|
||||
export function revParseWhoseLeaderName(data, dicData) {
|
||||
// 谁的主管,可自定义更多
|
||||
dicData.users.unshift(PROP_CONST.FLOW_METHOD.whoseLeader)
|
||||
if (!data.whoseLeader) return
|
||||
if (data.whoseLeader === PROP_CONST.FLOW_METHOD.whoseLeader.userId) {
|
||||
data.whoseLeaderName = PROP_CONST.FLOW_METHOD.whoseLeader.name
|
||||
} else {
|
||||
let find = dicData.users.find(f => f.userId === data.whoseLeader);
|
||||
if (find) data.whoseLeaderName = find.name;
|
||||
}
|
||||
}
|
||||
|
||||
export async function revParseUserKeyValName(props, data, dicData, methods) {
|
||||
if (methods.validateCurrSelectDefJob) {
|
||||
if (!methods.validateCurrSelectDefJob()) return;
|
||||
}
|
||||
let valType = props.currSelect.attributes.attrs.cdata.defJob.valType;
|
||||
let userKeyVal = props.currSelect.attributes.attrs.cdata.defJob.userKeyVal;
|
||||
if (!userKeyVal) return;
|
||||
let userKeyValFrom;
|
||||
if (userKeyVal === PROP_CONST.VAR_KEY_VAL.order + 'createUser') {
|
||||
userKeyValFrom = DIC_PROP.FLOW_METHOD_TYPE[0].value
|
||||
data.activeKey = 'flow-method'
|
||||
} else if (userKeyVal.indexOf('getUserDeptLeaderId') !== -1) {
|
||||
userKeyValFrom = DIC_PROP.FLOW_METHOD_TYPE[1].value
|
||||
data.whoseLeader = userKeyVal.substring(userKeyVal.indexOf('(Long#') + 6, userKeyVal.indexOf(',Integer#'))
|
||||
data.leaderLevel = parseInt(userKeyVal.substring(userKeyVal.indexOf(',Integer#') + 9, userKeyVal.indexOf(',String#')))
|
||||
data.levelExtract = userKeyVal.substring(userKeyVal.indexOf(',String#') + 8, userKeyVal.indexOf(')'))
|
||||
data.activeKey = 'flow-method'
|
||||
} else if (userKeyVal.indexOf('listUserDeptMultiLeaderId') !== -1) {
|
||||
userKeyValFrom = DIC_PROP.FLOW_METHOD_TYPE[2].value
|
||||
let lastIndex = userKeyVal.indexOf('String#') - 1;
|
||||
data.whoseLeader = userKeyVal.substring(userKeyVal.indexOf('(Long#') + 6, lastIndex)
|
||||
userKeyVal = userKeyVal.substr(lastIndex)
|
||||
lastIndex = userKeyVal.indexOf('Integer#') - 1;
|
||||
data.auditEndpoint = userKeyVal.substring(userKeyVal.indexOf('String#') + 7, lastIndex)
|
||||
userKeyVal = userKeyVal.substr(lastIndex)
|
||||
lastIndex = userKeyVal.indexOf('String#') - 1;
|
||||
let leaderLevel = userKeyVal.substring(userKeyVal.indexOf('Integer#') + 8, lastIndex)
|
||||
userKeyVal = userKeyVal.substr(lastIndex)
|
||||
if (data.auditEndpoint === '1') data.leaderLevel = parseInt(leaderLevel)
|
||||
lastIndex = userKeyVal.lastIndexOf('String#') - 1;
|
||||
data.seqAuditSort = userKeyVal.substring(userKeyVal.indexOf('String#') + 7, lastIndex)
|
||||
userKeyVal = userKeyVal.substr(lastIndex)
|
||||
data.levelExtract = userKeyVal.substring(userKeyVal.indexOf(')') - 1, userKeyVal.indexOf(')'))
|
||||
data.activeKey = 'flow-method'
|
||||
} else if (userKeyVal.indexOf('getDeptLeaderId') !== -1) {
|
||||
userKeyValFrom = DIC_PROP.FLOW_METHOD_TYPE[3].value
|
||||
data.appointDeptId = userKeyVal.substring(userKeyVal.indexOf('(Long#') + 6, userKeyVal.indexOf(',String#'))
|
||||
data.levelExtract = userKeyVal.substring(userKeyVal.indexOf(',String#') + 8, userKeyVal.indexOf(')'))
|
||||
} else if (props.currSelect.attributes.attrs.cdata.defJob.userKeyValName) {
|
||||
let find = DIC_PROP.FLOW_METHOD_TYPE.find(f => f.label === props.currSelect.attributes.attrs.cdata.defJob.userKeyValName);
|
||||
// 再次编辑时优先显示为专业模式
|
||||
if (find) {
|
||||
userKeyValFrom = DIC_PROP.FLOW_METHOD_TYPE[4].value
|
||||
data.userKeyVal = userKeyVal
|
||||
if (methods.handleUserKeyValFrom) methods.handleUserKeyValFrom(userKeyValFrom)
|
||||
data.activeKey = 'flow-method'
|
||||
}
|
||||
} else if (DIC_PROP.VAL_TYPE[4].value === valType && userKeyVal) {
|
||||
if (validateNull(data.formFieldPerms)) await validateListFormOption(data, props)
|
||||
if (!validateNull(data.formFieldPerms)) {
|
||||
let exist = data.formFieldPerms.find(f => f.prop === userKeyVal);
|
||||
if (exist) userKeyValFrom = DIC_PROP.FLOW_METHOD_TYPE[4].value
|
||||
}
|
||||
}
|
||||
if (userKeyValFrom) {
|
||||
data.userKeyValFrom = userKeyValFrom
|
||||
} else {
|
||||
data.activeKey = 'flow-rule'
|
||||
}
|
||||
}
|
||||
|
||||
export function parseUserKeyValName(props, data, methods) {
|
||||
if (methods.validateCurrSelectDefJob) {
|
||||
if (!methods.validateCurrSelectDefJob()) return;
|
||||
}
|
||||
let userKeyVal;
|
||||
if (data.userKeyValFrom === '0') {
|
||||
userKeyVal = PROP_CONST.VAR_KEY_VAL.order + 'createUser'
|
||||
} else if (data.userKeyValFrom === '1') {
|
||||
userKeyVal = '#distActorServiceImpl.getUserDeptLeaderId(Long#'+ data.whoseLeader +',Integer#'+ data.leaderLevel +',String#'+ data.levelExtract +')'
|
||||
} else if (data.userKeyValFrom === '2') {
|
||||
let leaderLevel = 'NULL'
|
||||
if (data.auditEndpoint === '1') leaderLevel = data.leaderLevel
|
||||
let seqAuditSort = 'NULL'
|
||||
if (data.seqAuditSort) seqAuditSort = data.seqAuditSort
|
||||
userKeyVal = '#distActorServiceImpl.listUserDeptMultiLeaderId(Long#'+ data.whoseLeader +',String#'+ data.auditEndpoint +',Integer#'+ leaderLevel +',String#'+ seqAuditSort +',String#'+ data.levelExtract +')'
|
||||
} else if (data.userKeyValFrom === '3') {
|
||||
userKeyVal = '#distActorServiceImpl.getDeptLeaderId(Long#'+ data.appointDeptId +',String#'+ data.levelExtract +')'
|
||||
} else if (data.userKeyValFrom === '4') {
|
||||
userKeyVal = data.userKeyVal
|
||||
}
|
||||
if (data.userKeyValFrom === '1' || data.userKeyValFrom === '2') {
|
||||
if (!data.whoseLeader) {
|
||||
if (methods.$message) methods.$message('whoseLeader')
|
||||
return
|
||||
}
|
||||
}
|
||||
if (data.userKeyValFrom === '3') {
|
||||
if (!data.appointDeptId) {
|
||||
if (methods.$message) methods.$message('appointDeptId')
|
||||
return
|
||||
}
|
||||
}
|
||||
props.currSelect.attributes.attrs.cdata.defJob.userKeyVal = userKeyVal;
|
||||
props.currSelect.attributes.attrs.cdata.defJob.userKeyValName = DIC_PROP.FLOW_METHOD_TYPE.find(f => f.value === data.userKeyValFrom).label;
|
||||
|
||||
props.currSelect.attributes.attrs.cdata.defJob.valType = DIC_PROP.VAL_TYPE[4].value
|
||||
// 清空其他参数
|
||||
props.currSelect.attributes.attrs.cdata.defJob.condGroups = []
|
||||
props.currSelect.attributes.attrs.cdata.defJob.httpParams = []
|
||||
props.currSelect.attributes.attrs.cdata.defJob.httpMethod = null
|
||||
}
|
||||
|
||||
export function handleLinkFlowNodeIds(data, props) {
|
||||
data.toFlowNodeIds = []
|
||||
data.fromFlowNodeIds = []
|
||||
let models = window._jfGraph.getElements();
|
||||
data.fromFlowNodeId = props.currSelect.attributes.source.id
|
||||
data.toFlowNodeId = props.currSelect.attributes.target.id
|
||||
// 修正拖拽连线箭头更改目标节点
|
||||
props.currSelect.attributes.attrs.cdata.attrs.fromFlowNodeId = data.fromFlowNodeId
|
||||
props.currSelect.attributes.attrs.cdata.attrs.toFlowNodeId = data.toFlowNodeId
|
||||
models.forEach(each => {
|
||||
if (!validateNodeType(each)) return
|
||||
let id = each.id
|
||||
let nodeName = each.attributes.attrs.label.text
|
||||
if (id !== props.currSelect.attributes.target.id) {
|
||||
data.fromFlowNodeIds.push({id, nodeName})
|
||||
}
|
||||
if (id !== props.currSelect.attributes.source.id) {
|
||||
data.toFlowNodeIds.push({id, nodeName})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function changeLinkFlowNodeIds(data, props, methods?, $emit?) {
|
||||
useMessageBox()
|
||||
.confirm('是否确认修改连线的' + (data.modifyPointType === '0' ? '起点?' : '终点?'))
|
||||
.then(() => {
|
||||
doLinkFlowNodeIds(data, props, methods, $emit)
|
||||
})
|
||||
}
|
||||
|
||||
function doLinkFlowNodeIds(data, props, methods?, $emit?) {
|
||||
if (data.modifyPointType === '0') {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.fromFlowNodeId = data.fromFlowNodeId
|
||||
props.currSelect.set('source', { id: data.fromFlowNodeId });
|
||||
} else {
|
||||
props.currSelect.attributes.attrs.cdata.attrs.toFlowNodeId = data.toFlowNodeId
|
||||
props.currSelect.set('target', { id: data.toFlowNodeId });
|
||||
}
|
||||
if (methods) methods.handleLinkFlowNodeIds()
|
||||
if (window._flowConfig.globalConfig.isSimpleMode === '1') window._jfOperate.layout()
|
||||
else notifyLeft('专业模式不会自动调整连线轨迹,有必要时请手动调整', 'warning', 3000)
|
||||
if ($emit) $emit("hideAttrConfig", false, '1');
|
||||
}
|
||||
|
||||
export function validateNodeType(currSelect, methods?, isVirtual?) {
|
||||
if (methods && !methods.validateCurrSelectAttrs()) return false;
|
||||
let type = currSelect.attributes.attrs.cdata.type;
|
||||
let noVirtual = type === CommonNodeType.START || type === CommonNodeType.END || type === CommonNodeType.SERIAL || type === CommonNodeType.PARALLEL;
|
||||
if (!isVirtual) return noVirtual
|
||||
return noVirtual || type === HighNodeType.VIRTUAL
|
||||
}
|
||||
|
||||
export function handleSyncFlowNodeIds(data, props, methods) {
|
||||
data.syncFlowNodeIds = []
|
||||
if (!methods.validateCurrSelectAttrsAttrs()) return;
|
||||
props.currSelect.attributes.attrs.cdata.attrs.syncFlowNodeId = null
|
||||
let isGateway = props.currSelect.attributes.attrs.cdata.attrs.isGateway;
|
||||
let models = window._jfGraph.getElements();
|
||||
if (validateNull(models)) return
|
||||
models.forEach(each => {
|
||||
let cdata = each.attributes.attrs.cdata;
|
||||
let b = cdata.type === CommonNodeType.SERIAL || cdata.type === CommonNodeType.PARALLEL;
|
||||
if (b && props.currSelect.id !== each.id) {
|
||||
let id = each.id
|
||||
let nodeName = each.attributes.attrs.label.text + "(ID:" + id + ")"
|
||||
let isExist = false
|
||||
if (isGateway === '1') {
|
||||
if (cdata.attrs.isGateway === '1') isExist = true
|
||||
} else {
|
||||
if (cdata.attrs.isGateway !== '1') isExist = true
|
||||
}
|
||||
if (isExist) data.syncFlowNodeIds.push({id, nodeName})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function changeSyncFlowNodeId(id, props, methods, $message) {
|
||||
let models = window._jfGraph.getElements();
|
||||
if (validateNull(models) || !id) return
|
||||
let isGateway = props.currSelect.attributes.attrs.cdata.attrs.isGateway;
|
||||
let cdata = models.find(f => f.id === id).attributes.attrs.cdata;
|
||||
let nodeAttrs: any[];
|
||||
if (isGateway !== '1') {
|
||||
nodeAttrs = Object.keys(syncNodeAttr);
|
||||
if (!validateNull(cdata.defJob)) {
|
||||
setPropsNullValue(props.currSelect.attributes.attrs.cdata.defJob, cdata.defJob, ...Object.keys(syncJobAttr))
|
||||
}
|
||||
} else {
|
||||
nodeAttrs = Object.keys(gateAttr);
|
||||
}
|
||||
setPropsNullValue(props.currSelect.attributes.attrs.cdata.attrs, cdata.attrs, ...nodeAttrs)
|
||||
$message.warning("已同步其他节点的配置,请重新打开查看")
|
||||
methods.hideAttrConfig(false, '1');
|
||||
}
|
||||
|
||||
export function handleSyncFlowNodeRelIds(data, props, methods) {
|
||||
data.syncFlowNodeRelIds = []
|
||||
if (!methods.validateCurrSelectAttrsAttrs()) return;
|
||||
props.currSelect.attributes.attrs.cdata.attrs.syncFlowNodeRelId = null
|
||||
let links = window._jfGraph.getLinks();
|
||||
if (validateNull(links)) return
|
||||
links.forEach(each => {
|
||||
if (props.currSelect.id !== each.id) {
|
||||
let id = each.id
|
||||
let linkName = "ID:" + id
|
||||
let text = each.attributes.labels[0].attrs.text.text;
|
||||
if (text) linkName = text + "(ID:" + id + ")"
|
||||
data.syncFlowNodeRelIds.push({id, linkName})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function changeSyncFlowNodeRelId(id, props, methods, $message) {
|
||||
let links = window._jfGraph.getLinks();
|
||||
if (validateNull(links) || !id) return
|
||||
let cdata = links.find(f => f.id === id).attributes.attrs.cdata;
|
||||
let linkAttrs = Object.keys(linkAttr);
|
||||
setPropsNullValue(props.currSelect.attributes.attrs.cdata.attrs, cdata.attrs, ...linkAttrs)
|
||||
$message.warning("已同步其他连线的配置,请重新打开查看")
|
||||
methods.hideAttrConfig(false, '1');
|
||||
}
|
||||
87
src/flow/designer/components/node-menu.vue
Normal file
87
src/flow/designer/components/node-menu.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="flow-node-menu">
|
||||
<el-menu style="border-right: 0;">
|
||||
<template v-for="(node, index) in props.menuList" :key="index">
|
||||
<el-menu-item style="padding-top: 4px; padding-left: 14px;" v-if="isShowNode(node) && node.type !== HighNodeType.CHILD_FLOW">
|
||||
<el-tooltip :content="getNodeName(node)" placement="right">
|
||||
<div
|
||||
class="el-node-item"
|
||||
draggable="true"
|
||||
@dragstart="dragNode(node.type, props.type)"
|
||||
>
|
||||
<img :src="node.icon" alt="node">
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts" name="NodeMenu">
|
||||
import {HighNodeType} from '../config/type'
|
||||
import {validateNull} from "/@/utils/validate";
|
||||
|
||||
const $emit = defineEmits(["setDragInfo"]);
|
||||
const props = defineProps({
|
||||
menuList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
flowData: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
function isShowNode(node) {
|
||||
if (validateNull(props.flowData)) return true
|
||||
if (node.type !== HighNodeType.JOB && node.type !== HighNodeType.VIRTUAL) {
|
||||
return true
|
||||
}
|
||||
let isJobSeparated = props.flowData.attrs.isJobSeparated;
|
||||
return isJobSeparated === '1';
|
||||
}
|
||||
|
||||
function getNodeName(node) {
|
||||
return node.nodeName + (node.nodeDesc ? node.nodeDesc : '')
|
||||
}
|
||||
|
||||
// 开始拖拽
|
||||
function dragNode(type, belongTo) {
|
||||
$emit("setDragInfo", {
|
||||
type,
|
||||
belongTo
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
/*菜单间距*/
|
||||
.flow-node-menu {
|
||||
|
||||
.el-menu-item {
|
||||
padding: 11px!important;
|
||||
height: 40px!important;
|
||||
}
|
||||
|
||||
.el-node-item {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
color: #fff;
|
||||
border-radius: 5px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
cursor: move;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
color: #0960bd;
|
||||
outline: 1px dashed #0960bd;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
127
src/flow/designer/config/attr-config.ts
Normal file
127
src/flow/designer/config/attr-config.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import {deepClone} from "/@/utils/other";
|
||||
|
||||
const clazzAttr = {
|
||||
clazzes: [],
|
||||
}
|
||||
|
||||
const fieldsAttr = {
|
||||
formFieldPerms: [],
|
||||
formId: null,
|
||||
}
|
||||
|
||||
const nodeJobLinkAttr = {
|
||||
condGroups: [],
|
||||
httpMethod: null,
|
||||
httpParams: [],
|
||||
}
|
||||
|
||||
const subFlowAttr = {
|
||||
subFlowParams: [],
|
||||
startSubFlow: null,
|
||||
restartSubFlow: null,
|
||||
backParFlow: null,
|
||||
startSubMethod: null,
|
||||
restartSubMethod: null,
|
||||
backParMethod: null,
|
||||
}
|
||||
|
||||
const flowNodeAttr = {
|
||||
...deepClone(clazzAttr),
|
||||
...deepClone(nodeJobLinkAttr),
|
||||
...deepClone(fieldsAttr),
|
||||
...deepClone(subFlowAttr),
|
||||
}
|
||||
|
||||
const commonAttr = {
|
||||
jobBtns: null,
|
||||
carbonCopy: null,
|
||||
approveMethod: '1',
|
||||
ticketCompRate: 100,
|
||||
routeKeyVal: null,
|
||||
valType: null,
|
||||
...deepClone(flowNodeAttr),
|
||||
pcTodoUrl: null,
|
||||
subDefFlowId: null,
|
||||
subFlowVersion: '0',
|
||||
timeout: 0,
|
||||
sort: 1,
|
||||
}
|
||||
|
||||
export const startAttr = {
|
||||
...deepClone(commonAttr),
|
||||
rejectType: '0'
|
||||
}
|
||||
|
||||
export const syncNodeAttr = {
|
||||
...deepClone(commonAttr),
|
||||
nodeApproveMethod: '1',
|
||||
isAutoNext: '1',
|
||||
rejectType: '0',
|
||||
isContinue: '0',
|
||||
isAutoAudit: '0',
|
||||
isPassSame: '0'
|
||||
}
|
||||
|
||||
export const nodeAttr = {
|
||||
description: '',
|
||||
...deepClone(syncNodeAttr),
|
||||
}
|
||||
|
||||
export const gateAttr = {
|
||||
...deepClone(flowNodeAttr),
|
||||
nodeApproveMethod: '1',
|
||||
isAutoNext: '1',
|
||||
isAutoAudit: '1',
|
||||
isGateway: '1',
|
||||
}
|
||||
|
||||
const baseJobAttr = {
|
||||
...deepClone(nodeJobLinkAttr),
|
||||
valType: '-2',
|
||||
userKey: null,
|
||||
userKeyVal: null,
|
||||
isNowRun: '0',
|
||||
timeout: 0,
|
||||
isSkipRejected: '0',
|
||||
belongType: null,
|
||||
sort: 1,
|
||||
}
|
||||
|
||||
export const jobAttr = {
|
||||
jobName: '节点任务',
|
||||
...deepClone(baseJobAttr),
|
||||
distFlowNodeId: null,
|
||||
}
|
||||
|
||||
// currRunJobs
|
||||
export const syncJobAttr = {
|
||||
...deepClone(baseJobAttr),
|
||||
userKeyValName: null,
|
||||
roleUserId: [],
|
||||
}
|
||||
|
||||
export const endAttr = {
|
||||
...deepClone(commonAttr),
|
||||
isAutoAudit: '1',
|
||||
}
|
||||
|
||||
export const virtualAttr = {
|
||||
...deepClone(commonAttr),
|
||||
rejectType: '1'
|
||||
}
|
||||
|
||||
export const highAttr = {
|
||||
childFlowKey: null,
|
||||
childOrderId: null
|
||||
}
|
||||
|
||||
export const linkAttr = {
|
||||
...deepClone(nodeJobLinkAttr),
|
||||
valType: null,
|
||||
varKeyVal: null,
|
||||
}
|
||||
|
||||
export const laneAttr = {
|
||||
id: null,
|
||||
nodeName: null,
|
||||
}
|
||||
354
src/flow/designer/config/flow-config.ts
Normal file
354
src/flow/designer/config/flow-config.ts
Normal file
@@ -0,0 +1,354 @@
|
||||
import {nodeJobSvgIcons as nodeJobPath} from "/@/flow/designer/assets/svges/path";
|
||||
|
||||
const clazzAttr = {
|
||||
clazzes: [],
|
||||
}
|
||||
|
||||
export const flowAttr = {
|
||||
id: null,
|
||||
...clazzAttr,
|
||||
isIndependent: '0',
|
||||
allowJobLink: '0',
|
||||
isJobSeparated: '0',
|
||||
isSimpleMode: '1',
|
||||
connector: null,
|
||||
router: null,
|
||||
queryOrder: null,
|
||||
updateOrder: null,
|
||||
queryMethod: null,
|
||||
updateMethod: null,
|
||||
orderParams: [],
|
||||
flowName: null,
|
||||
flowKey: null,
|
||||
groupName: null,
|
||||
formId: null,
|
||||
fromType: '1',
|
||||
version: 1,
|
||||
status: '-1',
|
||||
remark: null,
|
||||
isNew: true,
|
||||
sort: 1
|
||||
}
|
||||
|
||||
export let flowConfig = {
|
||||
// ID类型
|
||||
// 1.uuid uuid 2.time_stamp 时间戳 3.sequence 序列 4.time_stamp_and_sequence 时间戳加序列 5.custom 自定义
|
||||
idType: ['time_stamp_and_sequence', 6],
|
||||
flowData: {
|
||||
// null时init
|
||||
graph: null,
|
||||
nodeList: [],
|
||||
linkList: [],
|
||||
attrs: flowAttr,
|
||||
},
|
||||
mobileConfig: {
|
||||
mobilePrefix: "appdata",
|
||||
mobileCode: "jf320920",
|
||||
},
|
||||
globalConfig: {
|
||||
isHideShortcut: '0',
|
||||
allowJobLink: '0',
|
||||
isJobSeparated: '0',
|
||||
isSimpleMode: '1',
|
||||
connectors: [{value: "normal", label: "简单"}, {value: "rounded", label: "圆角"}, {
|
||||
value: "jumpover",
|
||||
label: "跳线"
|
||||
}, {value: "smooth", label: "平滑"}],
|
||||
routers: [{value: "normal", label: "简单"}, {value: "manhattan", label: "智能正交"}, {
|
||||
value: "metro",
|
||||
label: "智能地铁线"
|
||||
}, {value: "orthogonal", label: "垂直直角"}, {value: "oneSide", label: "受限正交"}],
|
||||
rankDirs: [{value: "TB", label: "上下"}, {value: "BT", label: "下上"}, {value: "LR", label: "左右"}, {
|
||||
value: "RL",
|
||||
label: "右左"
|
||||
}],
|
||||
defaultAutoLayoutName: "TB",
|
||||
defaultConnectorName: "rounded",
|
||||
defaultRouterName: "normal",
|
||||
maxNodeJobNum: 50
|
||||
},
|
||||
gridConfig: {
|
||||
showGrid: false,
|
||||
showGridText: "显示网格",
|
||||
showGridIcon: "SwitchButton",
|
||||
gridSize: 1
|
||||
},
|
||||
defaultStyle: {
|
||||
containerScale: {
|
||||
init: 1
|
||||
}
|
||||
},
|
||||
viewShortcut: {
|
||||
paper: {
|
||||
codeName: '鼠标滚动或点击画布拖拽或小地图',
|
||||
shortcutName: '拖动画布'
|
||||
},
|
||||
flow: {
|
||||
codeName: '鼠标点击画布隐藏节点信息',
|
||||
shortcutName: '隐藏节点信息'
|
||||
},
|
||||
node: {
|
||||
codeName: '鼠标放节点上即可查看',
|
||||
shortcutName: '查看节点信息'
|
||||
},
|
||||
link: {
|
||||
codeName: '鼠标放连线上即可查看',
|
||||
shortcutName: '查看连线信息'
|
||||
},
|
||||
zoomInTool: {
|
||||
codeName: '画布右上角',
|
||||
shortcutName: '放大工具'
|
||||
},
|
||||
zoomOutTool: {
|
||||
codeName: '画布右上角',
|
||||
shortcutName: '缩小工具'
|
||||
}
|
||||
},
|
||||
shortcut: {
|
||||
note: {
|
||||
codeName: '图中节点、连线均可拖拽(专业模式),缩放大小',
|
||||
shortcutName: '简约但不简单'
|
||||
},
|
||||
flow: {
|
||||
codeName: '左上角操作栏',
|
||||
shortcutName: '切换简单模式与专业模式'
|
||||
},
|
||||
flow2: {
|
||||
codeName: '左上角操作栏',
|
||||
shortcutName: '设置流程属性'
|
||||
},
|
||||
link: {
|
||||
codeName: '左上角操作栏',
|
||||
shortcutName: '设置连线、路由、布局'
|
||||
},
|
||||
paper: {
|
||||
codeName: '鼠标滚动或点击画布拖拽或小地图',
|
||||
shortcutName: '拖动画布'
|
||||
},
|
||||
node: {
|
||||
codeName: '从左侧节点菜单栏拖拽节点(专业模式)',
|
||||
shortcutName: '新增加点'
|
||||
},
|
||||
node1: {
|
||||
codeName: '鼠标点击节点拖动右下角灰色小圈',
|
||||
shortcutName: '缩放节点大小'
|
||||
},
|
||||
node2: {
|
||||
codeName: '鼠标放节点边缘显示(+)开始拖出连线',
|
||||
shortcutName: '节点连线'
|
||||
},
|
||||
node3: {
|
||||
codeName: '鼠标放节点文本上开始拖动节点',
|
||||
shortcutName: '拖拽节点'
|
||||
},
|
||||
node4: {
|
||||
codeName: '鼠标放节点上双击或右键菜单(专业模式)设置',
|
||||
shortcutName: '设置节点属性'
|
||||
},
|
||||
node41: {
|
||||
codeName: '鼠标放节点的任务项上单击(节点任务不分离时)设置',
|
||||
shortcutName: '设置任务属性'
|
||||
},
|
||||
node5: {
|
||||
codeName: '鼠标放节点上右键菜单删除(专业模式)或点击再点X删除',
|
||||
shortcutName: '删除节点'
|
||||
},
|
||||
link2: {
|
||||
codeName: '鼠标放连线上点击增加拖拽点拖动(专业模式)',
|
||||
shortcutName: '拖拽连线'
|
||||
},
|
||||
link3: {
|
||||
codeName: '鼠标放连线拖拽点上再次点击删除(专业模式)',
|
||||
shortcutName: '删除拖拽点'
|
||||
},
|
||||
link4: {
|
||||
codeName: '鼠标放连线上双击(简单模式)或右键菜单(专业模式)设置',
|
||||
shortcutName: '设置连线属性'
|
||||
},
|
||||
link5: {
|
||||
codeName: '鼠标放连线上点X删除或右键菜单(专业模式)删除',
|
||||
shortcutName: '删除连线'
|
||||
},
|
||||
zoomInTool: {
|
||||
codeName: '画布右上角',
|
||||
shortcutName: '放大工具'
|
||||
},
|
||||
zoomOutTool: {
|
||||
codeName: '画布右上角',
|
||||
shortcutName: '缩小工具'
|
||||
}
|
||||
},
|
||||
contextMenu: {
|
||||
container: {
|
||||
menuName: 'flow-menu',
|
||||
axis: {
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
menulists: [
|
||||
{
|
||||
fnHandler: 'flowInfo',
|
||||
icoName: 'iconfont icon-xianshimima',
|
||||
btnName: '流程图信息'
|
||||
},
|
||||
{
|
||||
fnHandler: 'paste',
|
||||
icoName: 'iconfont icon-fuzhiyemian',
|
||||
btnName: '粘贴'
|
||||
}
|
||||
]
|
||||
},
|
||||
node: {
|
||||
menuName: 'node-menu',
|
||||
axis: {
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
menulists: [
|
||||
{
|
||||
fnHandler: 'setNodeAttr',
|
||||
icoName: 'iconfont icon-quanjushezhi_o',
|
||||
btnName: '设置属性'
|
||||
},
|
||||
{
|
||||
fnHandler: 'setConnectNode',
|
||||
icoName: 'iconfont icon-shuxingtu',
|
||||
btnName: '连接节点'
|
||||
},
|
||||
{
|
||||
fnHandler: 'copyNode',
|
||||
icoName: 'iconfont icon-fuzhiyemian',
|
||||
btnName: '复制节点'
|
||||
},
|
||||
{
|
||||
fnHandler: 'deleteNode',
|
||||
icoName: 'iconfont icon-yincangmima',
|
||||
btnName: '删除节点'
|
||||
}
|
||||
]
|
||||
},
|
||||
nodeConnect: {
|
||||
menuName: 'node-connect-menu',
|
||||
axis: {
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
menulists: [
|
||||
{
|
||||
fnHandler: 'setConnectNode',
|
||||
icon: nodeJobPath.linkIcon,
|
||||
icoName: 'iconfont icon-tuodong',
|
||||
btnName: '连接节点',
|
||||
nodeConnect: true,
|
||||
},
|
||||
{
|
||||
fnHandler: 'setSerialNode',
|
||||
icon: nodeJobPath.serial,
|
||||
icoName: 'iconfont icon-icon-',
|
||||
btnName: '串行节点',
|
||||
nodeConnect: true,
|
||||
},
|
||||
{
|
||||
fnHandler: 'setParallelNode',
|
||||
icon: nodeJobPath.parallel,
|
||||
icoName: 'iconfont icon-shuxingtu',
|
||||
btnName: '并行节点',
|
||||
nodeConnect: true,
|
||||
},
|
||||
{
|
||||
fnHandler: 'setSerialGate',
|
||||
icon: nodeJobPath.serialGate,
|
||||
icoName: 'iconfont icon-shuaxin',
|
||||
btnName: '串行网关',
|
||||
nodeConnect: true,
|
||||
},
|
||||
{
|
||||
fnHandler: 'setParallelGate',
|
||||
icon: nodeJobPath.parallelGate,
|
||||
icoName: 'iconfont icon-tuodong',
|
||||
btnName: '并行网关',
|
||||
nodeConnect: true,
|
||||
}
|
||||
]
|
||||
},
|
||||
link: {
|
||||
menuName: 'link-menu',
|
||||
axis: {
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
menulists: [
|
||||
{
|
||||
fnHandler: 'setLinkAttr',
|
||||
icoName: 'iconfont icon-quanjushezhi_o',
|
||||
btnName: '设置属性'
|
||||
},
|
||||
{
|
||||
fnHandler: 'modifySourceNode',
|
||||
icoName: 'iconfont icon-step',
|
||||
icoStyle: 'font-size: 13px',
|
||||
btnName: '修改起点'
|
||||
},
|
||||
{
|
||||
fnHandler: 'modifyTargetNode',
|
||||
icoName: 'iconfont icon-radio-off-full',
|
||||
icoStyle: 'font-size: 13px',
|
||||
btnName: '修改终点'
|
||||
},
|
||||
{
|
||||
fnHandler: 'deleteLink',
|
||||
icoName: 'iconfont icon-yincangmima',
|
||||
btnName: '删除连线'
|
||||
}
|
||||
]
|
||||
},
|
||||
nodeView: {
|
||||
menuName: 'node-menu',
|
||||
axis: {
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
menulists: [
|
||||
{
|
||||
fnHandler: '',
|
||||
icoName: 'iconfont icon-shuaxin',
|
||||
btnName: '节点名称: '
|
||||
},
|
||||
{
|
||||
fnHandler: '',
|
||||
icoName: 'iconfont icon-xianshimima',
|
||||
btnName: '审批开始时间: '
|
||||
},
|
||||
{
|
||||
fnHandler: '',
|
||||
icoName: 'iconfont icon-gerenzhongxin',
|
||||
btnName: '参与者: '
|
||||
},
|
||||
{
|
||||
fnHandler: '',
|
||||
icoName: 'iconfont icon-icon-',
|
||||
btnName: '审批人: '
|
||||
},
|
||||
{
|
||||
fnHandler: '',
|
||||
icoName: 'iconfont icon-tongzhi1',
|
||||
btnName: '审批备注: '
|
||||
}
|
||||
]
|
||||
},
|
||||
linkView: {
|
||||
menuName: 'link-menu',
|
||||
axis: {
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
menulists: [
|
||||
{
|
||||
fnHandler: '',
|
||||
icoName: 'iconfont icon-shuxingtu',
|
||||
btnName: '连线条件: '
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/flow/designer/config/menu-config.ts
Normal file
70
src/flow/designer/config/menu-config.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {CommonNodeType, HighNodeType, LaneNodeType} from './type'
|
||||
import {nodeJobSvgIcons} from "../assets/svges";
|
||||
|
||||
export const commonNodes = [
|
||||
{
|
||||
type: CommonNodeType.START,
|
||||
nodeName: '开始',
|
||||
icon: nodeJobSvgIcons.startMenu
|
||||
},
|
||||
{
|
||||
type: CommonNodeType.SERIAL,
|
||||
nodeName: '串行节点',
|
||||
nodeDesc: '(表示流程同时只能流转到一个串行分支)',
|
||||
icon: nodeJobSvgIcons.serial
|
||||
},
|
||||
{
|
||||
type: CommonNodeType.PARALLEL,
|
||||
nodeName: '并行节点',
|
||||
nodeDesc: '(表示流程同时可以流转到多个并行分支)',
|
||||
icon: nodeJobSvgIcons.parallel
|
||||
},
|
||||
{
|
||||
type: CommonNodeType.END,
|
||||
nodeName: '结束',
|
||||
icon: nodeJobSvgIcons.endMenu
|
||||
}
|
||||
];
|
||||
|
||||
export const highNodes = [
|
||||
{
|
||||
type: HighNodeType.VIRTUAL,
|
||||
nodeName: '虚拟节点',
|
||||
nodeDesc: '(可选的自由节点,不常用)',
|
||||
icon: nodeJobSvgIcons.virtual
|
||||
},
|
||||
{
|
||||
type: HighNodeType.JOB,
|
||||
nodeName: '节点任务',
|
||||
nodeDesc: '(可选的辅助节点,不常用)',
|
||||
icon: nodeJobSvgIcons.job
|
||||
},
|
||||
{
|
||||
type: CommonNodeType.SERIAL,
|
||||
nodeName: '串行网关',
|
||||
icon: nodeJobSvgIcons.serialGate
|
||||
},
|
||||
{
|
||||
type: CommonNodeType.PARALLEL,
|
||||
nodeName: '并行网关',
|
||||
icon: nodeJobSvgIcons.parallelGate
|
||||
},
|
||||
{
|
||||
type: HighNodeType.CHILD_FLOW,
|
||||
nodeName: '子流程',
|
||||
icon: 'set-up'
|
||||
}
|
||||
];
|
||||
|
||||
export const laneNodes = [
|
||||
{
|
||||
type: LaneNodeType.Y_LANE,
|
||||
nodeName: '纵向泳道',
|
||||
icon: nodeJobSvgIcons.yLaneMenu
|
||||
},
|
||||
{
|
||||
type: LaneNodeType.X_LANE,
|
||||
nodeName: '横向泳道',
|
||||
icon: nodeJobSvgIcons.xLaneMenu
|
||||
}
|
||||
];
|
||||
110
src/flow/designer/config/node-config.ts
Normal file
110
src/flow/designer/config/node-config.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { CommonNodeType, HighNodeType, LaneNodeType } from './type'
|
||||
import {
|
||||
endAttr, gateAttr,
|
||||
jobAttr,
|
||||
laneAttr,
|
||||
linkAttr,
|
||||
nodeAttr, startAttr,
|
||||
virtualAttr
|
||||
} from "./attr-config";
|
||||
import JsonflowDesign from "@jackrolling/jsonflow3"
|
||||
import {deepClone} from "/@/utils/other";
|
||||
|
||||
export function initNodeShapes() {
|
||||
|
||||
window._defShapes = JsonflowDesign.shapes.initDefShapes();
|
||||
let initShapes = JsonflowDesign.shapes.initShapes(true);
|
||||
|
||||
let cdata = window._defShapes.cdata
|
||||
|
||||
initShapes.start.attr(cdata, {
|
||||
type: CommonNodeType.START,
|
||||
attrs: deepClone(startAttr),
|
||||
defJob: deepClone(jobAttr),
|
||||
})
|
||||
|
||||
initShapes.serial.attr(cdata, {
|
||||
type: CommonNodeType.SERIAL,
|
||||
attrs: deepClone(nodeAttr),
|
||||
defJob: deepClone(jobAttr),
|
||||
})
|
||||
|
||||
initShapes.parallel.attr(cdata, {
|
||||
type: CommonNodeType.PARALLEL,
|
||||
attrs: deepClone(nodeAttr),
|
||||
defJob: deepClone(jobAttr),
|
||||
})
|
||||
|
||||
initShapes.serialGate.attr(cdata, {
|
||||
type: CommonNodeType.SERIAL,
|
||||
attrs: deepClone(gateAttr),
|
||||
defJob: deepClone(jobAttr)
|
||||
})
|
||||
|
||||
initShapes.parallelGate.attr(cdata, {
|
||||
type: CommonNodeType.PARALLEL,
|
||||
attrs: deepClone(gateAttr),
|
||||
defJob: deepClone(jobAttr)
|
||||
})
|
||||
|
||||
initShapes.end.attr(cdata, {
|
||||
type: CommonNodeType.END,
|
||||
attrs: deepClone(endAttr),
|
||||
defJob: deepClone(jobAttr),
|
||||
})
|
||||
|
||||
const commonNodes = [
|
||||
initShapes.start,
|
||||
initShapes.serial,
|
||||
initShapes.parallel,
|
||||
initShapes.end
|
||||
];
|
||||
|
||||
initShapes.virtual.attr(cdata, {
|
||||
type: HighNodeType.VIRTUAL,
|
||||
attrs: deepClone(virtualAttr),
|
||||
defJob: deepClone(jobAttr),
|
||||
})
|
||||
|
||||
initShapes.job.attr(cdata, {
|
||||
type: HighNodeType.JOB,
|
||||
defJob: deepClone(jobAttr),
|
||||
})
|
||||
|
||||
const highNodes = [
|
||||
initShapes.serialGate,
|
||||
initShapes.parallelGate,
|
||||
initShapes.virtual,
|
||||
initShapes.job
|
||||
/*,
|
||||
{ cdata: {
|
||||
type: HighNodeType.CHILD_FLOW,
|
||||
attrs: deepClone(highAttr)
|
||||
}
|
||||
}*/
|
||||
];
|
||||
|
||||
initShapes.xLane.attr(cdata, {
|
||||
type: LaneNodeType.X_LANE,
|
||||
attrs: deepClone(laneAttr)
|
||||
})
|
||||
|
||||
initShapes.yLane.attr(cdata, {
|
||||
type: LaneNodeType.Y_LANE,
|
||||
attrs: deepClone(laneAttr)
|
||||
})
|
||||
|
||||
const laneNodes = [
|
||||
initShapes.xLane,
|
||||
initShapes.yLane
|
||||
];
|
||||
|
||||
const defLink = initShapes.link.attr(cdata, {
|
||||
type: CommonNodeType.LINK,
|
||||
attrs: deepClone(linkAttr),
|
||||
})
|
||||
|
||||
return {commonNodes, highNodes, laneNodes, defLink}
|
||||
}
|
||||
|
||||
window._nodeConfig = { initNodeShapes }
|
||||
18
src/flow/designer/config/type.ts
Normal file
18
src/flow/designer/config/type.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export const CommonNodeType = {
|
||||
START : 'start',
|
||||
SERIAL : 'serial',
|
||||
PARALLEL : 'parallel',
|
||||
END : 'end',
|
||||
LINK : 'link'
|
||||
}
|
||||
|
||||
export const HighNodeType = {
|
||||
CHILD_FLOW : 'child_flow',
|
||||
VIRTUAL : 'virtual',
|
||||
JOB : 'job'
|
||||
}
|
||||
|
||||
export const LaneNodeType = {
|
||||
X_LANE : 'x_lane',
|
||||
Y_LANE : 'y_lane'
|
||||
}
|
||||
110
src/flow/designer/utils/common.ts
Normal file
110
src/flow/designer/utils/common.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { flowConfig } from '../config/flow-config.ts'
|
||||
|
||||
export let utils = {
|
||||
seqNo: 1,
|
||||
getId: function() {
|
||||
let idType = flowConfig.idType;
|
||||
if (typeof idType == 'string') {
|
||||
if (idType === 'uuid') {
|
||||
return this.getUUID();
|
||||
} else if (idType === 'time_stamp') {
|
||||
return this.getTimeStamp();
|
||||
}
|
||||
} else if (idType instanceof Array) {
|
||||
if (idType[0] === 'sequence') {
|
||||
return this.getSequence(idType[1]);
|
||||
} else if (idType[0] === 'time_stamp_and_sequence') {
|
||||
return this.getTimeStampAndSequence(idType[1]);
|
||||
} else if (idType[0] === 'custom') {
|
||||
return idType[1]();
|
||||
}
|
||||
}
|
||||
},
|
||||
getUUID: function() {
|
||||
let s = [];
|
||||
let hexDigits = "0123456789abcdef";
|
||||
for(let i = 0; i < 36; i++) {
|
||||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||
}
|
||||
s[14] = "4";
|
||||
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
|
||||
s[8] = s[13] = s[18] = s[23] = "-";
|
||||
|
||||
let uuid = s.join("");
|
||||
return uuid.replace(/-/g, '');
|
||||
},
|
||||
getTimeStamp: function() {
|
||||
return new Date().getTime();
|
||||
},
|
||||
getSequence: function(seqNoLength) {
|
||||
let zeroStr = new Array(seqNoLength).fill('0').join('');
|
||||
return (zeroStr + (this.seqNo++)).slice(-seqNoLength);
|
||||
},
|
||||
getTimeStampAndSequence: function(seqNoLength) {
|
||||
return this.getTimeStamp() + this.getSequence(seqNoLength);
|
||||
},
|
||||
add: function(a, b) {
|
||||
let c, d, e;
|
||||
try {
|
||||
c = a.toString().split(".")[1].length;
|
||||
} catch (f) {
|
||||
c = 0;
|
||||
}
|
||||
try {
|
||||
d = b.toString().split(".")[1].length;
|
||||
} catch (f) {
|
||||
d = 0;
|
||||
}
|
||||
return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) + this.mul(b, e)) / e;
|
||||
},
|
||||
sub: function(a, b) {
|
||||
let c, d, e;
|
||||
try {
|
||||
c = a.toString().split(".")[1].length;
|
||||
} catch (f) {
|
||||
c = 0;
|
||||
}
|
||||
try {
|
||||
d = b.toString().split(".")[1].length;
|
||||
} catch (f) {
|
||||
d = 0;
|
||||
}
|
||||
return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) - this.mul(b, e)) / e;
|
||||
},
|
||||
mul: function(a, b) {
|
||||
let c = 0, d = a.toString(), e = b.toString();
|
||||
try {
|
||||
c += d.split(".")[1].length;
|
||||
} catch (f) {}
|
||||
try {
|
||||
c += e.split(".")[1].length;
|
||||
} catch (f) {}
|
||||
return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
|
||||
},
|
||||
div: function(a, b) {
|
||||
let c, d, e = 0, f = 0;
|
||||
try {
|
||||
e = a.toString().split(".")[1].length;
|
||||
} catch (g) {}
|
||||
try {
|
||||
f = b.toString().split(".")[1].length;
|
||||
} catch (g) {}
|
||||
return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), this.mul(c / d, Math.pow(10, f - e));
|
||||
},
|
||||
deepClone(obj) {
|
||||
let newObj;
|
||||
try {
|
||||
newObj = obj.push ? [] : {};
|
||||
} catch (error) {
|
||||
newObj = {};
|
||||
}
|
||||
for (let attr in obj) {
|
||||
if (obj[attr] && typeof obj[attr] === 'object') {
|
||||
newObj[attr] = this.deepClone(obj[attr]);
|
||||
} else {
|
||||
newObj[attr] = obj[attr];
|
||||
}
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
};
|
||||
84
src/flow/designer/views/json-view.vue
Normal file
84
src/flow/designer/views/json-view.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer
|
||||
class="flow-header-drawer"
|
||||
title="导入导出"
|
||||
direction="rtl"
|
||||
append-to-body
|
||||
:size="600"
|
||||
v-model="data.viewJsonVisible"
|
||||
@close="methods.onClose">
|
||||
<div style="padding: 24px">
|
||||
<div>当前JSON数据:</div>
|
||||
<json-view
|
||||
:value="data.flowData"
|
||||
:expand-depth=3
|
||||
boxed
|
||||
copyable/>
|
||||
|
||||
<div style="margin-top: 12px;">导入导出数据:</div>
|
||||
<el-input type="textarea" minlength="10" v-model="data.flowDataJson" @change="methods.editFlowDataJson"/>
|
||||
|
||||
<el-divider/>
|
||||
<el-button @click="methods.tempSave" :style="{ marginRight: '8px' }">导出数据</el-button>
|
||||
<el-button @click="methods.onLoad" type="primary">导入数据</el-button>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="JsonView">
|
||||
import JsonView from "vue-json-viewer"
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useMessage} from "/@/hooks/message";
|
||||
import {stringifyRemoveNullKey} from "../../index";
|
||||
|
||||
const {t} = useI18n();
|
||||
const $message = useMessage();
|
||||
const $emit = defineEmits(["loadFlow"]);
|
||||
|
||||
const data = reactive({
|
||||
viewJsonVisible: false,
|
||||
flowData: {},
|
||||
flowDataJson: ""
|
||||
})
|
||||
|
||||
const methods = {
|
||||
open(flowData) {
|
||||
flowData = stringifyRemoveNullKey(flowData);
|
||||
data.flowData = !window.isWebTest ? {contact: "演示环境不能操作,如需了解联系我们"}: JSON.parse(flowData);
|
||||
data.viewJsonVisible = true;
|
||||
},
|
||||
onClose() {
|
||||
data.viewJsonVisible = false;
|
||||
},
|
||||
// 编辑框
|
||||
editFlowDataJson(value) {
|
||||
data.flowDataJson = value;
|
||||
},
|
||||
// 导出数据
|
||||
tempSave() {
|
||||
if (!data.flowData.attrs) return
|
||||
let tempObj = Object.assign({}, data.flowData);
|
||||
data.flowDataJson = stringifyRemoveNullKey(tempObj);
|
||||
},
|
||||
// 导入数据
|
||||
onLoad() {
|
||||
if (!data.flowDataJson) {
|
||||
$message.warning("请先导入数据")
|
||||
return
|
||||
}
|
||||
$emit('loadFlow', JSON.parse(data.flowDataJson));
|
||||
methods.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
open: methods.open
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../flow/components/style/flow-drawer.scss";
|
||||
</style>
|
||||
109
src/flow/designer/views/setting.vue
Normal file
109
src/flow/designer/views/setting.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer
|
||||
class="flow-header-drawer"
|
||||
title="画布设置"
|
||||
direction="rtl"
|
||||
append-to-body
|
||||
:size="600"
|
||||
v-if="data.settingVisible"
|
||||
v-model="data.settingVisible"
|
||||
style="z-index: 1001"
|
||||
@close="methods.close">
|
||||
<el-form
|
||||
class="flow-drawer-form"
|
||||
:model="data.settingForm"
|
||||
label-position="right">
|
||||
<el-divider content-position="left">画布</el-divider>
|
||||
<el-form-item label="网格大小">
|
||||
<el-slider
|
||||
:min="1"
|
||||
:max="20"
|
||||
v-model="data.gridConfig.gridSize"
|
||||
@change="methods.setGridSize"/>
|
||||
</el-form-item>
|
||||
<el-divider content-position="left">连线</el-divider>
|
||||
<!-- <el-form-item label="是否允许节点与任务分离显示">
|
||||
<el-switch
|
||||
v-model="data.globalConfig.isJobSeparated"
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
@change="methods.toggleJobSeparated"/>
|
||||
</el-form-item>-->
|
||||
<el-tooltip content="当节点与任务分离显示时,该设置在专业模式下生效" placement="left">
|
||||
<el-form-item label="是否允许任务连线到其他节点">
|
||||
<el-switch
|
||||
v-model="data.globalConfig.allowJobLink"
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
@change="methods.toggleAllowJobLink"/>
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
<el-divider content-position="left">样式</el-divider>
|
||||
<el-form-item label="是否切换节点UI图形显示效果">
|
||||
<el-switch
|
||||
v-model="data.globalConfig.isJobSeparated"
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
@change="methods.toggleJobSeparated"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowSetting">
|
||||
import {flowConfig} from '../config/flow-config'
|
||||
import * as nodeConfig from "/@/flow/designer/config/node-config";
|
||||
|
||||
const $emit = defineEmits(["flowSeparated"]);
|
||||
|
||||
const data = reactive({
|
||||
settingVisible: false,
|
||||
settingForm: {},
|
||||
globalConfig: flowConfig.globalConfig,
|
||||
gridConfig: flowConfig.gridConfig
|
||||
})
|
||||
|
||||
const methods = {
|
||||
open() {
|
||||
data.settingVisible = true
|
||||
},
|
||||
close() {
|
||||
data.settingVisible = false
|
||||
},
|
||||
toggleAllowJobLink(flag) {
|
||||
data.globalConfig.allowJobLink = flag
|
||||
flowConfig.globalConfig.allowJobLink = flag
|
||||
},
|
||||
toggleJobSeparated(flag) {
|
||||
data.globalConfig.isJobSeparated = flag
|
||||
flowConfig.globalConfig.isJobSeparated = flag
|
||||
$emit('flowSeparated', flag);
|
||||
},
|
||||
setGridSize(v) {
|
||||
data.gridConfig.gridSize = v
|
||||
window._jfOperate.resetGridSize(v)
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
open: methods.open
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "../../../flow/components/style/flow-drawer.scss";
|
||||
|
||||
.flow-drawer-form {
|
||||
/*属性面板*/
|
||||
.el-form-item {
|
||||
margin: 0 40px 10px;
|
||||
}
|
||||
|
||||
.el-form-item .el-form-item__content {
|
||||
margin-left: 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
87
src/flow/designer/views/shortcut.vue
Normal file
87
src/flow/designer/views/shortcut.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="快捷入门"
|
||||
width="60%"
|
||||
append-to-body
|
||||
top="5vh"
|
||||
v-model="data.modalVisible">
|
||||
<el-table
|
||||
row-key="code"
|
||||
:data="data.dataSource">
|
||||
<el-table-column
|
||||
v-for="item in data.columns"
|
||||
:key="item.dataIndex"
|
||||
:label="item.title"
|
||||
:prop="item.key"
|
||||
style="width: 100%">
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="methods.cancel">取 消</el-button>
|
||||
<el-button type="primary" @click="methods.saveSetting">确 定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="FlowShortcut">
|
||||
|
||||
const props = defineProps({
|
||||
shortcut: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
const data = reactive({
|
||||
modalVisible: false,
|
||||
columns: [
|
||||
{
|
||||
title: '功能',
|
||||
align: 'center',
|
||||
key: 'shortcutName',
|
||||
dataIndex: 'shortcutName',
|
||||
width: '50%'
|
||||
},
|
||||
{
|
||||
title: '快捷入门',
|
||||
align: 'center',
|
||||
key: 'codeName',
|
||||
dataIndex: 'codeName',
|
||||
width: '50%'
|
||||
}
|
||||
],
|
||||
dataSource: []
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
let obj = Object.assign({}, props.shortcut)
|
||||
for (let k in obj) {
|
||||
data.dataSource.push(obj[k])
|
||||
}
|
||||
})
|
||||
|
||||
const methods = {
|
||||
open() {
|
||||
data.modalVisible = true
|
||||
},
|
||||
close() {
|
||||
data.modalVisible = false
|
||||
},
|
||||
saveSetting() {
|
||||
methods.close()
|
||||
},
|
||||
cancel() {
|
||||
methods.close()
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
open: methods.open
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
Reference in New Issue
Block a user