feat: 场景联动中告警按条件查询

* feat: 场景联动新增多条件

* feat: 优化告警绑定场景联动多条件

* feat: 兼容告警绑定场景联动多条件

* feat: 场景联动中告警按条件查询

* fix: 优化场景联动多条件回显
This commit is contained in:
XieYongHong 2024-03-13 11:32:39 +08:00 committed by GitHub
parent 4600fcb4d7
commit 1c50005161
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 1137 additions and 508 deletions

View File

@ -42,7 +42,7 @@ export const detail = (id:string) => server.get(`/alarm/config/${id}`);
/** /**
* *
*/ */
export const unbindScene = (id:string,data:any) => server.post(`/alarm/rule/bind/${id}/_delete`,data); export const unbindScene = (id:string,data:any, branchId: string) => server.post(`/alarm/rule/bind/${id}/_delete?branchIndex=${branchId}`,data);
/** /**
* *

View File

@ -9,6 +9,8 @@ export const detail = (id: string) => server.get(`/scene/${id}`)
export const query = (data: any) => server.post('/scene/_query/',data); export const query = (data: any) => server.post('/scene/_query/',data);
export const queryBranch = (data: any, id: string) => server.post(`/scene/branch/query?alarmId=${id}`,data);
export const _delete = (id: string) => server.remove(`/scene/${id}/`); export const _delete = (id: string) => server.remove(`/scene/${id}/`);
export const _action = (id: string, type: '_disable' | '_enable') => server.put(`/scene/${id}/${type}`); export const _action = (id: string, type: '_disable' | '_enable') => server.put(`/scene/${id}/${type}`);

View File

@ -1,7 +1,7 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import type { FormModelType } from '@/views/rule-engine/Scene/typings' import type { FormModelType } from '@/views/rule-engine/Scene/typings'
import { detail } from '@/api/rule-engine/scene' import { detail } from '@/api/rule-engine/scene'
import { cloneDeep, isArray } from 'lodash-es' import {cloneDeep, isArray, isObject} from 'lodash-es'
import { randomString } from '@/utils/utils' import { randomString } from '@/utils/utils'
type DataType = { type DataType = {
@ -54,6 +54,8 @@ export const defaultBranches = [
alarmFirst: false, alarmFirst: false,
}, },
then: [], then: [],
executeAnyway: true,
branchId: Math.floor(Math.random() * 100000000)
}, },
]; ];
@ -73,7 +75,7 @@ const defaultOptions = {
export const useSceneStore = defineStore('scene', () => { export const useSceneStore = defineStore('scene', () => {
const data = ref<FormModelType>({ const data = ref<FormModelType>({
trigger: { type: ''}, trigger: { type: ''},
options: defaultOptions, options: [defaultOptions],
branches: defaultBranches, branches: defaultBranches,
description: '', description: '',
name: '', name: '',
@ -93,6 +95,14 @@ export const useSceneStore = defineStore('scene', () => {
} }
} }
const compatibleOldOptions = (options: any) => {
if (isObject(options)) {
return [options]
} else {
return options
}
}
const getDetail = async (id: string) => { const getDetail = async (id: string) => {
refresh() refresh()
const resp = await detail(id) const resp = await detail(id)
@ -109,21 +119,48 @@ export const useSceneStore = defineStore('scene', () => {
branches[0].when.length = [] branches[0].when.length = []
} }
} else { } else {
const branchesLength = branches.length; if (triggerType === 'device') {
if ( const len = branches.length
triggerType === 'device' && const newBranches: any[] = []
((branchesLength === 1 && branches[0]?.when?.length) || // 有一组数据并且when有值
(branchesLength > 1 && branches[branchesLength - 1]?.when?.length)) // 有多组否则数据并且最后一组when有值
) { branches.forEach((item, index) => {
branches.push(null);
if (item?.executeAnyway && index > 0 && branches[index - 1]?.when?.length) {
newBranches.push(null)
newBranches.push(item)
// branches.splice(index, 0 , null)
} else {
newBranches.push(item)
} }
// if (item?.executeAnyway && index > 0 && branches[index - 1]?.when?.length) {
// branches.splice(index, 0 , null)
// }
if ( index === len - 1 && item?.when?.length) {
newBranches.push(null)
} }
console.log(branches) })
branches = [...newBranches]
}
// const branchesLength = branches.length;
// if (
// triggerType === 'device' &&
// ((branchesLength === 1 && branches[0]?.when?.length) || // 有一组数据并且when有值
// (branchesLength > 1 && branches[branchesLength - 1]?.when?.length)) // 有多组否则数据并且最后一组when有值
// ) {
// branches.push(null);
// }
}
console.log('result.options',branches)
data.value = { data.value = {
...result, ...result,
trigger: result.trigger || {}, trigger: result.trigger || {},
branches: cloneDeep(assignmentKey(branches)), branches: cloneDeep(assignmentKey(branches)),
options: result.options ? {...cloneDeep(defaultOptions), ...result.options } : cloneDeep(defaultOptions), options: result.options && Object.keys(result.options)?.length ? result.options : cloneDeep(defaultOptions),
} }
} }
} }

View File

@ -9,7 +9,14 @@
@ok="saveCorrelation" @ok="saveCorrelation"
:maskClosable="false" :maskClosable="false"
> >
<pro-search :columns="columns" @search="handleSearch" /> <div v-if="type !== 'other'" style="padding: 0 24px">
<j-steps :current="current" >
<j-step title="选择场景"></j-step>
<j-step title="选择条件"></j-step>
</j-steps>
</div>
<template v-if="current === 0 || type === 'other' ">
<pro-search :columns="columns" type="simple" @search="handleSearch"/>
<div style="height: 500px; overflow-y: auto"> <div style="height: 500px; overflow-y: auto">
<JProTable <JProTable
model="CARD" model="CARD"
@ -79,13 +86,61 @@
</template> </template>
</JProTable> </JProTable>
</div> </div>
</template>
<template v-if="current === 1">
<div class="branch-terms-items">
<j-tree
v-if="branchGroup.length"
defaultExpandAll
checkable
:treeData="branchGroup"
@check="branchCheck"
>
</j-tree>
<!-- <CardBox-->
<!-- v-for="(item, index) in branchGroup.branches"-->
<!-- :showStatus="false"-->
<!-- :active="branchActiveKey.includes(item.id)"-->
<!-- @click="() => branchClick(item.id)"-->
<!-- >-->
<!-- <template #content>-->
<!-- <div class="condition-name">-->
<!-- 条件 {{ index + 1 }}-->
<!-- </div>-->
<!-- <div style="height: 80px">-->
<!-- <j-scrollbar >-->
<!-- <div v-for="(b, bIndex) in item">-->
<!-- <div style="font-weight: bold">-->
<!-- <span v-if="bIndex === 0"></span>-->
<!-- <span v-else>否则</span>-->
<!-- <span>{{ b.condition }}</span>-->
<!-- </div>-->
<!-- <div style="padding-left: 16px" v-for="action in b.actions">-->
<!-- 执行 {{ action }}-->
<!-- </div>-->
<!-- </div>-->
<!-- </j-scrollbar>-->
<!-- </div>-->
<!-- </template>-->
<!-- </CardBox>-->
</div>
</template>
<template #footer>
<j-button v-if="current === 0" @click="closeModal">取消</j-button>
<j-button v-if="current === 0" type="primary" @click="next">下一步</j-button>
<j-button v-if="current === 1" @click="prev">上一步</j-button>
<j-button v-if="current === 1" type="primary" @click="saveCorrelation">完成</j-button>
</template>
</j-modal> </j-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { query } from '@/api/rule-engine/scene'; import {query} from '@/api/rule-engine/scene';
import { bindScene } from '@/api/rule-engine/configuration'; import {bindScene} from '@/api/rule-engine/configuration';
import { getImage, onlyMessage } from '@/utils/comm'; import {getImage, onlyMessage} from '@/utils/comm';
import {handleSceneBranches} from './utils'
const columns = [ const columns = [
{ {
title: '场景名称', title: '场景名称',
@ -176,15 +231,21 @@ const props = defineProps({
type: String, type: String,
}, },
}); });
const current = ref(0)
const branchGroup = ref<any[]>([])
const branchActiveKey = ref([])
const branchCheckKeys = ref([])
const terms = [ const terms = [
{ {
terms: [ terms: [
{ // {
column: 'id', // column: 'id',
termType: 'alarm-bind-rule$not', // termType: 'alarm-bind-rule$not',
value: props.id, // value: props.id,
type: 'and', // type: 'and',
}, // },
{ {
column: 'triggerType', column: 'triggerType',
termType: 'eq', termType: 'eq',
@ -222,6 +283,7 @@ const handleClick = (dt: any) => {
} else { } else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id]; _selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
} }
// _selectedRowKeys.value = [dt.id]
}; };
/** /**
* 取消选择事件 * 取消选择事件
@ -229,31 +291,69 @@ const handleClick = (dt: any) => {
const onSelectChange = (arr: any[]) => { const onSelectChange = (arr: any[]) => {
_selectedRowKeys.value = arr _selectedRowKeys.value = arr
}; };
const log = () => {};
log(); const branchClick = (id: string) => {
const keys = new Set(branchActiveKey.value)
}
const handleSearch = (e: any) => { const handleSearch = (e: any) => {
params.value = e; params.value = e;
}; };
const emit = defineEmits(['closeSave', 'saveScene']); const emit = defineEmits(['closeSave', 'saveScene']);
const next = () => {
if (_selectedRowKeys.value.length) {
query({
pageSize: 99,
terms: [{column: 'id', termType: 'in', value: _selectedRowKeys.value.join(',')}]
}).then(res => {
if (res.success) {
branchGroup.value = handleSceneBranches(res.result.data) || []
console.log(branchGroup.value)
}
})
current.value += 1
} else {
onlyMessage('请选择场景', 'warning')
}
}
const branchCheck = (checkedKeys: string[], { checkedNodes }) => {
branchCheckKeys.value = checkedNodes.filter(item => item.branchId).map(item => ({
branchIndex: item.branchId,
ruleId: item.sceneId,
alarmId: props.id,
}))
}
const prev = () => {
current.value -= 1
}
/** /**
* 保存选中关联场景 * 保存选中关联场景
*/ */
const saveCorrelation = async () => { const saveCorrelation = async () => {
if (_selectedRowKeys.value.length > 0) { if (_selectedRowKeys.value.length === 0 && branchCheckKeys.value.length === 0) {
const list = _selectedRowKeys.value.map((item: any) => { onlyMessage('请选择至少一条数据', 'error')
return
}
const list = props.type === 'other' ? _selectedRowKeys.value.map((item: any) => {
return { return {
alarmId: props.id, alarmId: props.id,
ruleId: item, ruleId: item,
}; };
}); }) : branchCheckKeys.value
const res = await bindScene([...list]); const res = await bindScene([...list]);
if (res.status === 200) { if (res.status === 200) {
onlyMessage('操作成功'); onlyMessage('操作成功');
emit('saveScene'); emit('saveScene');
} }
} else {
onlyMessage('请选择至少一条数据', 'error');
}
}; };
const closeModal = () => { const closeModal = () => {
emit('closeSave'); emit('closeSave');
@ -265,4 +365,16 @@ const closeModal = () => {
font-size: 14px; font-size: 14px;
margin-top: 10px; margin-top: 10px;
} }
.condition-name {
font-size: 16px;
font-weight: bold;
}
.branch-terms-items {
display: flex;
flex-direction: column;
gap: 8px;
padding-top: 12px;
}
</style> </style>

View File

@ -0,0 +1,241 @@
import {send} from "vite";
import {isArray, isBoolean, isObject} from "lodash-es";
import {randomString} from "@/utils/utils";
const TypeMap = {
'and': '并且',
'or': '或者'
}
const DoubleFilter = ['nbtw', 'btw', 'in', 'nin'];
const TermsTypeMap = {
eq: '等于_value',
neq: '不等于_value',
gt: '大于_value',
gte: '大于等于_value',
lt: '小于_value',
lte: '小于等于_value',
btw: '在_value和_value2之间',
nbtw: '不在_value和_value2之间',
time_gt_now: '距离当前时间大于_value秒',
time_lt_now: '距离当前时间小于_value秒',
in: '在_value,_value2之中',
nin: '不在_value,_value2之中',
like: '包含_value',
nlike: '不包含_value',
notnull: '不为空',
isnull: '为空'
};
const handleValueString = (t: string, value: any) => {
if (DoubleFilter.includes(t)) {
const _v = value.length === 2 ? value : [value[0], value[0]]
return TermsTypeMap[t].replace('_value', _v[0]).replace('_value2', _v[1])
} else if(['notnull', 'isnull'].includes(t)) {
return TermsTypeMap[t]
} else if (TermsTypeMap[t]){
return TermsTypeMap[t].replace('_value', value[0]);
} else {
return `${t}${value[0]}`
}
}
const handleNotifyType = (data: any, options: any) => {
if (data.notifyType === 'dingTalk') {
const { sendTo, orgName, templateName } = options
if (options.provider === 'dingTalkRobotWebHook') {
return `通过群机器人消息发送 ${templateName || data?.notify?.templateId}`
}
const move = sendTo || orgName ? '向' : ''
return `通过钉钉${move} ${sendTo || ''} ${orgName || ''} 发送 ${templateName || data?.notify?.templateId}`
}
if (data.notifyType === 'weixin') {
const { sendTo, orgName, tagName, templateName } = options
const move = sendTo || orgName || tagName ? '向' : ''
return `通过微信${move}${sendTo || ''}${orgName || ''}${tagName || ''}发送${templateName || data?.notify?.templateId}`
}
if (data.notifyType === 'email') {
const { sendTo, templateName } = options
const move = sendTo ? '向' : ''
return `通过邮件${move}${sendTo || ''}发送${templateName || data?.notify?.templateId}`
}
if (data.notifyType === 'voice') {
const { sendTo, templateName } = options
const move = sendTo ? '向' : ''
return `通过语音${move}${sendTo || ''}发送${templateName || data?.notify?.templateId}`
}
if (data.notifyType === 'sms') {
const { sendTo, templateName } = options
const move = sendTo ? '向' : ''
return `通过短信${move}${sendTo || ''}发送${templateName || data?.notify?.templateId}`
}
if (data.notifyType === 'sms') {
const { templateName } = options
return `通过WebHook发送${templateName || data?.notify?.templateId}`
}
return undefined
}
const handleDevice = (device: any, options: any) => {
let str = ''
const {type, name, propertiesName, propertiesValue, tagName, productName, triggerName, relationName} = options
if (['fixed', 'context'].includes(device?.selector)) {
str += `${type} ${name} ${propertiesName}`
let isValueBoolean = isBoolean(propertiesValue)
if (propertiesValue && isValueBoolean) {
str += '为'
}
str += isValueBoolean || propertiesValue ? propertiesValue : ''
} else if (device?.selector === 'tag') {
str = `${type} ${tagName} ${productName} ${propertiesName}`
} else if (device?.selector === 'relation') {
str = `${type}${triggerName}具有相同${relationName}${productName}设备的${propertiesName}`
}
return str
}
const handleActions = (then: any): any[] => {
let actionsArr:any[] = []
const arr = then?.[0].actions.length ? then?.[0].actions : then?.[1].actions
arr?.forEach((item: any) => {
console.log(item, item.options)
if (item.executor === 'alarm') {
actionsArr.push(
item.alarm.mode === 'trigger' ?
'满足条件后将触发关联此条件的告警' :
'满足条件后将解除关联此条件的告警'
)
}
if (item.executor === 'notify') {
actionsArr.push(handleNotifyType(item.notify, item.options))
}
if (item.executor === 'delay') {
actionsArr.push(item.options?.name)
}
if (item.executor === 'device') {
actionsArr.push(handleDevice(item.device, item.options))
}
})
return actionsArr
}
const handleConditions = (when: any, whenData: any[]) => {
let termsArr: string = ''
if (when) {
when?.terms.forEach((item, itemIndex) => {
if (item.terms?.length) {
if (itemIndex != 0) {
termsArr += item.termType
}
termsArr += '【'
item.terms.forEach((b, index) => {
const [ name, termType, value, type ] = b
if (index !== 0) {
termsArr += ` ${TypeMap[type] || type} `
}
termsArr += `${name} ${handleValueString(termType, value)}`
})
termsArr += '】'
}
})
} else {
whenData.forEach((item, itemIndex) => {
if (item.terms.length) {
if (itemIndex !== 0) {
termsArr += TypeMap[item.type]
}
termsArr += '【'
item.terms.forEach((b, index) => {
console.log(b)
const { column, termType, value, type } = b
let _val: any = { 0: value }
if (isObject(value)) {
_val = { 0: value.value }
} else if (isArray(value)) {
_val = value
}
if (index !== 0) {
termsArr += ` ${TypeMap[type] || type} `
}
termsArr += `${column} ${handleValueString(termType, _val)}`
})
termsArr += '】'
}
})
}
return termsArr
}
const handleBranches = (branches: any[], when: any, parentId: string) => {
const msg: any[] = []
branches.forEach((item: any, index) => {
const _id = `condition_${index}`
const obj = {
title: `条件 ${index + 1}`,
id: _id,
parentId,
children: [{
title: handleConditions(when[index], item.when),
id: randomString(),
branchId: item.branchId || -1,
parentId: _id,
sceneId: parentId
}]
}
if (index === 0) {
msg[0] = obj
} else {
const lastIndex = msg.length - 1
if (item.executeAnyway) {
msg[lastIndex + 1] = obj
} else {
msg[lastIndex].children.push({
title: handleConditions(when[index], item.when),
id: randomString(),
branchId: item.branchId || -1,
parentId: _id,
sceneId: parentId
})
}
}
})
return msg
}
export const handleSceneBranches = (data: any): any[] => {
const group: any[] = []
data?.forEach((item: any) => {
let obj: any = {
title: item.name,
id: item.id,
children: []
}
if (item.branches?.length) {
obj.trigger = item.options.trigger
obj.children = handleBranches(item.branches, item.options.when, item.id)
}
group.push(obj)
})
return group
}

View File

@ -2,7 +2,7 @@
<FullPage> <FullPage>
<JProTable <JProTable
model="CARD" model="CARD"
:request="query" :request="queryTable"
:defaultParams="{ :defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
terms, terms,
@ -47,11 +47,15 @@
<img :src="typeMap.get(slotProps.triggerType)?.img" /> <img :src="typeMap.get(slotProps.triggerType)?.img" />
</template> </template>
<template #content> <template #content>
<div style="height: 102px;">
<Ellipsis style="width: calc(100% - 100px)"> <Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600"> <span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }} {{ slotProps.name }}
</span> </span>
</Ellipsis> </Ellipsis>
<div v-if="slotProps.branchName">
{{ slotProps.branchName }}
</div>
<Ellipsis :lineClamp="2"> <Ellipsis :lineClamp="2">
<div class="subTitle"> <div class="subTitle">
说明{{ 说明{{
@ -60,6 +64,7 @@
}} }}
</div> </div>
</Ellipsis> </Ellipsis>
</div>
</template> </template>
<template #actions="item"> <template #actions="item">
<PermissionButton <PermissionButton
@ -95,7 +100,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { query } from '@/api/rule-engine/scene'; import { queryBranch} from '@/api/rule-engine/scene';
import { unbindScene } from '@/api/rule-engine/configuration'; import { unbindScene } from '@/api/rule-engine/configuration';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import type { ActionsType } from '@/components/Table'; import type { ActionsType } from '@/components/Table';
@ -154,7 +159,7 @@ const getActions = (
popConfirm: { popConfirm: {
title: '确定解绑?', title: '确定解绑?',
onConfirm: async () => { onConfirm: async () => {
const res = await unbindScene(id, [data.id]); const res = await unbindScene(id, [data.id], data.branchIndex);
if (res.status === 200) { if (res.status === 200) {
onlyMessage('操作成功'); onlyMessage('操作成功');
actionRef.value.reload(); actionRef.value.reload();
@ -165,6 +170,11 @@ const getActions = (
]; ];
return actions; return actions;
}; };
const queryTable = (_terms: any) => {
return queryBranch(_terms, id)
}
const visible = ref(false); const visible = ref(false);
const log = () => { const log = () => {
console.log(); console.log();

View File

@ -7,7 +7,7 @@ import { storeToRefs } from 'pinia';
import { useSceneStore } from '@/store/scene' import { useSceneStore } from '@/store/scene'
import { Form } from 'jetlinks-ui-components' import { Form } from 'jetlinks-ui-components'
import { queryProductList } from '@/api/device/product' import { queryProductList } from '@/api/device/product'
import { query as deviceQuery } from '@/api/device/instance' import {query as deviceQuery, detail as deviceDetailQuery} from '@/api/device/instance'
import { getTreeData_api } from '@/api/system/department' import { getTreeData_api } from '@/api/system/department'
const sceneStore = useSceneStore() const sceneStore = useSceneStore()
@ -42,7 +42,8 @@ const check = async (): Promise<boolean> => {
} }
if (selectorValues!.length === 1) { if (selectorValues!.length === 1) {
const deviceDetail = deviceResp?.result?.data?.[0] const deviceDetailResp = await deviceDetailQuery(selectorValues![0])
const deviceDetail = deviceDetailResp?.result
metadata = JSON.parse(deviceDetail?.metadata || '{}') // metadata = JSON.parse(deviceDetail?.metadata || '{}') //
} }
} else if (deviceTrigger.selector === 'org') { // } else if (deviceTrigger.selector === 'org') { //
@ -60,7 +61,7 @@ const check = async (): Promise<boolean> => {
// //
if (['readProperty', 'writeProperty'].includes(deviceTrigger.operation?.operator!)) { if (['readProperty', 'writeProperty'].includes(deviceTrigger.operation?.operator!)) {
let hasProperties = false let hasProperties = false
if (metadata.properties.length) { if (metadata.properties?.length) {
if (deviceTrigger.operation?.readProperties && deviceTrigger.operation?.readProperties.length) { if (deviceTrigger.operation?.readProperties && deviceTrigger.operation?.readProperties.length) {
// hasProperties = metadata.properties.every((item: any) => deviceTrigger.operation!.readProperties!.includes(item.id)) // hasProperties = metadata.properties.every((item: any) => deviceTrigger.operation!.readProperties!.includes(item.id))
hasProperties = deviceTrigger.operation!.readProperties.every(_id => metadata.properties.some((item: any) => item.id === _id)) hasProperties = deviceTrigger.operation!.readProperties.every(_id => metadata.properties.some((item: any) => item.id === _id))

View File

@ -316,6 +316,7 @@ const checkNoticeDelete = async () => {
} }
const check = () => { const check = () => {
console.log(_data.value.branches)
const _executor = _data.value.branches![props.branchesName].then[props.thenName].actions?.[props.name]?.executor const _executor = _data.value.branches![props.branchesName].then[props.thenName].actions?.[props.name]?.executor
if (_executor === 'device' && _data.value.branches![props.branchesName].then[props.thenName].actions[props.name]?.device) { // if (_executor === 'device' && _data.value.branches![props.branchesName].then[props.thenName].actions[props.name]?.device) { //
checkDeviceDelete() checkDeviceDelete()

View File

@ -195,7 +195,7 @@ const handOptionByColumn = (option: any) => {
} else if(option.type === 'enum') { } else if(option.type === 'enum') {
valueOptions.value = _options?.elements?.map((item: any) => ({ ...item, label: item.text, value: item.value})) || [] valueOptions.value = _options?.elements?.map((item: any) => ({ ...item, label: item.text, value: item.value})) || []
} else{ } else{
valueOptions.value = _options?.map((item: any) => ({ ...item, label: item.name, value: item.id})) || [] valueOptions.value = (isObject(_options) ? [] : _options)?.map((item: any) => ({ ...item, label: item.name, value: item.id})) || []
} }
valueColumnOptions.value = treeFilter(cloneDeep(columnOptions.value), option.type, 'type') valueColumnOptions.value = treeFilter(cloneDeep(columnOptions.value), option.type, 'type')
} else { } else {

View File

@ -28,7 +28,7 @@
style="padding: 0" style="padding: 0"
type="link" type="link"
@click.stop="triggerVisible = true" @click.stop="triggerVisible = true"
>关联此场景的告警</j-button >关联此条件的告警</j-button
> >
</template> </template>
<template v-else> <template v-else>
@ -36,7 +36,7 @@
style="padding: 0" style="padding: 0"
type="link" type="link"
@click.stop="triggerVisible = true" @click.stop="triggerVisible = true"
>关联此场景的告警</j-button >关联此条件的告警</j-button
> >
</template> </template>
</div> </div>
@ -386,6 +386,7 @@
</template> </template>
<TriggerAlarm <TriggerAlarm
:id="_data.id" :id="_data.id"
:branchId="_data.branches[branchesName].branchId"
v-if="triggerVisible" v-if="triggerVisible"
@close="triggerVisible = false" @close="triggerVisible = false"
/> />

View File

@ -4,7 +4,7 @@
@cancel="emit('close')" @cancel="emit('close')"
@ok="emit('close')" @ok="emit('close')"
visible visible
title="关联此场景的告警" title="关联此条件的告警"
> >
<div style="margin-bottom: 24px">关联告警数量{{ count }}</div> <div style="margin-bottom: 24px">关联告警数量{{ count }}</div>
<JProTable <JProTable
@ -18,9 +18,8 @@
{ {
terms: [ terms: [
{ {
column: 'id', column: 'id$rule-bind-alarm',
value: id, value: branchId ? `${id}:${branchId}` : id,
termType: 'rule-bind-alarm',
}, },
], ],
}, },
@ -59,6 +58,10 @@ const props = defineProps({
type: String, type: String,
default: '', default: '',
}, },
branchId: {
type: String,
default: '',
},
}); });
const emit = defineEmits(['close']); const emit = defineEmits(['close']);
@ -108,7 +111,8 @@ watch(
terms: [ terms: [
{ {
column: 'id$rule-bind-alarm', column: 'id$rule-bind-alarm',
value: newId, // value: newId,
value: props.branchId ? `${newId}:${props.branchId}` : newId,
}, },
], ],
}).then((resp) => { }).then((resp) => {

View File

@ -1,5 +1,16 @@
<template> <template>
<div :class='WarpClass'> <div :class='WarpClass'>
<j-popconfirm
title='确认删除?'
v-if="showGroupDelete && isFirst"
placement="topRight"
:overlayStyle='{minWidth: "180px"}'
@confirm='deleteGroup'
>
<div v-if="showGroupDelete && isFirst" class="group-delete">
删除条件
</div>
</j-popconfirm>
<div class='actions-terms-title'> <div class='actions-terms-title'>
{{ isFirst ? '当' : '否则' }} {{ isFirst ? '当' : '否则' }}
</div> </div>
@ -40,6 +51,7 @@
:isFirst='index === 0' :isFirst='index === 0'
:isLast='index === whenData.length -1' :isLast='index === whenData.length -1'
:branchName='name' :branchName='name'
:branches_Index='branches_Index'
:data='item' :data='item'
/> />
@ -102,9 +114,27 @@ const props = defineProps({
name: { name: {
type: Number, type: Number,
default: 0 default: 0
},
branches_Index: {
type: Number,
default: 0
},
groupLen: {
type: Number,
default: 0
},
groupIndex: {
type: Number,
default: 0
},
showGroupDelete: {
type: Boolean,
default: false
} }
}) })
const emit = defineEmits(['deleteGroup'])
const showDelete = ref(false) const showDelete = ref(false)
const error = ref(false) const error = ref(false)
@ -169,8 +199,8 @@ const addWhen = () => {
key: `terms_${randomString()}` key: `terms_${randomString()}`
} }
FormModel.value.branches?.[props.name].when?.push(terms) FormModel.value.branches?.[props.name].when?.push(terms)
FormModel.value.branches?.push(null as any) FormModel.value.branches?.splice(props.groupLen, 0, null)
FormModel.value.options!.when[props.name]?.terms.push({ termType: '并且', terms: [['','eq','','and']]}) FormModel.value.options!.when[props.branches_Index]?.terms.push({ termType: '并且', terms: [['','eq','','and']]})
} }
const optionsClass = computed(() => { const optionsClass = computed(() => {
@ -193,6 +223,10 @@ const rules = [{
} }
}] }]
const deleteGroup = () => {
emit('deleteGroup')
}
</script> </script>
<style scoped lang='less'> <style scoped lang='less'>

View File

@ -1,79 +1,73 @@
<template> <template>
<div class="terms-params-item"> <div class='terms-params-item'>
<div v-if="!isFirst" class="term-type-warp"> <div v-if='!isFirst' class='term-type-warp'>
<DropdownButton <DropdownButton
:options="[ :options='[
{ label: '并且', value: 'and' }, { label: "并且", value: "and" },
{ label: '或者', value: 'or' }, { label: "或者", value: "or" },
]" ]'
type="type" type='type'
v-model:value="paramsValue.type" v-model:value='paramsValue.type'
@select="typeSelect" @select='typeSelect'
/> />
</div> </div>
<div <div
class="params-item_button" class='params-item_button'
@mouseover="mouseover" @mouseover='mouseover'
@mouseout="mouseout" @mouseout='mouseout'
> >
<DropdownButton <DropdownButton
:options="columnOptions" :options='columnOptions'
icon="icon-zhihangdongzuoxie-1" icon='icon-zhihangdongzuoxie-1'
type="column" type='column'
value-name="column" value-name='column'
label-name="fullName" label-name='fullName'
placeholder="请选择参数" placeholder='请选择参数'
v-model:value="paramsValue.column" v-model:value='paramsValue.column'
component="treeSelect" component='treeSelect'
@select="columnSelect" @select='columnSelect'
/> />
<DropdownButton <DropdownButton
:options="termTypeOptions" :options='termTypeOptions'
type="termType" type="termType"
value-name="id" value-name='id'
label-name="name" label-name='name'
placeholder="操作符" placeholder="操作符"
v-model:value="paramsValue.termType" v-model:value='paramsValue.termType'
@select="termsTypeSelect" @select='termsTypeSelect'
/> />
<div v-if="!['notnull','isnull'].includes(paramsValue.termType)"> <div v-if="!['notnull','isnull'].includes(paramsValue.termType)">
<DoubleParamsDropdown <DoubleParamsDropdown
v-if="showDouble" v-if='showDouble'
icon="icon-canshu" icon='icon-canshu'
placeholder="参数值" placeholder='参数值'
:options="valueOptions" :options='valueOptions'
:metricOptions="metricOption" :metricOptions='metricOption'
:tabsOptions="tabsOptions" :tabsOptions='tabsOptions'
v-model:value="paramsValue.value.value" v-model:value='paramsValue.value.value'
v-model:source="paramsValue.value.source" v-model:source='paramsValue.value.source'
@select="valueSelect" @select='valueSelect'
/> />
<ParamsDropdown <ParamsDropdown
v-else v-else
icon="icon-canshu" icon='icon-canshu'
placeholder="参数值" placeholder='参数值'
:options="valueOptions" :options='valueOptions'
:metricOptions="metricOption" :metricOptions='metricOption'
:tabsOptions="tabsOptions" :tabsOptions='tabsOptions'
:metric="paramsValue.value?.metric" :metric='paramsValue.value?.metric'
v-model:value="paramsValue.value.value" v-model:value='paramsValue.value.value'
v-model:source="paramsValue.value.source" v-model:source='paramsValue.value.source'
@select="valueSelect" @select='valueSelect'
/> />
</div> </div>
<j-popconfirm <j-popconfirm title='确认删除?' @confirm='onDelete' :overlayStyle='{minWidth: "180px"}'>
title="确认删除?" <div v-show='showDelete' class='button-delete'> <AIcon type='CloseOutlined' /></div>
@confirm="onDelete"
:overlayStyle="{ minWidth: '180px' }"
>
<div v-show="showDelete" class="button-delete">
<AIcon type="CloseOutlined" />
</div>
</j-popconfirm> </j-popconfirm>
</div> </div>
<div class="term-add" @click.stop="termAdd" v-if="isLast"> <div class='term-add' @click.stop='termAdd' v-if='isLast'>
<div class="terms-content"> <div class='terms-content'>
<AIcon type="PlusOutlined" style="font-size: 12px" /> <AIcon type='PlusOutlined' style='font-size: 12px' />
</div> </div>
</div> </div>
</div> </div>
@ -116,31 +110,35 @@ type TabsOption = {
const props = defineProps({ const props = defineProps({
isFirst: { isFirst: {
type: Boolean, type: Boolean,
default: true, default: true
}, },
isLast: { isLast: {
type: Boolean, type: Boolean,
default: true, default: true
}, },
showDeleteBtn: { showDeleteBtn: {
type: Boolean, type: Boolean,
default: true, default: true
}, },
name: { name: {
type: Number, type: Number,
default: 0, default: 0
}, },
termsName: { termsName: {
type: Number, type: Number,
default: 0, default: 0
}, },
branchName: { branchName: {
type: Number, type: Number,
default: 0, default: 0
},
branches_Index: {
type: Number,
default: 0
}, },
whenName: { whenName: {
type: Number, type: Number,
default: 0, default: 0
}, },
value: { value: {
type: Object as PropType<TermsType>, type: Object as PropType<TermsType>,
@ -150,11 +148,11 @@ const props = defineProps({
termType: 'eq', termType: 'eq',
value: { value: {
source: 'manual', source: 'manual',
value: undefined, value: undefined
}, }
}), })
}, }
}); })
const emit = defineEmits<Emit>(); const emit = defineEmits<Emit>();
@ -321,33 +319,20 @@ const columnSelect = (option: any) => {
// //
const termTypes = option.termTypes; const termTypes = option.termTypes;
if ( if (!termTypes.some((item: {id: string}) => paramsValue.termType === item.id)) { //
!termTypes.some( termTypeChange = true
(item: { id: string }) => paramsValue.termType === item.id, paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq'
)
) {
//
termTypeChange = true;
paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq';
} }
console.log('hasTypeChange', paramsValue.value.source, tabsOptions.value);
if ( if (hasTypeChange || !tabsOptions.value.every(a => a.key === paramsValue.value.source )) { //
hasTypeChange || paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq'
!tabsOptions.value.every((a) => a.key === paramsValue.value.source)
) {
//
paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq';
paramsValue.value = { paramsValue.value = {
source: tabsOptions.value[0].key, source: tabsOptions.value[0].key,
value: undefined, value: undefined
}; }
} else if (termTypeChange) { } else if (termTypeChange) {
const oldValue = isArray(paramsValue.value!.value) const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
? paramsValue.value!.value[0] const value = arrayParamsKey.includes(paramsValue.termType as string) ? [ oldValue, undefined ] : oldValue
: paramsValue.value!.value;
const value = arrayParamsKey.includes(paramsValue.termType as string)
? [oldValue, undefined]
: oldValue;
const _source = paramsValue.value?.source || tabsOptions.value[0].key; const _source = paramsValue.value?.source || tabsOptions.value[0].key;
const newValue: any = { const newValue: any = {
@ -359,21 +344,22 @@ const columnSelect = (option: any) => {
newValue.metric = paramsValue.value?.metric; newValue.metric = paramsValue.value?.metric;
} }
paramsValue.value = newValue; paramsValue.value = newValue
} }
console.log(paramsValue, hasTypeChange);
handOptionByColumn(option); handOptionByColumn(option)
emit('update:value', { ...paramsValue }); emit('update:value', { ...paramsValue })
nextTick(() => { nextTick(() => {
formItemContext.onFieldChange(); formItemContext.onFieldChange()
}); })
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[
props.termsName if (!formModel.value.options!.when[props.branches_Index]) {
][0] = option.name; formModel.value.options!.when[props.branches_Index] = {terms:[{terms: [['', '', '', '并且']]}]}
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[ }
props.termsName console.log([props.branchName, props.whenName, props.termsName])
][1] = paramsValue.termType; formModel.value.options!.when[props.branches_Index].terms[props.whenName].terms[props.termsName][0] = option.name
}; formModel.value.options!.when[props.branches_Index].terms[props.whenName].terms[props.termsName][1] = paramsValue.termType
}
const termsTypeSelect = (e: { key: string; name: string }) => { const termsTypeSelect = (e: { key: string; name: string }) => {
const oldValue = isArray(paramsValue.value!.value) const oldValue = isArray(paramsValue.value!.value)
@ -405,28 +391,25 @@ const termsTypeSelect = (e: { key: string; name: string }) => {
}; };
if (_source === 'metric') { if (_source === 'metric') {
newValue.metric = paramsValue.value?.metric; newValue.metric = paramsValue.value?.metric
const isArray = isString(paramsValue.value!.value) const isArray = isString(paramsValue.value!.value) ? paramsValue.value!.value?.includes?.(',') : false
? paramsValue.value!.value?.includes?.(',') if (arrayParamsKey.includes(e.key) !== isArray) { //
: false; newValue.value = undefined
if (arrayParamsKey.includes(e.key) !== isArray) {
//
newValue.value = undefined;
} }
} }
if( if(
['isnull','notull'].includes(e.key) ['isnull','notnull'].includes(e.key)
){ ){
newValue.value = 1 newValue.value = 1
} }
paramsValue.value = newValue; paramsValue.value = newValue
emit('update:value', { ...paramsValue }); emit('update:value', { ...paramsValue })
formItemContext.onFieldChange(); formItemContext.onFieldChange()
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[ formModel.value.options!.when[props.branches_Index].terms[props.whenName].terms[props.termsName][1] = e.key
props.termsName
][1] = e.name; }
};
const valueSelect = ( const valueSelect = (
v: any, v: any,
@ -441,49 +424,44 @@ const valueSelect = (
const newValues = { ...paramsValue }; const newValues = { ...paramsValue };
if (paramsValue.value?.source !== 'metric') { if (paramsValue.value?.source !== 'metric') {
delete newValues.value.metric; delete newValues.value.metric
} }
emit('update:value', { ...newValues }); emit('update:value', { ...newValues })
formItemContext.onFieldChange(); formItemContext.onFieldChange()
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[
props.termsName if (!formModel.value.options!.when[props.branches_Index]) {
][2] = labelObj; formModel.value.options!.when[props.branches_Index] = {terms:[{terms: [['', '', '', '并且']]}]}
}; }
formModel.value.options!.when[props.branches_Index].terms[props.whenName].terms[props.termsName][2] = labelObj
}
const typeSelect = (e: any) => { const typeSelect = (e: any) => {
emit('update:value', { ...paramsValue }); emit('update:value', { ...paramsValue })
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[ formModel.value.options!.when[props.branches_Index].terms[props.whenName].terms[props.termsName][3] = e.label
props.termsName }
][3] = e.label;
};
const termAdd = () => { const termAdd = () => {
const terms = { const terms = {
column: undefined, column: undefined,
value: { value: {
source: 'manual', source: 'manual',
value: undefined, value: undefined
}, },
termType: undefined, termType: undefined,
type: 'and', type: 'and',
key: `params_${new Date().getTime()}`, key: `params_${new Date().getTime()}`
}; }
formModel.value.branches?.[props.branchName]?.when?.[ if (!formModel.value.options!.when[props.branches_Index]) {
props.whenName formModel.value.options!.when[props.branches_Index] = {terms:[{terms: [['', '', '', '并且']]}]}
]?.terms?.push(terms); }
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[ formModel.value.branches?.[props.branches_Index]?.when?.[props.whenName]?.terms?.push(terms)
props.termsName formModel.value.options!.when[props.branches_Index].terms[props.whenName].terms.push(['', '', '', '并且'])
].push(['', '', '', '并且']); }
};
const onDelete = () => { const onDelete = () => {
formModel.value.branches?.[props.branchName]?.when?.[ formModel.value.branches?.[props.branches_Index]?.when?.[props.whenName]?.terms?.splice(props.termsName, 1)
props.whenName formModel.value.options!.when[props.branches_Index].terms[props.whenName].terms.splice(props.termsName, 1)
]?.terms?.splice(props.termsName, 1); }
formModel.value.options!.when[props.branchName].terms[
props.whenName
].terms.splice(props.termsName, 1);
};
nextTick(() => { nextTick(() => {
Object.assign( Object.assign(
@ -499,7 +477,9 @@ nextTick(() => {
'key', 'key',
]), ]),
); );
}); })
</script> </script>
<style scoped></style> <style scoped>
</style>

View File

@ -12,26 +12,45 @@
</template> </template>
</TitleComponent> </TitleComponent>
<template v-if='open'> <template v-if='open'>
<div>
<j-tabs type="editable-card" v-model:activeKey="activeKey" @edit="addGroup">
<j-tab-pane
v-for="(b, i) in group"
:key="b.id"
:tab="`条件${i + 1}`"
:closable="false"
>
<template v-for='(item, index) in data.branches'> <template v-for='(item, index) in data.branches'>
<template v-if="index >= b.start && index < (b.start + b.len)">
<Branches <Branches
v-if='!!item' v-if='!!item'
:data='item' :data='item'
:isFirst='index === 0' :isFirst='index === b.start'
:name='index' :name='index'
:branches_Index='item.branches_Index'
:groupLen="b.start + b.len"
:groupIndex="i"
:key='item.key' :key='item.key'
:showGroupDelete="group.length !== 1"
@delete='branchesDelete' @delete='branchesDelete'
@deleteAll='branchesDeleteAll' @deleteAll='branchesDeleteAll'
@deleteGroup="() => groupDelete(b, i)"
/> />
<div v-else class='actions-terms-warp' :style='{ marginTop: data.branches.length === 2 ? 0 : 24 }'> <div v-else class='actions-terms-warp' :style='{ marginTop: data.branches.length === 2 ? 0 : 24 }'>
<div class='actions-terms-title' style='padding: 0;margin-bottom: 24px;'> <div class='actions-terms-title' style='padding: 0;margin-bottom: 24px;'>
否则 否则
</div> </div>
<div class='actions-terms-options no-when'> <div class='actions-terms-options no-when'>
<AIcon type='PlusOutlined' class='when-add-button' @click='addBranches' /> <AIcon type='PlusOutlined' class='when-add-button' @click='() => addBranches(b.start + b.len)' />
</div> </div>
</div> </div>
</template> </template>
</template> </template>
</j-tab-pane>
</j-tabs>
</div>
</template>
<div v-else class='actions-branches-item'> <div v-else class='actions-branches-item'>
<j-form-item <j-form-item
:name='["branches", 0, "then"]' :name='["branches", 0, "then"]'
@ -49,7 +68,7 @@
<script setup lang='ts' name='Terms'> <script setup lang='ts' name='Terms'>
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useSceneStore } from 'store/scene' import { useSceneStore } from '@/store/scene'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
import { provide } from 'vue' import { provide } from 'vue'
import { ContextKey, handleParamsData, thenRules } from './util' import { ContextKey, handleParamsData, thenRules } from './util'
@ -57,15 +76,20 @@ import { getParseTerm } from '@/api/rule-engine/scene'
import type { FormModelType } from '@/views/rule-engine/Scene/typings' import type { FormModelType } from '@/views/rule-engine/Scene/typings'
import Branches from './Branches.vue' import Branches from './Branches.vue'
import Action from '../../action/index.vue' import Action from '../../action/index.vue'
import {randomString} from "@/utils/utils";
const sceneStore = useSceneStore() const sceneStore = useSceneStore()
const { data } = storeToRefs(sceneStore) const { data } = storeToRefs(sceneStore)
const open = ref<boolean>(false) const open = ref<boolean>(false)
const columnOptions = ref<any>([]) const columnOptions = ref<any>([])
const group = ref<Array<{ id: string, len: number}>>([])
const activeKey = ref('')
provide(ContextKey, columnOptions) provide(ContextKey, columnOptions)
const change = (e: boolean) => { const change = (e: boolean) => {
group.value = []
activeKey.value = ''
if (!e) { if (!e) {
data.value.branches!.length = 1 data.value.branches!.length = 1
data.value.branches![0].when = [] data.value.branches![0].when = []
@ -81,12 +105,12 @@ const change = (e: boolean) => {
value: undefined value: undefined
}, },
termType: undefined, termType: undefined,
key: 'params_1', key: `params_${randomString()}`,
type: 'and', type: 'and',
}, },
], ],
type: 'and', type: 'and',
key: 'terms_1', key: `terms_${randomString()}`,
}, },
] ]
} }
@ -100,7 +124,7 @@ const queryColumn = (dataModel: FormModelType) => {
}) })
} }
const addBranches = () => { const addBranches = (len: number) => {
const branchesItem = { const branchesItem = {
when: [], when: [],
key: `branches_${new Date().getTime()}`, key: `branches_${new Date().getTime()}`,
@ -111,10 +135,14 @@ const addBranches = () => {
alarmFirst: false, alarmFirst: false,
}, },
then: [], then: [],
branchId: Math.floor(Math.random() * 100000000)
} }
const lastIndex = data.value.branches!.length - 1 || 0 // const lastIndex = data.value.branches!.length - 1 || 0
data.value.branches?.splice(lastIndex, 1, branchesItem) data.value.branches?.splice(len - 1, 1, branchesItem)
data.value.options!.when = [] data.value.options!.when.splice(len - 1, 1, {
terms: []
})
// data.value.options!.when = []
} }
const branchesDelete = (index: number) => { const branchesDelete = (index: number) => {
@ -126,10 +154,62 @@ const branchesDelete = (index: number) => {
data.value.options?.when?.splice(index, 1) data.value.options?.when?.splice(index, 1)
} }
const addGroup = () => {
const branchesItem: any = {
when: [
{
terms: [
{
column: undefined,
value: {
source: 'fixed',
value: undefined
},
termType: undefined,
key: `params_${randomString()}`,
type: 'and',
},
],
type: 'and',
key: `terms_${randomString()}`,
},
],
key: `branches_${randomString()}`,
shakeLimit: {
enabled: false,
time: 1,
threshold: 1,
alarmFirst: false,
},
then: [],
executeAnyway: true,
branchId: Math.floor(Math.random() * 100000000)
}
data.value.branches?.push(branchesItem)
data.value.branches?.push(null as any)
activeKey.value = `group_${branchesItem.key}`
data.value.options!.when.push({
terms: [{
terms: [['','eq','','and']],
}]
})
}
const branchesDeleteAll = () => { const branchesDeleteAll = () => {
} }
const groupDelete = (g: any, index: number) => {
let _index = index - 1
if (_index < 0) { //
_index = 0
}
group.value.splice(index, 1)
data.value.branches.splice(g.start, g.len)
data.value.options!.when.splice(g.start, g.len)
activeKey.value = group.value[_index].id
}
watchEffect(() => { watchEffect(() => {
if (data.value.trigger?.device) { if (data.value.trigger?.device) {
queryColumn({ trigger: data.value.trigger }) queryColumn({ trigger: data.value.trigger })
@ -137,15 +217,48 @@ watchEffect(() => {
}) })
watchEffect(() => { watchEffect(() => {
const branches = data.value.branches
if (data.value.branches?.filter(item => item).length) { if (data.value.branches?.filter(item => item).length) {
open.value = !!data.value.branches[0].when.length open.value = !!data.value.branches[0].when.length
} else { } else {
open.value = true open.value = true
} }
})
onMounted(() => { let _group = []
console.log('terms-onMounted') if (branches) {
branches.forEach((item, index) => {
// if (index === 0) {
// _group.push({
// id: `group_${item.key}`,
// len: 0,
// start: 0,
// })
// }
const lastIndex = _group.length - 1
if (index === 0 || item?.executeAnyway) {
_group[lastIndex + 1] = {
id: `group_${item.key}`,
len: 1,
start: index
}
} else {
_group[lastIndex].len += 1
}
})
branches.filter(item => item).forEach((item, index) => {
item.branches_Index = index
})
group.value = _group
if (!activeKey.value) {
activeKey.value = _group[0].id
}
}
}) })
</script> </script>

View File

@ -11,6 +11,7 @@
:termsName='name' :termsName='name'
:whenName='whenName' :whenName='whenName'
:branchName='branchName' :branchName='branchName'
:branches_Index='branches_Index'
/> />
</j-form-item> </j-form-item>
</template> </template>
@ -60,6 +61,10 @@ const props = defineProps({
type: Number, type: Number,
default: 0 default: 0
}, },
branches_Index: {
type: Number,
default: 0
},
whenName: { whenName: {
type: Number, type: Number,
default: 0 default: 0

View File

@ -30,6 +30,7 @@
v-for='(item, index) in termsData' v-for='(item, index) in termsData'
:key='item.key' :key='item.key'
:branchName='branchName' :branchName='branchName'
:branches_Index='branches_Index'
:whenName='props.name' :whenName='props.name'
:name='index' :name='index'
:showDeleteBtn='termsData.length > 1' :showDeleteBtn='termsData.length > 1'
@ -89,6 +90,10 @@ const props = defineProps({
type: Number, type: Number,
default: 0 default: 0
}, },
branches_Index: {
type: Number,
default: 0
},
isLast: { isLast: {
type: Boolean, type: Boolean,
default: true default: true
@ -119,7 +124,7 @@ const typeChange = (e: any) => {
const onDelete = () => { const onDelete = () => {
formModel.value.branches?.[props.branchName]?.when?.splice(props.name, 1) formModel.value.branches?.[props.branchName]?.when?.splice(props.name, 1)
formModel.value.options!.when[props.branchName].terms.splice(props.name, 1) formModel.value.options!.when[props.branches_Index].terms.splice(props.name, 1)
} }
const addWhen = () => { const addWhen = () => {
@ -140,7 +145,10 @@ const addWhen = () => {
key: `terms_${randomString()}` key: `terms_${randomString()}`
} }
formModel.value.branches?.[props.branchName]?.when?.push(terms) formModel.value.branches?.[props.branchName]?.when?.push(terms)
formModel.value.options?.when?.[props.branchName]?.terms.push({ termType: '并且', terms: [['','eq','','and']]}) if (!formModel.value.options!.when[props.branches_Index]) {
formModel.value.options!.when[props.branches_Index] = {terms:[{terms: [['', '', '', '并且']]}]}
}
formModel.value.options?.when?.[props.branches_Index]?.terms.push({ termType: '并且', terms: [['','eq','','and']]})
} }
</script> </script>

View File

@ -50,6 +50,16 @@
.actions-terms-warp { .actions-terms-warp {
display: flex; display: flex;
margin-bottom: 24px; margin-bottom: 24px;
position: relative;
.group-delete {
position: absolute;
right: 0;
top: -14px;
z-index: 2;
cursor: pointer;
color: #e50012;
}
&.first-children, &.first-children,
&:last-child { &:last-child {

View File

@ -24,3 +24,4 @@ export const thenRules = [{
return Promise.resolve(); return Promise.resolve();
} }
}] }]

View File

@ -14,25 +14,25 @@
<template v-if='!options.onlyName'> <template v-if='!options.onlyName'>
<div v-if='options.productName' class='center-item'> <div v-if='options.productName' class='center-item'>
<AIcon type='icon-chanpin1' class='icon-padding-right' /> <AIcon type='icon-chanpin1' class='icon-padding-right' />
<span className='trigger-options-type'>{{ options.productName }}</span> <span class='trigger-options-type'>{{ options.productName }}</span>
</div> </div>
<div v-if='options.when'> <div v-if='options.when'>
<span className='trigger-options-when'>{{ options.when }}</span> <span class='trigger-options-when'>{{ options.when }}</span>
</div> </div>
<div v-if='options.time'> <div v-if='options.time'>
<span className='trigger-options-time'>{{ options.time }}</span> <span class='trigger-options-time'>{{ options.time }}</span>
</div> </div>
<div v-if='options.extraTime'> <div v-if='options.extraTime'>
<span className='trigger-options-extraTime'>{{ options.extraTime }}</span> <span class='trigger-options-extraTime'>{{ options.extraTime }}</span>
</div> </div>
<div v-if='options.action' class='center-item'> <div v-if='options.action' class='center-item'>
<AIcon :type='options.typeIcon' class='icon-padding-right' /> <AIcon :type='options.typeIcon' class='icon-padding-right' />
<span className='trigger-options-action'>{{ options.action }}</span> <span class='trigger-options-action'>{{ options.action }}</span>
</div> </div>
<div v-if='options.type' class='center-item'> <div v-if='options.type' class='center-item'>
<AIcon :type='options.typeIcon' class='icon-padding-right' /> <AIcon :type='options.typeIcon' class='icon-padding-right' />
<span className='trigger-options-type'>{{ options.type }}</span> <span class='trigger-options-type'>{{ options.type }}</span>
</div> </div>
</template> </template>
</template> </template>

View File

@ -0,0 +1,19 @@
import { useSceneStore } from '@/store/scene'
import {storeToRefs} from "pinia";
import type {BranchesGroup} from "@/views/rule-engine/Scene/typings";
export const useTrigger = () => {
const sceneStore = useSceneStore()
const { data } = storeToRefs(sceneStore)
const open = ref(false)
watchEffect(() => {
const group = data.value.branches as BranchesGroup
console.log(group)
open.value = !!group?.filter(item => item.filter(b => b)?.length).length
})
return {
open
}
}

View File

@ -328,7 +328,10 @@ const getActions = (
{ {
column: 'id', column: 'id',
termType: 'rule-bind-alarm', termType: 'rule-bind-alarm',
value: data.id, value: {
ruleId: [data.id],
branchId: [-1]
},
}, },
] ]
} }

View File

@ -280,6 +280,8 @@ export interface ActionBranchesProps {
shakeLimit: ShakeLimitType; shakeLimit: ShakeLimitType;
then: BranchesThen[]; then: BranchesThen[];
key?: string; key?: string;
executeAnyway?: boolean
} }
export interface ActionsType { export interface ActionsType {
@ -301,6 +303,8 @@ export interface ActionsType {
options?: Record<string, any>; options?: Record<string, any>;
} }
export type BranchesGroup = Array<ActionBranchesProps[]>
export interface FormModelType { export interface FormModelType {
id?: string; id?: string;
name?: string; name?: string;
@ -319,7 +323,7 @@ export interface FormModelType {
/** /**
* *
*/ */
branches?: ActionBranchesProps[]; branches?: ActionBranchesProps[] | Array<ActionBranchesProps[]>;
/** /**
* , * ,
*/ */

View File

@ -0,0 +1,43 @@
import type {ActionBranchesProps} from "./typings";
import {isArray} from "lodash-es";
export const handleGroup = (branches: ActionBranchesProps[]) => {
let group: Array<Array<ActionBranchesProps | null>> = []
branches.forEach((item) => {
const lastIndex = group.length - 1
if (item?.executeAnyway) {
group[lastIndex] = [item]
} else {
if (isArray(group[lastIndex])) {
group[lastIndex].push(item)
} else {
group[lastIndex] = [item]
}
}
})
// 判断每组末尾是否有数据并且when有值
if (group.length) {
group = group.map(item => {
if (item.length && item[item.length -1]?.when?.length) {
item.push(null)
}
return item
})
} else {
group[0] = [null]
}
return group
}
export const groupToArray = (branchesGroup: Array<ActionBranchesProps[]>) => {
const arr:ActionBranchesProps[] = []
branchesGroup.forEach(item => {
})
}

View File

@ -44,7 +44,7 @@
import PermissionButton from '@/components/PermissionButton/index.vue'; import PermissionButton from '@/components/PermissionButton/index.vue';
import AddDialog from './components/AddDialog.vue'; import AddDialog from './components/AddDialog.vue';
import { getRoleList_api, delRole_api } from '@/api/system/role'; import { getRoleList_api, delRole_api } from '@/api/system/role';
import type { ActionsType } from './typings'; import type { ActionsType } from '@/components/Table';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
const props = defineProps({ const props = defineProps({

View File

@ -94,11 +94,11 @@ export default defineConfig(({ mode}) => {
[env.VITE_APP_BASE_API]: { [env.VITE_APP_BASE_API]: {
// target: 'http://192.168.32.226:8844', // target: 'http://192.168.32.226:8844',
// target: 'http://192.168.32.244:8881', // target: 'http://192.168.32.244:8881',
// target: 'http://192.168.32.163:8844', //张本地 // target: 'http://192.168.32.163:8844', //张本地
// target: 'http://120.77.179.54:8844', // 120测试 // target: 'http://120.77.179.54:8844', // 120测试
target: 'http://192.168.33.46:8844', // 本地开发环境 target: 'http://192.168.33.46:8844', // 本地开发环境
// target: 'http://192.168.33.1:8845', // 社区版开发环境 // target: 'http://192.168.33.1:8845', // 社区版开发环境
// target: 'http://192.168.32.5:8848', // 刘本地 // target: 'http://192.168.32.200:8844', // 刘本地
// target: 'http://192.168.32.187:8844', // 谭本地 // target: 'http://192.168.32.187:8844', // 谭本地
ws: 'ws://192.168.33.46:8844', ws: 'ws://192.168.33.46:8844',
changeOrigin: true, changeOrigin: true,