528 lines
22 KiB
Vue
528 lines
22 KiB
Vue
<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>
|