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), 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: '说明', title: '说明',
dataIndex: 'describe', dataIndex: 'description',
key: 'describe', key: 'description',
search: { search: {
type: 'string', type: 'string',
}, },

View File

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

View File

@ -144,7 +144,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { queryNoPagingPost } from '@/api/device/product'; import { queryGatewayList, queryNoPagingPost } from '@/api/device/product';
import { queryTree } from '@/api/device/category'; import { queryTree } from '@/api/device/category';
import { message } from 'jetlinks-ui-components'; import { message } from 'jetlinks-ui-components';
import { ActionsType } from '@/views/device/Instance/typings'; 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', dataIndex: 'deviceType',
title: '设备类型', title: '设备类型',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,17 +19,17 @@
v-if="data?.executor === 'alarm'" v-if="data?.executor === 'alarm'"
> >
<template v-if="data?.alarm?.mode === 'trigger'"> <template v-if="data?.alarm?.mode === 'trigger'">
满足条件后将触发<a-button 满足条件后将触发<j-button style="padding: 0;"
type="link" type="link"
@click.stop="triggerVisible = true" @click.stop="triggerVisible = true"
>关联此场景的告警</a-button >关联此场景的告警</j-button
> >
</template> </template>
<template v-else> <template v-else>
满足条件后将解除<a-button 满足条件后将解除<j-button style="padding: 0;"
type="link" type="link"
@click.stop="triggerVisible = true" @click.stop="triggerVisible = true"
>关联此场景的告警</a-button >关联此场景的告警</j-button
> >
</template> </template>
</div> </div>
@ -308,14 +308,14 @@
</div> </div>
</template> </template>
</div> </div>
<a-button v-else @click="onAdd">点击配置执行动作</a-button> <j-button v-else @click="onAdd">点击配置执行动作</j-button>
</div> </div>
<div class="item-number">{{ name + 1 }}</div> <div class="item-number">{{ name + 1 }}</div>
<a-popconfirm title="确认删除?" @confirm="onDelete"> <j-popconfirm title="确认删除?" @confirm="onDelete">
<div class="item-delete"> <div class="item-delete">
<AIcon type="DeleteOutlined" /> <AIcon type="DeleteOutlined" />
</div> </div>
</a-popconfirm> </j-popconfirm>
</div> </div>
<template v-if="!isLast && type === 'serial'"> <template v-if="!isLast && type === 'serial'">
<div class="actions-item-filter-warp"> <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" /> <Device v-bind="props" :value="data?.device" @cancel="onCancel" @save="onPropsOk" :thenName="branchesName" />
</template> </template>
<template v-else-if="actionType === 'notify'"> <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>
<template v-else-if="actionType === 'delay'"> <template v-else-if="actionType === 'delay'">
<Delay :value="data?.delay" @cancel="onCancel" @save="onPropsOk" /> <Delay :value="data?.delay" @cancel="onCancel" @save="onPropsOk" />
@ -55,7 +55,7 @@ const onPropsOk = (data: any, options: any) => {
type: props.actionType, type: props.actionType,
executor: props.actionType, executor: props.actionType,
key: props?.data?.key || `${props.actionType}_${new Date().getTime()}`, key: props?.data?.key || `${props.actionType}_${new Date().getTime()}`,
device: { [props.actionType]: {
...data, ...data,
}, },
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,12 @@
<template> <template>
<a-input <j-input
allowClear allowClear
placeholder="请上传文件" placeholder="请上传文件"
v-model:value="url" v-model:value="url"
@change="onChange" @change="onChange"
> >
<template #addonAfter> <template #addonAfter>
<a-upload <j-upload
name="file" name="file"
:showUploadList="false" :showUploadList="false"
:accept="'image/jpeg,image/png'" :accept="'image/jpeg,image/png'"
@ -23,9 +23,9 @@
<AIcon type="PlusOutlined" v-else /> <AIcon type="PlusOutlined" v-else />
上传附件 上传附件
</j-button> </j-button>
</a-upload> </j-upload>
</template> </template>
</a-input> </j-input>
</template> </template>
<script lang="ts" setup> <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 departmentTree = ref<any[]>([]);
const keys = ref<any[]>([]); const keys = ref<any[]>([]);
@ -68,6 +68,7 @@ const onChange = (key: string[], label: string[]) => {
source: 'fixed', source: 'fixed',
value: key, value: key,
}); });
emit('change', label)
}; };
</script> </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 tagsList = ref<any[]>([]);
const keys = ref<string>(''); const keys = ref<string | undefined>(undefined);
const getDepartment = async (id: string) => { const getDepartment = async (id: string) => {
const resp = await TemplateApi.getTags(id); const resp = await TemplateApi.getTags(id);
@ -37,9 +37,9 @@ const getDepartment = async (id: string) => {
watch( watch(
() => props.value, () => props.value,
(newVal) => { (newVal) => {
keys.value = newVal || '' keys.value = newVal || undefined
}, },
{ deep: true, immediate: true }, { immediate: true },
); );
watch( watch(
@ -52,12 +52,12 @@ watch(
{ deep: true, immediate: true }, { deep: true, immediate: true },
); );
const onChange = (key: string, label: string[]) => { const onChange = (key: string, option: any) => {
// TODO label
emit('update:value', { emit('update:value', {
source: 'fixed', source: 'fixed',
value: key, value: key,
}); });
emit('change', option ? option?.label : '')
}; };
</script> </script>

View File

@ -1,83 +1,87 @@
<template> <template>
<a-input-group compact> <j-input-group compact>
<a-select <j-select
style="width: 120px" style="width: 120px"
v-model:value="mySource" v-model:value="mySource"
@change="sourceChange" @change="sourceChange"
> >
<a-select-option key="5" value="relation"> <j-select-option key="5" value="relation">
平台用户 平台用户
</a-select-option> </j-select-option>
<a-select-option <j-select-option
v-if="notifyType === 'dingTalk'" v-if="notifyType === 'dingTalk'"
key="1" key="1"
value="fixed" value="fixed"
> >
钉钉用户 钉钉用户
</a-select-option> </j-select-option>
<a-select-option <j-select-option
v-else-if="notifyType === 'weixin'" v-else-if="notifyType === 'weixin'"
key="2" key="2"
value="fixed" value="fixed"
> >
微信用户 微信用户
</a-select-option> </j-select-option>
<a-select-option <j-select-option
v-else-if="notifyType === 'email'" v-else-if="notifyType === 'email'"
key="3" key="3"
value="fixed" value="fixed"
> >
固定邮箱 固定邮箱
</a-select-option> </j-select-option>
<a-select-option v-else key="4" value="fixed"> <j-select-option v-else key="4" value="fixed">
固定号码 固定号码
</a-select-option> </j-select-option>
</a-select> </j-select>
<a-tree-select <j-tree-select
v-if="source === 'relation'" v-if="source === 'relation'"
style="width: calc(100% - 120px)" style="width: calc(100% - 120px)"
placeholder="请选择收信人" placeholder="请选择收信人"
@select="treeSelect" @select="(key, node) => onChange(source, key, false, node?.relation, node.name)"
:tree-data="treeData" :tree-data="treeData"
:multiple="['email'].includes(notifyType)"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:value="relationData" :value="relationData"
/> >
<a-select <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)" style="width: calc(100% - 120px)"
v-else-if="['dingTalk', 'weixin'].includes(notifyType)" v-if="['dingTalk', 'weixin'].includes(notifyType)"
placeholder="请选择收信人" placeholder="请选择收信人"
:value="value?.value" :value="value?.value"
@change="(val) => onChange(val)" showSearch
> @change="(val, option) => onChange(source, val, false, option?.label || option?.name)"
<a-select-option :options="relationList"
v-for="item in relationList" />
:key="item.id" <j-select
:value="item.id"
>{{ item.name }}</a-select-option
>
</a-select>
<a-input
style="width: calc(100% - 120px)" style="width: calc(100% - 120px)"
v-else-if="['email'].includes(notifyType)" v-else-if="['email'].includes(notifyType)"
placeholder="请输入固定邮箱" placeholder="请输入收件人邮箱,多个收件人用换行分隔"
:value="value?.value" :value="value?.value"
:multiple="true" mode="tags"
@change="(e) => onChange(e.target.value)" @change="(val) => onChange(source, val, false, Array.isArray(val) ? val.join(',') : val)"
></a-input> />
<a-input <j-input
style="width: calc(100% - 120px)" style="width: calc(100% - 120px)"
v-else-if="['sms', 'voice'].includes(notifyType)" v-else-if="['sms', 'voice'].includes(notifyType)"
placeholder="请输入固定号码" placeholder="请输入固定号码"
:value="value?.value" :value="value?.value"
@change="(e) => onChange(e.target.value)" @change="(e) => onChange(source, e.target.value, false, e.target.value)"
></a-input> ></j-input>
</a-input-group> </template>
</j-input-group>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useSceneStore } from '@/store/scene'; import { useSceneStore } from '@/store/scene';
import NoticeApi from '@/api/notice/config'; import NoticeApi from '@/api/notice/config';
import { unionBy } from 'lodash-es';
const sceneStore = useSceneStore(); const sceneStore = useSceneStore();
const { data } = storeToRefs(sceneStore); 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(() => { const notifyType = computed(() => {
return props.notify?.notifyType; return props.notify?.notifyType;
@ -142,6 +146,7 @@ const treeData = ref<any[]>([
}, },
]); ]);
const mySource = ref<string>('relation'); const mySource = ref<string>('relation');
const labelMap = new Map();
const getRelationUsers = async (notifyType: string, notifierId: string) => { const getRelationUsers = async (notifyType: string, notifierId: string) => {
let resp = undefined; let resp = undefined;
@ -151,7 +156,12 @@ const getRelationUsers = async (notifyType: string, notifierId: string) => {
resp = await NoticeApi.queryWechatUsers(notifierId); resp = await NoticeApi.queryWechatUsers(notifierId);
} }
if (resp && resp.status === 200) { 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; 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) => { const sourceChange = (v: any) => {
emit('update:value', { emit('update:value', {
source: v, source: v,
}); });
}; };
const onChange = (val: any) => { const getObj = (
emit('update:value', { _source: string = 'fixed',
source: source.value, _value?: string | string[],
value: val, 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( watch(

View File

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

View File

@ -1,17 +1,17 @@
<template> <template>
<div class="shakeLimit"> <div class="shakeLimit">
<a-switch <j-switch
checkedChildren="开启防抖" checkedChildren="开启防抖"
unCheckedChildren="关闭防抖" unCheckedChildren="关闭防抖"
v-model:checked="shakeLimit.enabled" v-model:checked="shakeLimit.enabled"
style="margin-right: 12px" style="margin-right: 12px"
/> />
<template v-if="shakeLimit.enabled"> <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> <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> <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> </template>
</div> </div>
</template> </template>

11855
yarn.lock

File diff suppressed because it is too large Load Diff