fix: 场景联动-通知配置-options处理

This commit is contained in:
100011797 2023-03-15 11:39:00 +08:00
parent d7f3ba6317
commit 2b18323745
28 changed files with 6499 additions and 6005 deletions

View File

@ -42,7 +42,7 @@ export default {
// 不分页-列表
queryListNoPaging: (data: any) => post(`/notifier/config/_query/no-paging?paging=false`, data),
//
queryDingTalkUsers: (id: string) => get<any>(`/notifier/dingtalk/corp/${id}/users?sorts[0].name='name'&sorts[0].order=asc`),
queryDingTalkUsers: (id: string) => get<any>(`/notifier/dingtalk/corp/${id}/users?sorts[0].name="name"&sorts[0].order=asc`),
//
queryWechatUsers: (id: string) => get<any>(`/notifier/wechat/corp/${id}/users?sorts[0].name='name'&sorts[0].order=asc`),
queryWechatUsers: (id: string) => get<any>(`/notifier/wechat/corp/${id}/users?sorts[0].name="name"&sorts[0].order=asc`),
}

View File

@ -149,8 +149,8 @@ const columns = [
},
{
title: '说明',
dataIndex: 'describe',
key: 'describe',
dataIndex: 'description',
key: 'description',
search: {
type: 'string',
},

View File

@ -191,8 +191,8 @@ const columns = [
},
{
title: '说明',
dataIndex: 'describe',
key: 'describe',
dataIndex: 'description',
key: 'description',
},
{
title: '状态',

View File

@ -144,7 +144,7 @@
</template>
<script lang="ts" setup>
import { queryNoPagingPost } from '@/api/device/product';
import { queryGatewayList, queryNoPagingPost } from '@/api/device/product';
import { queryTree } from '@/api/device/category';
import { message } from 'jetlinks-ui-components';
import { ActionsType } from '@/views/device/Instance/typings';
@ -260,6 +260,26 @@ const columns = [
}),
},
},
{
key: 'productId$product-info',
dataIndex: 'productId$product-info',
title: '接入方式',
hideInTable: true,
search: {
type: 'select',
options: () =>
new Promise((resolve) => {
queryGatewayList({}).then((resp: any) => {
resolve(
resp.result.map((item: any) => ({
label: item.name,
value: `accessId is ${item.id}`,
})),
);
});
}),
},
},
{
dataIndex: 'deviceType',
title: '设备类型',

View File

@ -13,20 +13,28 @@
import { useSceneStore } from '@/store/scene';
import Action from '../action/index.vue';
import { storeToRefs } from 'pinia';
import { ActionsType } from '@/views/rule-engine/Scene/typings';
const sceneStore = useSceneStore();
const { data } = storeToRefs(sceneStore);
const onActionAdd = (_data: any) => {
if (data.value?.branches && _data) {
data?.value.branches?.[0].then.push(_data)
console.log(data?.value.branches?.[0].then)
const newThen = [...data.value.branches[0].then, _data];
data.value.branches![0].then = newThen
}
};
const onActionUpdate = (_data: ActionsType, type: boolean) => {
console.log(_data, type)
const onActionUpdate = (_data: any, type: boolean) => {
const indexOf = data.value.branches![0].then.findIndex(
(item) => item.parallel === type,
);
if (indexOf !== -1) {
if (_data?.actions?.length) {
data.value.branches![0].then[indexOf] = _data;
} else {
data.value.branches![0].then[indexOf].actions = [];
}
}
};
</script>

View File

@ -7,7 +7,7 @@
@ok="onOk"
:maskClosable="false"
>
<a-input-number
<j-input-number
style="max-width: 220px"
placeholder="请输入时间"
v-model:value="_value"
@ -16,7 +16,7 @@
:max="6535"
>
<template #addonAfter>
<a-select
<j-select
:options="[
{ label: '秒', value: 'seconds' },
{ label: '分', value: 'minutes' },
@ -25,7 +25,7 @@
v-model:value="unit"
/>
</template>
</a-input-number>
</j-input-number>
</j-modal>
</template>

View File

@ -1,12 +1,12 @@
<template>
<j-advanced-search
<pro-search
:columns="columns"
type="simple"
@search="handleSearch"
class="search"
target="scene-trigger-device-product"
/>
<a-divider style="margin: 0" />
<j-divider style="margin: 0" />
<j-pro-table
ref="actionRef"
model="CARD"
@ -48,16 +48,16 @@
</span>
</Ellipsis>
</div>
<a-row>
<a-col :span="12">
<j-row>
<j-col :span="12">
<div class="card-item-content-text">设备类型</div>
<Ellipsis>{{ slotProps.deviceType?.text }}</Ellipsis>
</a-col>
<a-col :span="12">
</j-col>
<j-col :span="12">
<div class="card-item-content-text">接入方式</div>
<Ellipsis>{{ slotProps?.accessName || '未接入' }}</Ellipsis>
</a-col>
</a-row>
</j-col>
</j-row>
</template>
</CardBox>
</template>

View File

@ -15,13 +15,16 @@
</template>
<template v-else>
<ParamsDropdown
icon="icon-canshu"
placeholder="请选择"
:options="[]"
:tabsOptions="tabOptions"
:metricOption="upperOptions(record.valueType)"
v-model:value="record.value"
/>
>
<template v-slot="{label}">
<j-input :value="label" />
</template>
</ParamsDropdown>
</template>
</div>
</template>

View File

@ -1,6 +1,6 @@
<template>
<div>
<a-form :layout="'vertical'" ref="formRef" :model="modelRef">
<j-form :layout="'vertical'" ref="formRef" :model="modelRef">
<j-row>
<j-col :span="11">
<j-form-item
@ -40,7 +40,7 @@
</j-form-item>
</j-col>
</j-row>
</a-form>
</j-form>
</div>
</template>

View File

@ -1,6 +1,6 @@
<template>
<div>
<a-form :layout="'vertical'" ref="formRef" :model="modelRef">
<j-form :layout="'vertical'" ref="formRef" :model="modelRef">
<j-form-item
:name="['message', 'messageType']"
label="动作类型"
@ -67,7 +67,7 @@
:builtInList="builtInList"
/>
</template>
</a-form>
</j-form>
</div>
</template>
@ -211,6 +211,7 @@ watch(
watch(
() => props.values?.message,
(newVal) => {
console.log(newVal)
if (newVal?.messageType) {
modelRef.message = newVal;
if (newVal.messageType === 'INVOKE_FUNCTION' && newVal.functionId) {

View File

@ -1,12 +1,12 @@
<template>
<j-advanced-search
<pro-search
:columns="columns"
type="simple"
@search="handleSearch"
class="search"
target="scene-trigger-device-device"
/>
<a-divider style="margin: 0" />
<j-divider style="margin: 0" />
<j-pro-table
ref="actionRef"
model="CARD"
@ -153,7 +153,7 @@ const deviceQuery = (p: any) => {
if (props.value) {
sorts.push({
name: 'id',
value: props.value,
value: props.value[0]?.value,
});
}
sorts.push({ name: 'createTime', order: 'desc' });

View File

@ -1,6 +1,6 @@
<template>
<div>
<a-form :layout="'vertical'" ref="formRef" :model="modelRef">
<j-form :layout="'vertical'" ref="formRef" :model="modelRef">
<j-form-item
name="selector"
label="选择方式"
@ -64,16 +64,16 @@
:fieldNames="{ label: 'name', value: 'id' }"
>
<template #title="{ name, description }">
<a-space>
<j-space>
{{ name }}
<span style="color: grey; margin-left: 5px">{{
description
}}</span>
</a-space>
</j-space>
</template>
</j-tree-select>
</j-form-item>
</a-form>
</j-form>
</div>
</template>

View File

@ -19,17 +19,17 @@
v-if="data?.executor === 'alarm'"
>
<template v-if="data?.alarm?.mode === 'trigger'">
满足条件后将触发<a-button
满足条件后将触发<j-button style="padding: 0;"
type="link"
@click.stop="triggerVisible = true"
>关联此场景的告警</a-button
>关联此场景的告警</j-button
>
</template>
<template v-else>
满足条件后将解除<a-button
满足条件后将解除<j-button style="padding: 0;"
type="link"
@click.stop="triggerVisible = true"
>关联此场景的告警</a-button
>关联此场景的告警</j-button
>
</template>
</div>
@ -308,14 +308,14 @@
</div>
</template>
</div>
<a-button v-else @click="onAdd">点击配置执行动作</a-button>
<j-button v-else @click="onAdd">点击配置执行动作</j-button>
</div>
<div class="item-number">{{ name + 1 }}</div>
<a-popconfirm title="确认删除?" @confirm="onDelete">
<j-popconfirm title="确认删除?" @confirm="onDelete">
<div class="item-delete">
<AIcon type="DeleteOutlined" />
</div>
</a-popconfirm>
</j-popconfirm>
</div>
<template v-if="!isLast && type === 'serial'">
<div class="actions-item-filter-warp">

View File

@ -4,7 +4,7 @@
<Device v-bind="props" :value="data?.device" @cancel="onCancel" @save="onPropsOk" :thenName="branchesName" />
</template>
<template v-else-if="actionType === 'notify'">
<Notify v-bind="props" :value="data?.notify" @cancel="onCancel" @save="onPropsOk" />
<Notify :options="data?.options" :value="data?.notify" @cancel="onCancel" @save="onPropsOk" />
</template>
<template v-else-if="actionType === 'delay'">
<Delay :value="data?.delay" @cancel="onCancel" @save="onPropsOk" />
@ -55,7 +55,7 @@ const onPropsOk = (data: any, options: any) => {
type: props.actionType,
executor: props.actionType,
key: props?.data?.key || `${props.actionType}_${new Date().getTime()}`,
device: {
[props.actionType]: {
...data,
},
};

View File

@ -7,8 +7,8 @@
@ok="onOk"
:maskClosable="false"
>
<a-form ref="actionForm" :model="formModel" layout="vertical">
<a-form-item
<j-form ref="actionForm" :model="formModel" layout="vertical">
<j-form-item
label="类型"
name="type"
:rules="[
@ -19,7 +19,7 @@
]"
>
<CardSelect v-model:value="formModel.type" :options="options"/>
</a-form-item>
</j-form-item>
<ActionTypeComponent
v-bind="props"
v-if="!!actionType"
@ -27,7 +27,7 @@
@save="onPropsOk"
@cancel="onPropsCancel"
/>
</a-form>
</j-form>
</j-modal>
</template>

View File

@ -1,5 +1,5 @@
<template>
<j-advanced-search
<pro-search
:columns="columns"
type="simple"
target="action-notice-config"
@ -9,22 +9,7 @@
<div style="height: 400px; overflow-y: auto">
<JProTable
:columns="columns"
:request="(e) => ConfigApi.list({
...e,
terms: [
...e?.terms,
{
terms: [
{
termType: 'eq',
column: 'type',
value: props.notifyType,
},
],
},
],
sorts: [{ name: 'id', value: props.value }, { name: 'createTime', order: 'desc' }],
})"
:request="query"
model="CARD"
:bodyStyle="{
paddingRight: 0,
@ -34,8 +19,8 @@
:gridColumn="2"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
>
<template #card="slotProps">
<CardBox
@ -63,22 +48,22 @@
{{ slotProps.name }}
</span>
</Ellipsis>
<a-row>
<a-col :span="12">
<j-row>
<j-col :span="12">
<div class="card-item-content-text">
通知方式
</div>
<div>
{{ getMethodTxt(slotProps.type) }}
</div>
</a-col>
<a-col :span="12">
</j-col>
<j-col :span="12">
<div class="card-item-content-text">说明</div>
<Ellipsis>
{{ slotProps.description }}
</Ellipsis>
</a-col>
</a-row>
</j-col>
</j-row>
</template>
</CardBox>
</template>
@ -100,7 +85,7 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value']);
const emit = defineEmits(['update:value', 'change']);
const getLogo = (type: string, provider: string) => {
return MSG_TYPE[type].find((f: any) => f.value === provider)?.logo;
@ -140,17 +125,39 @@ const columns = [
},
];
const query = (e: Record<string, any>) =>
ConfigApi.list({
...e,
terms: [
...e?.terms,
{
terms: [
{
termType: 'eq',
column: 'type',
value: props.notifyType,
},
],
},
],
sorts: [
{ name: 'id', value: props.value },
{ name: 'createTime', order: 'desc' },
],
});
const handleSearch = (_params: any) => {
params.value = _params;
};
const cancelSelect = () => {
_selectedRowKeys.value = [];
const onSelectChange = (keys: string[]) => {
_selectedRowKeys.value = [...keys];
};
const handleClick = (dt: any) => {
_selectedRowKeys.value = [dt.id];
emit('update:value', dt.id);
emit('change', { provider: dt?.provider });
};
watch(
@ -176,7 +183,7 @@ watch(
padding-left: 0px;
}
.logo{
.logo {
width: 88px;
height: 88px;
}

View File

@ -1,5 +1,5 @@
<template>
<j-advanced-search
<pro-search
:columns="columns"
type="simple"
target="action-notice-template"
@ -19,8 +19,8 @@
:gridColumn="2"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
>
<template #card="slotProps">
<CardBox
@ -48,22 +48,22 @@
{{ slotProps.name }}
</span>
</Ellipsis>
<a-row>
<a-col :span="12">
<j-row>
<j-col :span="12">
<div class="card-item-content-text">
通知方式
</div>
<div>
{{ getMethodTxt(slotProps.type) }}
</div>
</a-col>
<a-col :span="12">
</j-col>
<j-col :span="12">
<div class="card-item-content-text">说明</div>
<Ellipsis>
{{ slotProps.description }}
</Ellipsis>
</a-col>
</a-row>
</j-col>
</j-row>
</template>
</CardBox>
</template>
@ -85,7 +85,7 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value']);
const emit = defineEmits(['update:value', 'change']);
const getLogo = (type: string, provider: string) => {
return MSG_TYPE[type].find((f: any) => f.value === provider)?.logo;
@ -129,13 +129,14 @@ const handleSearch = (_params: any) => {
params.value = _params;
};
const cancelSelect = () => {
_selectedRowKeys.value = [];
};
const handleClick = (dt: any) => {
_selectedRowKeys.value = [dt.id];
emit('update:value', dt.id);
emit('change', { templateName: dt?.name });
};
const onSelectChange = (keys: string[]) => {
_selectedRowKeys.value = [...keys];
};
const handleData = async (e: any) => {
@ -178,8 +179,7 @@ watch(
<style lang="less" scoped>
.search {
margin-bottom: 0;
padding-right: 0px;
padding-left: 0px;
padding: 0;
}
.logo {

View File

@ -1,5 +1,5 @@
<template>
<a-spin :spinning="loading">
<j-spin :spinning="loading">
<div class="notify-type-warp" :class="{ disabled: disabled }">
<div
:key="item.id"
@ -14,7 +14,7 @@
<div class="notify-type-item-title">{{item.label}}</div>
</div>
</div>
</a-spin>
</j-spin>
</template>
<script lang="ts" setup>
@ -40,7 +40,7 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value']);
const emit = defineEmits(['update:value', 'change']);
const loading = ref<boolean>(false);
const notifyType = ref('');
@ -57,6 +57,7 @@ watch(
const onSelect = (val: string) => {
if (!props.disabled) {
emit('update:value', val);
emit('change', val);
}
};

View File

@ -1,11 +1,11 @@
<template>
<a-form
<j-form
v-if="variableDefinitions.length"
:layout="'vertical'"
ref="formRef"
:model="modelRef"
>
<a-form-item
<j-form-item
:name="`${item?.id}`"
:label="item?.name"
v-for="item in variableDefinitions"
@ -14,7 +14,7 @@
:rules="[
{
validator: (_rule, value) => checkValue(_rule, value, item),
trigger: 'change',
trigger: ['change', 'blur']
},
]"
>
@ -27,23 +27,25 @@
:notify="notify"
v-else-if="getType(item) === 'org'"
v-model:value="modelRef[item.id]"
@change="(val) => onChange(val, 'org')"
/>
<Tag
:notify="notify"
v-else-if="getType(item) === 'tag'"
v-model:value="modelRef[item.id]"
@change="(val) => onChange(val, 'tag')"
/>
<InputFile
v-else-if="getType(item) === 'file'"
v-model:value="modelRef[item.id]"
/>
<a-input
<j-input
v-else-if="getType(item) === 'link'"
v-model:value="modelRef[item.id]"
/>
<BuildIn v-else :item="item" v-model:value="modelRef[item.id]" />
</a-form-item>
</a-form>
</j-form-item>
</j-form>
</template>
<script lang="ts" setup>
@ -69,6 +71,8 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value', 'change']);
const formRef = ref();
const modelRef = reactive({});
@ -111,14 +115,14 @@ const checkValue = (_rule: any, value: any, item: any) => {
}
}
}
} else if (value.source === 'fixed' && !value.value) {
} else if (value?.source === 'fixed' && !value.value) {
return Promise.reject(new Error('请输入' + item.name));
} else if (value.source === 'relation' && !value.value && !value.relation) {
} else if (value?.source === 'relation' && !value.value && !value.relation) {
return Promise.reject(new Error('请选择' + item.name));
} else if (value.source === 'upper' && !value.upperKey) {
} else if (value?.source === 'upper' && !value.upperKey) {
return Promise.reject(new Error('请选择' + item.name));
} else if (type === 'user') {
if (props.notify.notifyType === 'email') {
if (props.notify.notifyType === 'email' && value?.source !== 'relation') {
if (Array.isArray(value.value)) {
if (!value.value.length) {
return Promise.reject(new Error('请输入收件人'));
@ -139,7 +143,7 @@ const checkValue = (_rule: any, value: any, item: any) => {
}
if (
props.notify.notifyType &&
['sms', 'voice'].includes(props?.notify?.notifyType)
['sms', 'voice'].includes(props?.notify?.notifyType) && value?.source !== 'relation'
) {
const reg = /^[1][3-9]\d{9}$/;
if (!reg.test(value.value)) {
@ -151,4 +155,21 @@ const checkValue = (_rule: any, value: any, item: any) => {
}
return Promise.resolve();
};
const onChange = (val: any, type: any) => {
if (type === 'org') {
emit('change', { orgName: val.join(',') });
} else if (type === 'tag') {
emit('change', { tagName: val });
}
};
const onSave = () =>
new Promise((resolve) => {
formRef.value.validate().then(async (_data: any) => {
resolve(_data);
});
});
defineExpose({ onSave });
</script>

View File

@ -8,17 +8,17 @@
:maskClosable="false"
>
<div class="steps-steps">
<a-steps :current="current" size="small" @change="onChange">
<a-step title="通知方式" key="way" />
<a-step title="通知配置" key="config" />
<a-step title="通知模板" key="template" />
<a-step title="模板变量" key="variable" />
</a-steps>
<j-steps :current="current" size="small" @change="onChange">
<j-step title="通知方式" key="way" />
<j-step title="通知配置" key="config" />
<j-step title="通知模板" key="template" />
<j-step title="模板变量" key="variable" />
</j-steps>
</div>
<div class="steps-content">
<a-form ref="actionForm" :model="formModel" layout="vertical">
<j-form ref="actionForm" :model="formModel" layout="vertical">
<template v-if="current === 0">
<a-form-item
<j-form-item
label="应用"
name="notifyType"
:rules="[
@ -28,38 +28,45 @@
},
]"
>
<NotifyWay v-model:value="formModel.notifyType" />
</a-form-item>
<NotifyWay
v-model:value="formModel.notifyType"
@change="(val) => onValChange(val, 'notifyType')"
/>
</j-form-item>
</template>
<template v-if="current === 1">
<a-form-item name="notifierId">
<j-form-item name="notifierId">
<NotifyConfig
v-model:value="formModel.notifierId"
:notifyType="formModel.notifyType"
@change="(val) => onValChange(val, 'notifierId')"
/>
</a-form-item>
</j-form-item>
</template>
<template v-if="current === 2">
<a-form-item name="templateId">
<j-form-item name="templateId">
<NotifyTemplate
v-model:value="formModel.templateId"
:notifierId="formModel.notifierId"
@change="(val) => onValChange(val, 'templateId')"
/>
</a-form-item>
</j-form-item>
</template>
<template v-if="current === 3">
<a-form-item name="variables">
<j-form-item name="variables">
<VariableDefinitions
:variableDefinitions="variable"
v-model:value="formModel.variables"
:value="formModel.variables"
:notify="formModel"
@change="(val) => onValChange(val, 'variables')"
ref="variableRef"
/>
</a-form-item>
</j-form-item>
</template>
</a-form>
</j-form>
</div>
<template #footer>
<a-space>
<j-space>
<j-button v-if="current === 0" @click="onCancel">取消</j-button>
<j-button v-if="current > 0" @click="prev">上一步</j-button>
<j-button v-if="current < 3" type="primary" @click="next"
@ -68,7 +75,7 @@
<j-button v-if="current === 3" type="primary" @click="onOk"
>确定</j-button
>
</a-space>
</j-space>
</template>
</j-modal>
</template>
@ -90,6 +97,7 @@ const props = defineProps({
},
options: {
type: Object,
default: () => {},
},
name: {
type: Number,
@ -106,9 +114,11 @@ const formModel = reactive({
notifierId: '',
templateId: '',
variables: {},
options: {},
});
const variable = ref([]);
const variableRef = ref();
watch(
() => props.value,
@ -118,6 +128,27 @@ watch(
{ deep: true, immediate: true },
);
watchEffect(() => {
formModel.options = props.options || {};
});
const onValChange = (val: any, type: string) => {
if (type === 'notifyType') {
formModel.templateId = '';
formModel.variables = [];
formModel.notifierId = '';
} else if (type === 'notifierId') {
formModel.templateId = '';
formModel.variables = [];
} else if (type === 'templateId') {
formModel.variables = [];
}
formModel.options = {
...unref(formModel.options),
...val,
};
};
const jumpStep = async (val: number) => {
if (val === 0) {
current.value = val;
@ -134,7 +165,6 @@ const jumpStep = async (val: number) => {
onlyMessage('请选择通知配置', 'error');
}
} else if (val === 3) {
formModel.templateId = '1628943618904956928';
if (formModel.templateId) {
const resp = await Template.getTemplateDetail(formModel.templateId);
if (resp.status === 200) {
@ -162,8 +192,11 @@ const next = async () => {
const onCancel = () => {
emit('cancel');
};
const onOk = () => {
emit('save');
const onOk = async () => {
const _data = await variableRef.value.onSave();
formModel.variables = _data;
const { options, ...extra } = formModel;
emit('save', { ...extra }, { ...options });
};
</script>

View File

@ -1,6 +1,6 @@
<template>
<a-input-group compact>
<a-select
<j-input-group compact>
<j-select
:options="[
{ label: '手动输入', value: 'fixed' },
{ label: '内置参数', value: 'upper' },
@ -10,22 +10,22 @@
@change="sourceChange"
/>
<template v-if="source === 'upper'">
<a-tree-select
<j-tree-select
v-model:value="upperKey"
:treeData="builtInList"
placeholder="请选择参数"
style="width: calc(100% - 120px)"
>
<template #title="{ name, description }">
<a-space>
<j-space>
{{ name }}
<span style="color: grey; margin-left: 5px">{{ description }}</span>
</a-space>
</j-space>
</template>
</a-tree-select>
</j-tree-select>
</template>
<template v-else>
<a-date-picker
<j-date-picker
:value="value.value"
allowClear
format="YYYY-MM-DD HH:mm:ss"
@ -33,7 +33,7 @@
v-if="item.type === 'date'"
@change="(_, dateString) => itemOnChange(dateString)"
/>
<a-input-number
<j-input-number
:value="value.value"
allowClear
style="width: calc(100% - 120px)"
@ -41,7 +41,7 @@
:placeholder="`请输入${item.name}`"
@change="itemOnChange"
/>
<a-input
<j-input
:value="value.value"
allowClear
style="width: calc(100% - 120px)"
@ -50,7 +50,7 @@
@change="(e) => itemOnChange(e.target.value)"
/>
</template>
</a-input-group>
</j-input-group>
</template>
<script lang="ts" setup>

View File

@ -1,12 +1,12 @@
<template>
<a-input
<j-input
allowClear
placeholder="请上传文件"
v-model:value="url"
@change="onChange"
>
<template #addonAfter>
<a-upload
<j-upload
name="file"
:showUploadList="false"
:accept="'image/jpeg,image/png'"
@ -23,9 +23,9 @@
<AIcon type="PlusOutlined" v-else />
上传附件
</j-button>
</a-upload>
</j-upload>
</template>
</a-input>
</j-input>
</template>
<script lang="ts" setup>

View File

@ -26,7 +26,7 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value']);
const emit = defineEmits(['update:value', 'change']);
const departmentTree = ref<any[]>([]);
const keys = ref<any[]>([]);
@ -68,6 +68,7 @@ const onChange = (key: string[], label: string[]) => {
source: 'fixed',
value: key,
});
emit('change', label)
};
</script>

View File

@ -22,10 +22,10 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value']);
const emit = defineEmits(['update:value', 'change']);
const tagsList = ref<any[]>([]);
const keys = ref<string>('');
const keys = ref<string | undefined>(undefined);
const getDepartment = async (id: string) => {
const resp = await TemplateApi.getTags(id);
@ -37,9 +37,9 @@ const getDepartment = async (id: string) => {
watch(
() => props.value,
(newVal) => {
keys.value = newVal || ''
keys.value = newVal || undefined
},
{ deep: true, immediate: true },
{ immediate: true },
);
watch(
@ -52,12 +52,12 @@ watch(
{ deep: true, immediate: true },
);
const onChange = (key: string, label: string[]) => {
// TODO label
const onChange = (key: string, option: any) => {
emit('update:value', {
source: 'fixed',
value: key,
});
emit('change', option ? option?.label : '')
};
</script>

View File

@ -1,83 +1,87 @@
<template>
<a-input-group compact>
<a-select
<j-input-group compact>
<j-select
style="width: 120px"
v-model:value="mySource"
@change="sourceChange"
>
<a-select-option key="5" value="relation">
<j-select-option key="5" value="relation">
平台用户
</a-select-option>
<a-select-option
</j-select-option>
<j-select-option
v-if="notifyType === 'dingTalk'"
key="1"
value="fixed"
>
钉钉用户
</a-select-option>
<a-select-option
</j-select-option>
<j-select-option
v-else-if="notifyType === 'weixin'"
key="2"
value="fixed"
>
微信用户
</a-select-option>
<a-select-option
</j-select-option>
<j-select-option
v-else-if="notifyType === 'email'"
key="3"
value="fixed"
>
固定邮箱
</a-select-option>
<a-select-option v-else key="4" value="fixed">
</j-select-option>
<j-select-option v-else key="4" value="fixed">
固定号码
</a-select-option>
</a-select>
<a-tree-select
</j-select-option>
</j-select>
<j-tree-select
v-if="source === 'relation'"
style="width: calc(100% - 120px)"
placeholder="请选择收信人"
@select="treeSelect"
@select="(key, node) => onChange(source, key, false, node?.relation, node.name)"
:tree-data="treeData"
:multiple="['email'].includes(notifyType)"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:value="relationData"
/>
<a-select
style="width: calc(100% - 120px)"
v-else-if="['dingTalk', 'weixin'].includes(notifyType)"
placeholder="请选择收信人"
:value="value?.value"
@change="(val) => onChange(val)"
>
<a-select-option
v-for="item in relationList"
:key="item.id"
:value="item.id"
>{{ item.name }}</a-select-option
>
</a-select>
<a-input
style="width: calc(100% - 120px)"
v-else-if="['email'].includes(notifyType)"
placeholder="请输入固定邮箱"
:value="value?.value"
:multiple="true"
@change="(e) => onChange(e.target.value)"
></a-input>
<a-input
style="width: calc(100% - 120px)"
v-else-if="['sms', 'voice'].includes(notifyType)"
placeholder="请输入固定号码"
:value="value?.value"
@change="(e) => onChange(e.target.value)"
></a-input>
</a-input-group>
<template #title="{ key, username, title }">
<div style="display: flex; justify-content: space-between; margin-right: 10px;" v-if="key !== 'p1' && key !== 'p2'">{{ title }} <span style="color: #cfcfcf;">{{ username }}</span></div>
<span v-else>{{ title }}</span>
</template>
</j-tree-select>
<template v-else>
<j-select
style="width: calc(100% - 120px)"
v-if="['dingTalk', 'weixin'].includes(notifyType)"
placeholder="请选择收信人"
:value="value?.value"
showSearch
@change="(val, option) => onChange(source, val, false, option?.label || option?.name)"
:options="relationList"
/>
<j-select
style="width: calc(100% - 120px)"
v-else-if="['email'].includes(notifyType)"
placeholder="请输入收件人邮箱,多个收件人用换行分隔"
:value="value?.value"
mode="tags"
@change="(val) => onChange(source, val, false, Array.isArray(val) ? val.join(',') : val)"
/>
<j-input
style="width: calc(100% - 120px)"
v-else-if="['sms', 'voice'].includes(notifyType)"
placeholder="请输入固定号码"
:value="value?.value"
@change="(e) => onChange(source, e.target.value, false, e.target.value)"
></j-input>
</template>
</j-input-group>
</template>
<script lang="ts" setup>
import { storeToRefs } from 'pinia';
import { useSceneStore } from '@/store/scene';
import NoticeApi from '@/api/notice/config';
import { unionBy } from 'lodash-es';
const sceneStore = useSceneStore();
const { data } = storeToRefs(sceneStore);
@ -93,7 +97,7 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value']);
const emit = defineEmits(['update:value', 'change']);
const notifyType = computed(() => {
return props.notify?.notifyType;
@ -142,6 +146,7 @@ const treeData = ref<any[]>([
},
]);
const mySource = ref<string>('relation');
const labelMap = new Map();
const getRelationUsers = async (notifyType: string, notifierId: string) => {
let resp = undefined;
@ -151,7 +156,12 @@ const getRelationUsers = async (notifyType: string, notifierId: string) => {
resp = await NoticeApi.queryWechatUsers(notifierId);
}
if (resp && resp.status === 200) {
relationList.value = resp.result;
relationList.value = unionBy(resp.result, 'id').map((item: any) => {
return {
value: item.id,
label: item.name,
};
});
}
};
@ -206,43 +216,72 @@ const getUser = async (_source: string, triggerType: string) => {
treeData.value = newTree;
};
const treeSelect = (val: string, _data: any) => {
const obj = {
source: source.value,
relation: {}
};
if (_data?.isRelation) {
obj.relation = {
objectType: 'device',
objectSource: {
source: 'upper',
upperKey: 'scene.deviceId',
},
related: {
objectType: 'user',
relation: val,
},
};
} else {
obj.relation = {
objectType: 'user',
objectId: val,
};
}
emit('update:value', obj);
};
const sourceChange = (v: any) => {
emit('update:value', {
source: v,
});
};
const onChange = (val: any) => {
emit('update:value', {
source: source.value,
value: val,
});
const getObj = (
_source: string = 'fixed',
_value?: string | string[],
isRelation?: boolean,
) => {
const obj: any = {
source: _source,
};
if (_source === 'relation') {
if (isRelation) {
obj.relation = {
objectType: 'device',
objectSource: {
source: 'upper',
upperKey: 'deviceId',
},
related: {
objectType: 'user',
relation: _value,
},
};
} else {
obj.relation = {
objectType: 'user',
objectId: _value,
};
}
} else {
obj.value = _value;
}
return obj;
};
const onChange = (
_source: string = 'fixed',
_value?: string | string[],
isRelation?: boolean,
_name?: string,
) => {
let _values: any = undefined;
const _names: string[] = [_name || ''];
if (Array.isArray(_value)) {
if (props?.notify?.notifyType === 'email') {
if (isRelation) {
const arr = _value.map((item) => {
const _item = labelMap.get(item);
_names.push(_item?.name || '');
return getObj('relation', item, _item?.relation);
});
_values = arr;
} else {
_values = getObj(_source, _value, false);
}
}
} else {
_values = getObj(_source, _value, isRelation);
}
console.log(_values, '_values')
emit('update:value', _values);
emit('change', { sendTo: _names.filter((item) => !!item).join(',') });
};
watch(

View File

@ -8,8 +8,8 @@
/>
</div>
<div class="actions-warp">
<a-collapse v-model:activeKey="activeKeys">
<a-collapse-panel key="1">
<j-collapse v-model:activeKey="activeKeys">
<j-collapse-panel key="1">
<template #header>
<span>
串行
@ -27,11 +27,11 @@
serialArray.length ? serialArray[0].actions : []
"
@add="(_item) => onAdd(_item, false)"
@delete="onDelete"
@delete="(_key) => onDelete(_key, false)"
/>
</div>
</a-collapse-panel>
<a-collapse-panel key="2">
</j-collapse-panel>
<j-collapse-panel key="2">
<template #header>
<span>
并行
@ -51,11 +51,11 @@
: []
"
@add="(_item) => onAdd(_item, true)"
@delete="onDelete"
@delete="(_key) => onDelete(_key, true)"
/>
</div>
</a-collapse-panel>
</a-collapse>
</j-collapse-panel>
</j-collapse>
</div>
</div>
</template>
@ -98,8 +98,6 @@ watch(
parallelArray.value = newVal.filter((item) => item.parallel);
serialArray.value = newVal.filter((item) => !item.parallel);
console.log(parallelArray.value, serialArray.value, '123')
const isSerialActions = serialArray.value.some((item) => {
return !!item.actions.length;
});
@ -121,28 +119,39 @@ watch(
},
);
const onDelete = (_key: string) => {
const aIndex = unref(serialArray)[0].actions?.findIndex(
const onDelete = (_key: string, _parallel: boolean) => {
const newArray = _parallel ? [...parallelArray.value] : [...serialArray.value];
const aIndex = newArray[0].actions?.findIndex(
(aItem) => aItem.key === _key,
);
if (aIndex !== -1) {
serialArray.value[0].actions?.splice(aIndex, 1);
emit('update', serialArray[0], false);
if(_parallel){
parallelArray.value[0].actions?.splice(aIndex, 1);
emit('update', parallelArray.value[0], _parallel);
} else {
serialArray.value[0].actions?.splice(aIndex, 1);
emit('update', serialArray.value[0], _parallel);
}
}
};
const onAdd = (actionItem: any, _parallel: boolean) => {
const newParallelArray = [...parallelArray.value];
if (newParallelArray.length) {
const indexOf = newParallelArray[0].actions?.findIndex(
const newArray = _parallel ? [...parallelArray.value] : [...serialArray.value];
if (newArray.length) {
const indexOf = newArray[0].actions?.findIndex(
(aItem) => aItem.key === actionItem.key,
);
if (indexOf !== -1) {
newParallelArray[0].actions.splice(indexOf, 1, actionItem);
newArray[0].actions.splice(indexOf, 1, actionItem);
} else {
newParallelArray[0].actions.push(actionItem);
newArray[0].actions.push(actionItem);
}
parallelArray.value = [...newParallelArray];
emit('update', newParallelArray[0], _parallel);
if(_parallel){
parallelArray.value = [...newArray];
} else {
serialArray.value = [...newArray];
}
emit('update', newArray[0], _parallel);
} else {
actionItem.key = randomString();
emit('add', {

View File

@ -1,17 +1,17 @@
<template>
<div class="shakeLimit">
<a-switch
<j-switch
checkedChildren="开启防抖"
unCheckedChildren="关闭防抖"
v-model:checked="shakeLimit.enabled"
style="margin-right: 12px"
/>
<template v-if="shakeLimit.enabled">
<a-input-number :min="1" :max="100" :precision="0" size="small" v-model:value="shakeLimit.time" style="width: 32px" />
<j-input-number :min="1" :max="100" :precision="0" size="small" v-model:value="shakeLimit.time" style="width: 32px" />
<span>秒内发送</span>
<a-input-number :min="1" :max="100" :precision="0" size="small" v-model:value="shakeLimit.threshold" style="width: 32px" />
<j-input-number :min="1" :max="100" :precision="0" size="small" v-model:value="shakeLimit.threshold" style="width: 32px" />
<span>次及以上时处理</span>
<a-radio-group :options="alarmFirstOptions" optionType="button" v-model:value="shakeLimit.alarmFirst" size="small" />
<j-radio-group :options="alarmFirstOptions" optionType="button" v-model:value="shakeLimit.alarmFirst" size="small" />
</template>
</div>
</template>

11855
yarn.lock

File diff suppressed because it is too large Load Diff