组件用于创建和编辑复杂的条件规则,支持添加、删除条件和子条件,以及选择不同的条件类型。
可实现json数据和页面显示的转换。
代码实现 :
index.vue:
<template>
<div class="allany-container">
<div class="control-bar">
<el-select v-model="pipe.condition" style="width: 200px; margin-right: 16px;" :disabled="disabled">
<el-option label="满足以下所有条件" value="all"/>
<el-option label="满足以下任一条件" value="any"/>
<el-option label="不包含以下条件" value="not"/>
</el-select>
<el-button v-if="!disabled" type="primary" @click="addCondition('condition')">添加条件</el-button>
<el-button v-if="!disabled" type="success" @click="addCondition('all_any')">添加子条件</el-button>
<el-button v-if=" !disabled" type="danger" :icon="Delete" circle @click="delSelf"/>
</div>
<div class="conditions-wrapper">
<!-- 侧边显示条 -->
<div :class="`conditions-wrapper-${pipe.condition}`"></div>
<div class="conditions-wrapper--conditions">
<div v-for="(child, idx) in pipe.children" :key="idx" class="conditions-wrapper--condition">
<biz-rule-all-any v-if="child.type === 'all_any'" :pipe="child" :attrOptions="attrOptions"
:disabled="disabled" @delRule="handleDelRule(idx,child)"/>
<biz-rule-condition v-else-if="child.type === 'condition'" :pipe="child" :attrOptions="attrOptions"
:disabled="disabled" @delRule="handleDelCondition(idx,child)"/>
</div>
</div>
</div>
</div>
</template>
<script setup>
import {ref, watch} from 'vue';
import BizRuleCondition from './BizRuleCondition.vue';
import {Delete} from "@element-plus/icons-vue";
import {deepClone} from "@/utils.js";
defineOptions({
name: 'BizRuleAllAny'
})
const emit = defineEmits(['delRule']);
const props = defineProps({
pipe: {
type: Object,
default: () => ({
type: 'all_any',
condition: 'all',
children: [],
})
},
attrOptions: {
type: Array,
default: () => {
return []
}
},
disabled: {
type: Boolean,
default: false
}
});
const pipe = ref(props.pipe);
function addCondition(type) {
if (type === 'all_any') {
pipe.value.children.push({
type: 'all_any',
condition: 'all',
children: [],
});
} else if (type === 'condition') {
pipe.value.children.push({
type: 'condition',
name: '',
operator: 'eq',
value: '',
val_type: 'string',
});
}
}
function delSelf() {
emit('delRule')
}
// 删除条件组
const handleDelRule = (idx,child) => {
pipe.value.children.splice(idx, 1);
}
// 删除条件组中的子数据
const handleDelCondition = (idx,child) => {
pipe.value.children.splice(idx, 1);
}
</script>
<style scoped lang="scss">
.allany-container {
.control-bar {
display: flex;
flex-direction: row;
}
.conditions-wrapper {
display: flex;
flex-direction: row;
}
.conditions-wrapper-all {
width: 4px;
margin: 5px 20px 0;
border-radius: 5px;
transition: background-color 400ms;
background-color: #67C23A;
&:hover {
background-color: #529b2e;
}
}
.conditions-wrapper-any {
width: 4px;
margin: 5px 20px 0;
border-radius: 5px;
transition: background-color 400ms;
background-color: #E6A23C;
&:hover {
background-color: #b88230;
}
}
.conditions-wrapper-not {
width: 4px;
margin: 5px 20px 0;
border-radius: 5px;
transition: background-color 400ms;
background-color: rgb(245, 245, 245);
&:hover {
background-color: rgb(144, 147, 153);
}
}
.conditions-wrapper--conditions {
display: flex;
flex-direction: column;
}
.conditions-wrapper--condition {
padding-top: 15px;
}
}
</style>
BizRuleCondition.vue:
<template>
<div class="bizrulecondition-container">
<el-select v-model="pipe.name" placeholder="字段名称" style="width: 150px; margin-right: 16px;" clearable :disabled="disabled">
<el-option v-for="item in attrOptions" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
<el-select v-model="pipe.operator" style="width: 90px; margin-right: 16px;" :disabled="disabled">
<el-option label="==" value="eq"/>
<el-option label="!=" value="neq"/>
<el-option label="<" value="lt"/>
<el-option label=">" value="gt"/>
<el-option label="<=" value="lte"/>
<el-option label=">=" value="gte"/>
<el-option label="in" value="in"/>
<el-option label="not in" value="not_in"/>
</el-select>
<el-badge
:value="pipe.val_type === 'string' ? '字符串' : '数字'"
:type="pipe.val_type === 'string' ? 'info' : 'success'"
@click.native="switchVarType($event, pipe)"
style="margin-right: 50px;"
:disabled="disabled"
>
<el-input
v-model="pipe.value"
placeholder="字段值"
style="width: 150px;"
clearable
:disabled="disabled"
/>
</el-badge>
<el-button type="danger" :icon="Delete" circle @click="delSelf" :disabled="disabled"/>
</div>
</template>
<script setup>
import {ref, defineProps, watch} from 'vue';
import {Delete} from "@element-plus/icons-vue";
import {deepClone} from "@/utils.js";
const emit = defineEmits(['delRule']);
const props = defineProps({
pipe: Object,
attrOptions:Array,
disabled:Boolean
});
const pipe = ref({});
watch(() => props.pipe, (newData) => {
if (!newData) return
pipe.value = deepClone(newData)
}, {
deep: true,
immediate: true
})
function switchVarType(e, kv) {
if (String(e.target.tagName).toUpperCase() === 'SUP') {
kv.val_type = kv.val_type === 'number' ? 'string' : 'number';
}
}
function delSelf() {
emit('delRule')
}
</script>
<style lang="scss" scoped>
.bizrulecondition-container {
display: flex;
flex-direction: row;
.el-badge__content {
transition: 400ms;
user-select: none;
}
.el-badge__content:hover {
cursor: pointer;
}
}
</style>
BizRuleAdapter.js:
<template>
<div class="bizrulecondition-container">
<el-select v-model="pipe.name" placeholder="字段名称" style="width: 150px; margin-right: 16px;" clearable :disabled="disabled">
<el-option v-for="item in attrOptions" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
<el-select v-model="pipe.operator" style="width: 90px; margin-right: 16px;" :disabled="disabled">
<el-option label="==" value="eq"/>
<el-option label="!=" value="neq"/>
<el-option label="<" value="lt"/>
<el-option label=">" value="gt"/>
<el-option label="<=" value="lte"/>
<el-option label=">=" value="gte"/>
<el-option label="in" value="in"/>
<el-option label="not in" value="not_in"/>
</el-select>
<el-badge
:value="pipe.val_type === 'string' ? '字符串' : '数字'"
:type="pipe.val_type === 'string' ? 'info' : 'success'"
@click.native="switchVarType($event, pipe)"
style="margin-right: 50px;"
:disabled="disabled"
>
<el-input
v-model="pipe.value"
placeholder="字段值"
style="width: 150px;"
clearable
:disabled="disabled"
/>
</el-badge>
<el-button type="danger" :icon="Delete" circle @click="delSelf" :disabled="disabled"/>
</div>
</template>
<script setup>
import {ref, defineProps, watch} from 'vue';
import {Delete} from "@element-plus/icons-vue";
import {deepClone} from "@/utils.js";
const emit = defineEmits(['delRule']);
const props = defineProps({
pipe: Object,
attrOptions:Array,
disabled:Boolean
});
const pipe = ref({});
watch(() => props.pipe, (newData) => {
if (!newData) return
pipe.value = deepClone(newData)
}, {
deep: true,
immediate: true
})
function switchVarType(e, kv) {
if (String(e.target.tagName).toUpperCase() === 'SUP') {
kv.val_type = kv.val_type === 'number' ? 'string' : 'number';
}
}
function delSelf() {
emit('delRule')
}
</script>
<style lang="scss" scoped>
.bizrulecondition-container {
display: flex;
flex-direction: row;
.el-badge__content {
transition: 400ms;
user-select: none;
}
.el-badge__content:hover {
cursor: pointer;
}
}
</style>