This commit is contained in:
吴红兵
2025-12-02 10:37:49 +08:00
commit 1f645dad3e
1183 changed files with 147673 additions and 0 deletions

View 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>