feat: 订阅管理
This commit is contained in:
parent
0a479ee058
commit
2b740da418
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -30,3 +30,8 @@ export const checkOldPassword_api = (password:string) => server.post(`/user/me/p
|
|||
'Content-Type': 'text/plain'
|
||||
}
|
||||
});
|
||||
|
||||
// 我的订阅
|
||||
// 查询当前用户可访问的通道配置
|
||||
export const getAllNotice = () => server.get(`/notify/channel/all`);
|
||||
|
||||
|
|
|
@ -1,4 +1,26 @@
|
|||
import server from '@/utils/request';
|
||||
|
||||
// 获取角色列表
|
||||
export const queryRoleList = (data: any): Promise<any> => server.post(`/role/_query/`, data);
|
||||
export const queryRoleList = (data: any): Promise<any> => server.post(`/role/_query/`, data);
|
||||
|
||||
// 查询所有通道配置
|
||||
export const queryChannelConfig = (): Promise<any> => server.get(`/notify/channel/all-for-save`);
|
||||
|
||||
// 查询通知通道类型
|
||||
export const queryChannelProviders = (): Promise<any> => server.get(`/notify/channel/providers`);
|
||||
|
||||
// 保存通道配置
|
||||
export const saveChannelConfig = (data: any[]): Promise<any> => server.patch(`/notify/channel`, data);
|
||||
|
||||
export const updateChannelConfig = (providerId: string, data: any[]): Promise<any> => server.patch(`/notify/channel/${providerId}`, data);
|
||||
|
||||
export const editChannelConfig = (providerId: string, data: any): Promise<any> => server.put(`/notify/channel/${providerId}`, data);
|
||||
|
||||
export const actionChannelConfig = (providerId: string, type: 'enable' | 'disable'): Promise<any> => server.post(`/notify/channel/${providerId}/${type}`);
|
||||
|
||||
export const deleteChannelConfig = (providerId: string): Promise<any> => server.remove(`/notify/channel/${providerId}`);
|
||||
|
||||
export const queryConfigVariables = (providerId: string): Promise<any> => server.get(`/notify/channel/${providerId}/variables`);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
<template>
|
||||
<div class="box">
|
||||
<div class="content">
|
||||
<div class="content-item" v-for="item in bindList" :key="item.id">
|
||||
<div class="content-item-left">
|
||||
<img
|
||||
:src="item.logoUrl || getImage(bindIcon[item.provider])"
|
||||
style="height: 50px; width: 50px"
|
||||
width="50px"
|
||||
height="50px"
|
||||
alt=""
|
||||
/>
|
||||
<Ellipsis style="max-width: 200px; font-size: 22px">{{
|
||||
item?.name
|
||||
}}</Ellipsis>
|
||||
<template v-if="bindList.length">
|
||||
<div class="content-item" v-for="item in bindList" :key="item.id">
|
||||
<div class="content-item-left">
|
||||
<img
|
||||
:src="item.logoUrl || getImage(bindIcon[item.provider])"
|
||||
style="height: 50px; width: 50px"
|
||||
width="50px"
|
||||
height="50px"
|
||||
alt=""
|
||||
/>
|
||||
<Ellipsis style="max-width: 200px; font-size: 22px">{{
|
||||
item?.name
|
||||
}}</Ellipsis>
|
||||
<div>
|
||||
<j-tag v-if="item.bound">已绑定</j-tag>
|
||||
<j-tag v-else>未绑定</j-tag>
|
||||
</div>
|
||||
<div v-if="item.others?.name">
|
||||
绑定名:{{ item.others?.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<j-tag v-if="item.bound">已绑定</j-tag>
|
||||
<j-tag v-else>未绑定</j-tag>
|
||||
</div>
|
||||
<div v-if="item.others?.name">
|
||||
绑定名:{{ item.others?.name }}
|
||||
<j-popconfirm
|
||||
v-if="item.bound"
|
||||
title="确认解除绑定嘛?"
|
||||
@confirm="() => unBind(item.id)"
|
||||
>
|
||||
<j-button>解除绑定</j-button>
|
||||
</j-popconfirm>
|
||||
<j-button v-else type="primary" @click="clickBind(item.id)"
|
||||
>立即绑定</j-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<j-popconfirm
|
||||
v-if="item.bound"
|
||||
title="确认解除绑定嘛?"
|
||||
@confirm="() => unBind(item.id)"
|
||||
>
|
||||
<j-button>解除绑定</j-button>
|
||||
</j-popconfirm>
|
||||
<j-button v-else type="primary" @click="clickBind(item.id)"
|
||||
>立即绑定</j-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<j-empty style="margin: 200px 0;" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<template>
|
||||
<div style="margin-top: 24px;">
|
||||
<j-tabs tab-position="left">
|
||||
<j-tab-pane v-for="item in tabs" :key="item.key" :tab="item.tab"><NotificationRecord /></j-tab-pane>
|
||||
<j-tabs tab-position="left" v-if="tabs.length">
|
||||
<j-tab-pane v-for="item in tabs" :key="item.key" :tab="item.tab">
|
||||
<NotificationRecord />
|
||||
</j-tab-pane>
|
||||
</j-tabs>
|
||||
<j-empty v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<div><j-button type="link">取消订阅</j-button></div>
|
||||
<template v-if="['dingTalk', 'weixin'].includes(type)">
|
||||
<div><j-button type="link">更换接收账号</j-button></div>
|
||||
<p>当前绑定的账号名称</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div><j-button type="link">更换接收账号</j-button></div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { PropType } from "vue";
|
||||
type Type = 'dingTalk' | 'weixin' | 'email' | 'voice' | 'sms';
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String as PropType<Type>,
|
||||
default: 'dingTalk',
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -1,39 +0,0 @@
|
|||
<template>
|
||||
<j-modal visible @cancel="emit('close')">
|
||||
<template v-if="type === 'dingTalk'">
|
||||
<p>请先绑定钉钉账号</p>
|
||||
</template>
|
||||
<template v-else-if="type === 'weixin'">
|
||||
<p>请先绑定企业微信账号</p>
|
||||
</template>
|
||||
<template v-else-if="type === 'email'">
|
||||
<p>请先绑定邮箱</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>请先绑定手机号</p>
|
||||
</template>
|
||||
<template #footer>
|
||||
<j-button @click="emit('close')">确定</j-button>
|
||||
<j-button @click="onBind" type="primary" v-if="['voice', 'sms'].includes(type)">立即绑定</j-button>
|
||||
</template>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import { PropType } from 'vue';
|
||||
|
||||
type Type = 'dingTalk' | 'weixin' | 'email' | 'voice' | 'sms';
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String as PropType<Type>,
|
||||
default: 'dingTalk',
|
||||
},
|
||||
});
|
||||
|
||||
const onBind = () => {
|
||||
onlyMessage('打开详情编辑框')
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,286 @@
|
|||
<template>
|
||||
<div class="child-item">
|
||||
<div class="child-item-left">
|
||||
<div style="font-weight: 600">
|
||||
{{ data?.name }}
|
||||
</div>
|
||||
<div class="child-item-left-auth" v-if="data?.description">
|
||||
<j-tooltip :title="data.description">
|
||||
<AIcon
|
||||
style="font-size: 20px"
|
||||
type="ExclamationCircleOutlined"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="child-item-right">
|
||||
<MCarousel :data="data?.channels">
|
||||
<template #card="slotProps">
|
||||
<div class="box-item">
|
||||
<div class="box-item-img">
|
||||
<j-popover
|
||||
trigger="click"
|
||||
:visible="show?.[slotProps?.id]"
|
||||
@visibleChange="onVisibleChange(slotProps)"
|
||||
>
|
||||
<img
|
||||
:src="
|
||||
getImage(
|
||||
`/notice/${noticeType.get(
|
||||
slotProps?.channelProvider,
|
||||
)}.png`,
|
||||
)
|
||||
"
|
||||
/>
|
||||
<template
|
||||
#content
|
||||
v-if="
|
||||
notifyChannels?.includes(
|
||||
slotProps?.id,
|
||||
) &&
|
||||
slotProps?.channelProvider !==
|
||||
'inside-mail'
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:hasPermission="true"
|
||||
@click="onUnSubscribe(slotProps)"
|
||||
>
|
||||
取消订阅
|
||||
</PermissionButton>
|
||||
</div>
|
||||
<div>
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:hasPermission="true"
|
||||
>
|
||||
更换接收账号
|
||||
</PermissionButton>
|
||||
</div>
|
||||
</template>
|
||||
</j-popover>
|
||||
<div class="box-item-checked">
|
||||
<j-checkbox
|
||||
:checked="
|
||||
notifyChannels?.includes(slotProps?.id)
|
||||
"
|
||||
></j-checkbox>
|
||||
</div>
|
||||
<div
|
||||
:class="{
|
||||
disabled: !notifyChannels?.includes(
|
||||
slotProps?.id,
|
||||
),
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
<div class="box-item-text">
|
||||
{{ slotProps?.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MCarousel>
|
||||
</div>
|
||||
</div>
|
||||
<Unsubscribe
|
||||
@save="onSubscribe"
|
||||
v-if="visible"
|
||||
:data="props.data"
|
||||
:current="current"
|
||||
@close="visible = false"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getImage, onlyMessage } from '@/utils/comm';
|
||||
import MCarousel from '@/components/MCarousel/index.vue';
|
||||
import Unsubscribe from './Unsubscribe.vue';
|
||||
import { remove_api, save_api } from '@/api/account/notificationSubscription';
|
||||
import { useUserInfo } from '@/store/userInfo';
|
||||
|
||||
const noticeType = new Map();
|
||||
noticeType.set('notifier-dingTalk', 'dingtalk');
|
||||
noticeType.set('notifier-weixin', 'wechat');
|
||||
noticeType.set('notifier-email', 'email');
|
||||
noticeType.set('notifier-voice', 'voice');
|
||||
noticeType.set('notifier-sms', 'sms');
|
||||
noticeType.set('inside-mail', 'inside-mail');
|
||||
|
||||
const current = ref<any>({});
|
||||
const visible = ref<boolean>(false);
|
||||
const show = ref<any>()
|
||||
|
||||
const user = useUserInfo();
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
subscribe: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['refresh']);
|
||||
|
||||
const notifyChannels = computed(() => {
|
||||
return props.subscribe?.notifyChannels || [];
|
||||
});
|
||||
|
||||
const onSubscribe = async (obj: any) => {
|
||||
const _obj = {
|
||||
subscribeName: obj.name,
|
||||
topicProvider: props.data?.provider,
|
||||
providerId: obj.providerId,
|
||||
...props.subscribe,
|
||||
notifyChannels: [...(props.subscribe?.notifyChannels || []), obj?.id],
|
||||
};
|
||||
const resp = await save_api(_obj);
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功');
|
||||
emits('refresh');
|
||||
} else {
|
||||
onlyMessage('操作失败', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const onUnSubscribe = async (obj: any) => {
|
||||
// const resp = await remove_api(id);
|
||||
// if (resp.status === 200) {
|
||||
// onlyMessage('操作成功');
|
||||
// emits('refresh');
|
||||
// }
|
||||
const _set = new Set(props.subscribe?.notifyChannels || [])
|
||||
_set.delete(obj?.id)
|
||||
const _obj = {
|
||||
subscribeName: obj.name,
|
||||
topicProvider: props.data?.provider,
|
||||
providerId: obj.providerId,
|
||||
...props.subscribe,
|
||||
notifyChannels: [..._set.values()],
|
||||
};
|
||||
const resp = await save_api(_obj);
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功');
|
||||
emits('refresh');
|
||||
} else {
|
||||
onlyMessage('操作失败', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const onCheckChange = async (_data: any) => {
|
||||
let _bind: boolean = false;
|
||||
if (_data?.channelProvider !== 'inside-mail') {
|
||||
// 判断是否绑定
|
||||
if (
|
||||
['notifier-voice', 'notifier-sms'].includes(_data?.channelProvider)
|
||||
) {
|
||||
if (user.userInfos?.telephone) {
|
||||
_bind = true;
|
||||
}
|
||||
} else if (_data?.channelProvider === 'notifier-email') {
|
||||
if (user.userInfos?.email) {
|
||||
_bind = true;
|
||||
}
|
||||
} else {
|
||||
// 钉钉和微信
|
||||
}
|
||||
}
|
||||
if (_data?.channelProvider === 'inside-mail' || _bind) {
|
||||
onSubscribe(_data);
|
||||
} else {
|
||||
visible.value = true;
|
||||
current.value = _data;
|
||||
}
|
||||
};
|
||||
|
||||
const onVisibleChange = (_data: any) => {
|
||||
show.value = {}
|
||||
if (notifyChannels.value?.includes(_data?.id)) {
|
||||
if (_data?.channelProvider === 'inside-mail') {
|
||||
onUnSubscribe(_data);
|
||||
} else {
|
||||
show.value[_data.id] = true
|
||||
}
|
||||
} else {
|
||||
onCheckChange(_data)
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.child-item {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.child-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 80px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
margin-right: 30px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.child-item-left-auth {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.child-item-right {
|
||||
display: flex;
|
||||
|
||||
.box-item {
|
||||
margin-left: 10px;
|
||||
.box-item-img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.box-item-checked {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
background-color: rgba(#000, 0.38);
|
||||
position: absolute;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.box-item-text {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<j-modal visible @cancel="emit('close')">
|
||||
<template v-if="getType === 'notifier-dingTalk'">
|
||||
<div class="tip">请先绑定钉钉账号</div>
|
||||
</template>
|
||||
<template v-else-if="getType === 'notifier-weixin'">
|
||||
<div class="tip">请先绑定企业微信账号</div>
|
||||
</template>
|
||||
<template v-else-if="getType === 'notifier-email'">
|
||||
<div class="tip">请先绑定邮箱</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="tip">请先绑定手机号</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<j-button @click="emit('close')">取消</j-button>
|
||||
<j-button @click="onBind" type="primary" v-if="['notifier-email', 'notifier-voice', 'notifier-sms'].includes(getType)">立即绑定</j-button>
|
||||
<j-button v-else @click="emit('close')">确定</j-button>
|
||||
</template>
|
||||
<EditInfo v-if="editInfoVisible" :data="user.userInfos" @close="editInfoVisible = false" @save="onSave" />
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useUserInfo } from '@/store/userInfo';
|
||||
import EditInfo from '../../EditInfo/index.vue'
|
||||
|
||||
const user = useUserInfo();
|
||||
const emit = defineEmits(['close', 'save']);
|
||||
const props = defineProps({
|
||||
data: { // 外层数据
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
current: { // 当前的通道
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const editInfoVisible = ref<boolean>(false)
|
||||
|
||||
const getType = computed(() => {
|
||||
return props.current?.channelProvider
|
||||
})
|
||||
|
||||
const onBind = () => {
|
||||
editInfoVisible.value = true
|
||||
}
|
||||
|
||||
const onSave = () => {
|
||||
editInfoVisible.value = false
|
||||
emit('save', props.current)
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tip {
|
||||
width: 100%;
|
||||
margin: 80px 0;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #7F7F7F;
|
||||
}
|
||||
</style>
|
|
@ -1,227 +1,164 @@
|
|||
<template>
|
||||
<div style="margin-top: 24px">
|
||||
<div class="alert">
|
||||
<AIcon type="InfoCircleOutlined" />
|
||||
你可以在该页面选择需要订阅的主题及接收通知的方式。
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<j-collapse :bordered="false" v-model:activeKey="activeKey">
|
||||
<template #expandIcon="{ isActive }">
|
||||
<AIcon
|
||||
type="CaretRightOutlined"
|
||||
:rotate="isActive ? 90 : 0"
|
||||
/>
|
||||
</template>
|
||||
<j-collapse-panel
|
||||
v-for="item in dataSource"
|
||||
:key="item.id"
|
||||
class="custom"
|
||||
>
|
||||
<template #header
|
||||
><h3>{{ item.name }}</h3></template
|
||||
>
|
||||
<div class="child">
|
||||
<template
|
||||
v-for="child in item.children"
|
||||
:key="child.id"
|
||||
>
|
||||
<div class="child-item">
|
||||
<div class="child-item-left">
|
||||
<div style="font-weight: 600">
|
||||
{{ child.name }}
|
||||
</div>
|
||||
<div class="child-item-left-auth">
|
||||
<j-tooltip
|
||||
title="当产品类型的告警被触发时,你将在已订阅的方式中收到通知"
|
||||
>
|
||||
<AIcon
|
||||
type="ExclamationCircleOutlined"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="child-item-right">
|
||||
<MCarousel :data="child.children">
|
||||
<template #card="slotProps">
|
||||
<div class="box-item">
|
||||
<j-popover>
|
||||
<div class="box-item-img">
|
||||
<img
|
||||
style="width: 100%"
|
||||
:src="
|
||||
getImage(
|
||||
`/notice/${slotProps?.type}.png`,
|
||||
)
|
||||
"
|
||||
/>
|
||||
<div
|
||||
class="box-item-checked"
|
||||
>
|
||||
<j-checkbox
|
||||
:checked="
|
||||
!slotProps?.type
|
||||
"
|
||||
></j-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
<template #content>
|
||||
<Detail />
|
||||
<!-- <Error v-else /> -->
|
||||
</template>
|
||||
</j-popover>
|
||||
<div class="box-item-text">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MCarousel>
|
||||
</div>
|
||||
</div>
|
||||
<j-spin :spinning="loading">
|
||||
<div style="margin-top: 24px">
|
||||
<div class="alert">
|
||||
<AIcon type="InfoCircleOutlined" />
|
||||
你可以在该页面选择需要订阅的主题及接收通知的方式。
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<template v-if="dataSource.length">
|
||||
<j-collapse :bordered="false" v-model:activeKey="activeKey">
|
||||
<template #expandIcon="{ isActive }">
|
||||
<AIcon
|
||||
type="CaretRightOutlined"
|
||||
:style="{
|
||||
transform: `rotate(${
|
||||
isActive ? 90 : 0
|
||||
}deg)`,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</j-collapse-panel>
|
||||
</j-collapse>
|
||||
<j-collapse-panel
|
||||
v-for="item in dataSource"
|
||||
:key="item.provider"
|
||||
class="custom"
|
||||
>
|
||||
<template #header
|
||||
><h3>{{ item.name }}</h3></template
|
||||
>
|
||||
<div class="child">
|
||||
<template
|
||||
v-for="child in item.children"
|
||||
:key="child.id"
|
||||
>
|
||||
<Item
|
||||
@refresh="handleSearch"
|
||||
:data="child"
|
||||
:subscribe="
|
||||
subscribe.find(
|
||||
(i) =>
|
||||
i?.topicProvider ===
|
||||
child?.provider,
|
||||
)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</j-collapse-panel>
|
||||
</j-collapse>
|
||||
</template>
|
||||
<j-empty style="margin: 200px 0" v-else />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</j-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getImage } from '@/utils/comm';
|
||||
import MCarousel from '@/components/MCarousel/index.vue';
|
||||
import Detail from './components/Detail.vue';
|
||||
import Error from './components/Error.vue'
|
||||
import { getAllNotice } from '@/api/account/center';
|
||||
import { getNoticeList_api } from '@/api/account/notificationSubscription';
|
||||
import Item from './components/Item.vue';
|
||||
|
||||
const dataSource = ref([
|
||||
const initData = [
|
||||
{
|
||||
id: 'a',
|
||||
provider: 'alarm',
|
||||
name: '告警',
|
||||
children: [
|
||||
{
|
||||
id: 'product',
|
||||
provider: 'alarm-product',
|
||||
name: '产品告警',
|
||||
active: true,
|
||||
children: [
|
||||
{
|
||||
id: 'sms9',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
{
|
||||
id: 'dingtalk8',
|
||||
name: '钉钉',
|
||||
type: 'dingtalk',
|
||||
},
|
||||
{
|
||||
id: 'wechat7',
|
||||
name: '微信',
|
||||
type: 'wechat',
|
||||
},
|
||||
{
|
||||
id: 'email6',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
{
|
||||
id: 'dingtalk5',
|
||||
name: '钉钉',
|
||||
type: 'dingtalk',
|
||||
},
|
||||
{
|
||||
id: 'wechat4',
|
||||
name: '微信',
|
||||
type: 'wechat',
|
||||
},
|
||||
{
|
||||
id: 'email3',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
{
|
||||
id: 'email2',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
{
|
||||
id: 'email1',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
],
|
||||
description:
|
||||
'当产品类型的告警被触发时,你将在已订阅的方式中收到通知',
|
||||
},
|
||||
{
|
||||
id: 'device',
|
||||
provider: 'alarm-device',
|
||||
name: '设备告警',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'sms11',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
{
|
||||
id: 'wechat11',
|
||||
name: '微信',
|
||||
type: 'wechat',
|
||||
},
|
||||
{
|
||||
id: 'voice11',
|
||||
name: '语音',
|
||||
type: 'voice',
|
||||
},
|
||||
],
|
||||
description:
|
||||
'当设备类型的告警被触发时,你将在已订阅的方式中收到通知',
|
||||
},
|
||||
{
|
||||
provider: 'alarm-org',
|
||||
name: '部门告警',
|
||||
description:
|
||||
'当部门类型的告警被触发时,你将在已订阅的方式中收到通知',
|
||||
},
|
||||
{
|
||||
provider: 'alarm-other',
|
||||
name: '其他告警',
|
||||
description:
|
||||
'当其他类型的告警被触发时,你将在已订阅的方式中收到通知',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'b',
|
||||
provider: 'system-monitor',
|
||||
name: '系统监控',
|
||||
children: [
|
||||
{
|
||||
id: 'cache',
|
||||
name: '缓冲区数据丢弃',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'message111',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'mqtt',
|
||||
name: 'MQTT并发限制',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'message22',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
],
|
||||
provider: 'system-event',
|
||||
name: '系统运行异常',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'c',
|
||||
provider: 'system-business',
|
||||
name: '业务监控',
|
||||
children: [
|
||||
{
|
||||
id: 'error',
|
||||
provider: 'device-transparent-codec',
|
||||
name: '透传消息解析异常',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'message333',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
const activeKey = ['a', 'b', 'c'];
|
||||
];
|
||||
const subscribe = ref<any[]>([]);
|
||||
const dataSource = ref<any[]>([]);
|
||||
const activeKey = ref<string[]>(['alarm', 'system-monitor', 'system-business']);
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
const handleSearch = () => {
|
||||
loading.value = true
|
||||
getAllNotice().then((resp: any) => {
|
||||
if (resp.status === 200) {
|
||||
const arr = initData
|
||||
.map((item) => {
|
||||
const _child = item.children.map((i) => {
|
||||
const _item = (resp.result || []).find(
|
||||
(t: any) => t?.provider === i?.provider,
|
||||
);
|
||||
return {
|
||||
...i,
|
||||
..._item,
|
||||
};
|
||||
});
|
||||
return {
|
||||
...item,
|
||||
children: _child,
|
||||
};
|
||||
})
|
||||
.filter((it: any) => {
|
||||
return it.children.filter((lt: any) => lt?.id)?.length;
|
||||
})
|
||||
.map((item) => {
|
||||
return {
|
||||
...item,
|
||||
children: item.children.filter((lt: any) => lt?.id),
|
||||
};
|
||||
});
|
||||
dataSource.value = arr;
|
||||
}
|
||||
});
|
||||
getNoticeList_api().then((resp: any) => {
|
||||
if (resp.status === 200) {
|
||||
subscribe.value = resp?.result?.data || [];
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleSearch();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -242,59 +179,5 @@ const activeKey = ['a', 'b', 'c'];
|
|||
.child {
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
.child-item {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.child-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
margin-right: 30px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.child-item-left-auth {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.child-item-right {
|
||||
display: flex;
|
||||
|
||||
.box-item {
|
||||
margin-left: 10px;
|
||||
.box-item-img {
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.box-item-checked {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
.box-item-text {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -29,7 +29,7 @@
|
|||
<j-tooltip title="配置后平台可调用高德地图GIS服务">
|
||||
<img
|
||||
class="img-style"
|
||||
:src="getImage('/init-home/mark.png')"
|
||||
:src="'/images/init-home/mark.png'"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
|
@ -54,7 +54,7 @@
|
|||
</template>
|
||||
<img
|
||||
class="img-style"
|
||||
:src="getImage('/init-home/mark.png')"
|
||||
:src="'/images/init-home/mark.png'"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
|
@ -141,7 +141,7 @@
|
|||
<j-tooltip title="浏览器tab页中显示的图片元素">
|
||||
<img
|
||||
class="img-style"
|
||||
:src="getImage('/init-home/mark.png')"
|
||||
:src="'/images/init-home/mark.png'"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</template>
|
||||
|
@ -289,9 +289,9 @@ const form = ref<formState>({
|
|||
headerTheme: 'light',
|
||||
apikey: '',
|
||||
basePath: `${window.location.origin}/api`,
|
||||
logo: getImage('/logo.png'),
|
||||
ico: getImage('/favicon.ico'),
|
||||
background: getImage('/login.png'),
|
||||
logo: '/logo.png',
|
||||
ico: '/favicon.ico',
|
||||
background: '/images/login.png',
|
||||
});
|
||||
const rulesFrom = ref({
|
||||
title: [
|
||||
|
|
|
@ -70,7 +70,6 @@ const handleOk = async () => {
|
|||
...form.checkedMenu,
|
||||
...form.half,
|
||||
]);
|
||||
console.log(items)
|
||||
if (form.checkedSystem) {
|
||||
if (items && items.length !== 0) {
|
||||
loading.value = true;
|
||||
|
|
|
@ -12,19 +12,28 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import Role from '../Role/index.vue'
|
||||
import { PropType } from 'vue';
|
||||
import Role from '../Role/index.vue';
|
||||
|
||||
const emit = defineEmits(['close', 'save']);
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const _selectedRowKeys = ref<string[]>([]);
|
||||
const checked = ref<boolean>(false);
|
||||
|
||||
watchEffect(() => {
|
||||
_selectedRowKeys.value = props.data || [];
|
||||
});
|
||||
|
||||
const onSave = () => {
|
||||
if(_selectedRowKeys.value.length) {
|
||||
emit('save', _selectedRowKeys.value);
|
||||
} else {
|
||||
onlyMessage('请配置角色权限', 'error')
|
||||
}
|
||||
// if(_selectedRowKeys.value.length) {
|
||||
emit('save', _selectedRowKeys.value);
|
||||
// } else {
|
||||
// onlyMessage('请配置角色权限', 'error')
|
||||
// }
|
||||
};
|
||||
|
||||
</script>
|
|
@ -1,12 +1,24 @@
|
|||
<template>
|
||||
<j-modal :width="700" visible title="配置详情" @cancel="emit('close')">
|
||||
<j-modal :width="800" visible title="配置详情" @cancel="emit('close')">
|
||||
<j-descriptions bordered :column="2">
|
||||
<j-descriptions-item label="通知方式">Cloud Database</j-descriptions-item>
|
||||
<j-descriptions-item label="通知配置">Cloud Database</j-descriptions-item>
|
||||
<j-descriptions-item label="通知模板">Cloud Database</j-descriptions-item>
|
||||
<j-descriptions-item label="通知内容">Cloud Database</j-descriptions-item>
|
||||
<j-descriptions-item label="模板变量">Cloud Database</j-descriptions-item>
|
||||
<j-descriptions-item label="用户权限">Cloud Database</j-descriptions-item>
|
||||
<j-descriptions-item label="通知方式">{{
|
||||
data.name
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="通知配置">{{
|
||||
obj.notifier
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="通知模板">{{
|
||||
obj.template
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="模版内容">{{
|
||||
obj.content
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="模板变量">
|
||||
<div v-for="item in obj.variables" :key="item?.value">{{ item?.name }}: {{ item?.value }}</div>
|
||||
</j-descriptions-item>
|
||||
<j-descriptions-item label="用户权限">{{
|
||||
obj.role
|
||||
}}</j-descriptions-item>
|
||||
</j-descriptions>
|
||||
<template #footer>
|
||||
<j-button type="primary" @click="emit('close')">确定</j-button>
|
||||
|
@ -15,6 +27,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ConfigApi from '@/api/notice/config';
|
||||
import TemplateApi from '@/api/notice/template';
|
||||
import { getRoleList_api } from '@/api/system/user';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
|
@ -22,4 +38,71 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
const emit = defineEmits(['close', 'save']);
|
||||
|
||||
const obj = reactive<{
|
||||
notifier: string;
|
||||
template: string;
|
||||
content: string;
|
||||
variables: any[],
|
||||
role: string;
|
||||
}>({
|
||||
notifier: '',
|
||||
template: '',
|
||||
content: '',
|
||||
variables: [],
|
||||
role: '',
|
||||
});
|
||||
|
||||
const handleSearch = async () => {
|
||||
// 查询通知配置
|
||||
if (props.data?.channelConfiguration?.notifierId) {
|
||||
const resp = await ConfigApi.detail(
|
||||
props.data?.channelConfiguration?.notifierId,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
obj.notifier = resp.result?.name;
|
||||
}
|
||||
}
|
||||
// 查询通知模板
|
||||
if (props.data?.channelConfiguration?.templateId) {
|
||||
const resp = await TemplateApi.detail(
|
||||
props.data?.channelConfiguration?.templateId,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
obj.template = resp.result?.name;
|
||||
obj.content = resp.result?.template?.message;
|
||||
if (
|
||||
resp.result?.variableDefinitions?.length &&
|
||||
props.data?.channelConfiguration?.variables
|
||||
) {
|
||||
obj.variables = (resp.result?.variableDefinitions || []).map(
|
||||
(item: any) => {
|
||||
return {
|
||||
name: item.name,
|
||||
value:
|
||||
props.data?.channelConfiguration?.variables?.[
|
||||
item?.id
|
||||
]?.value || '',
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 查询用户权限
|
||||
if (props.data?.grant?.role?.idList?.length) {
|
||||
const resp: any = await getRoleList_api();
|
||||
if (resp.status === 200) {
|
||||
obj.role = props.data?.grant?.role?.idList
|
||||
.map((item: string) => {
|
||||
return (resp?.result || []).find((i: any) => i?.id === item)?.name
|
||||
})
|
||||
?.join(',');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleSearch();
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,315 @@
|
|||
<template>
|
||||
<div class="child-item">
|
||||
<div class="child-item-left">
|
||||
<div style="font-weight: 600">
|
||||
{{ data?.name }}
|
||||
</div>
|
||||
<div>
|
||||
<j-switch @change="onSwitchChange" :checked="checked" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="child-item-right" v-if="checked">
|
||||
<MCarousel :data="data?.channels">
|
||||
<template #card="slotProps">
|
||||
<div class="box-item">
|
||||
<j-dropdown>
|
||||
<div class="box-item-img">
|
||||
<img
|
||||
style="width: 100%"
|
||||
:src="
|
||||
getImage(
|
||||
`/notice/${noticeType.get(
|
||||
slotProps?.channelProvider,
|
||||
)}.png`,
|
||||
)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<template #overlay v-if="slotProps?.channelProvider !== 'inside-mail'">
|
||||
<j-menu mode="">
|
||||
<j-menu-item>
|
||||
<PermissionButton
|
||||
@click="onView(slotProps)"
|
||||
type="link"
|
||||
:hasPermission="true"
|
||||
>
|
||||
查看
|
||||
</PermissionButton>
|
||||
</j-menu-item>
|
||||
<j-menu-item>
|
||||
<PermissionButton
|
||||
@click="onEdit(slotProps)"
|
||||
type="link"
|
||||
:hasPermission="true"
|
||||
>
|
||||
编辑
|
||||
</PermissionButton>
|
||||
</j-menu-item>
|
||||
<j-menu-item>
|
||||
<PermissionButton
|
||||
@click="onDelete(slotProps.id)"
|
||||
danger
|
||||
type="link"
|
||||
:hasPermission="true"
|
||||
>
|
||||
删除
|
||||
</PermissionButton>
|
||||
</j-menu-item>
|
||||
</j-menu>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
<div class="box-item-text">
|
||||
{{ slotProps?.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #add>
|
||||
<div class="box-item">
|
||||
<div @click="onAdd" class="box-item-img">
|
||||
<AIcon
|
||||
style="font-size: 20px"
|
||||
type="PlusOutlined"
|
||||
/>
|
||||
</div>
|
||||
<div class="box-item-text"></div>
|
||||
</div>
|
||||
</template>
|
||||
</MCarousel>
|
||||
|
||||
<div
|
||||
class="child-item-right-auth"
|
||||
:class="{ active: auth.length }"
|
||||
@click="onAuth"
|
||||
>
|
||||
<AIcon type="UserOutlined" />
|
||||
<span>权限控制</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Save :data="current" v-if="visible" @close="visible = false" @save="onSave" />
|
||||
<Detail :data="current" v-if="detailVisible" @close="detailVisible = false" />
|
||||
<Auth
|
||||
v-if="authVisible"
|
||||
:data="data?.grant?.role?.idList"
|
||||
@close="authVisible = false"
|
||||
@save="onAuthSave"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MCarousel from '@/components/MCarousel/index.vue';
|
||||
import Save from '../Save/index.vue';
|
||||
import Detail from '../Detail/index.vue';
|
||||
import Auth from '../Auth/index.vue';
|
||||
import { noticeType } from '../../data';
|
||||
import { getImage, onlyMessage } from '@/utils/comm';
|
||||
import {
|
||||
saveChannelConfig,
|
||||
actionChannelConfig,
|
||||
deleteChannelConfig,
|
||||
editChannelConfig,
|
||||
updateChannelConfig,
|
||||
} from '@/api/system/noticeRule';
|
||||
import { Modal } from 'jetlinks-ui-components';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['refresh']);
|
||||
|
||||
const visible = ref<boolean>(false);
|
||||
const detailVisible = ref<boolean>(false);
|
||||
const authVisible = ref<boolean>(false);
|
||||
const current = ref<any>({});
|
||||
|
||||
const checked = ref<boolean>(false);
|
||||
const auth = ref<string[]>([]);
|
||||
|
||||
watchEffect(() => {
|
||||
checked.value = props.data?.state?.value === 'enabled';
|
||||
auth.value = props.data?.grant?.role?.idList || [];
|
||||
});
|
||||
|
||||
const onAdd = () => {
|
||||
visible.value = true;
|
||||
current.value = {
|
||||
providerId: props.data.id
|
||||
}
|
||||
};
|
||||
|
||||
const onView = (dt: any) => {
|
||||
current.value = dt
|
||||
detailVisible.value = true;
|
||||
};
|
||||
|
||||
const onEdit = (dt: any) => {
|
||||
current.value = dt
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const onDelete = async (id: string) => {
|
||||
if (id) {
|
||||
const resp = await deleteChannelConfig(id);
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
emits('refresh');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onAuth = () => {
|
||||
authVisible.value = true;
|
||||
};
|
||||
|
||||
const onAuthSave = (_data: string[]) => {
|
||||
const obj = {
|
||||
grant: {
|
||||
role: {
|
||||
idList: _data || [],
|
||||
},
|
||||
permissions: [],
|
||||
},
|
||||
};
|
||||
editChannelConfig(props.data.id, obj).then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!', 'success');
|
||||
authVisible.value = false;
|
||||
emits('refresh');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSwitchChange = (e: boolean) => {
|
||||
Modal.confirm({
|
||||
title: e
|
||||
? '开启后默认平台所有用户都能接收到该通知'
|
||||
: '关闭后平台所有用户都不能接收到该通知',
|
||||
cancelText: '取消',
|
||||
okText: e ? '确认开启' : '确认关闭',
|
||||
onOk() {
|
||||
if (e) {
|
||||
// enable
|
||||
if (
|
||||
props.data.id &&
|
||||
props.data.channels?.length &&
|
||||
props.data.channels.find(
|
||||
(item: any) => item.channelProvider === 'inside-mail',
|
||||
)
|
||||
) {
|
||||
actionChannelConfig(props.data.id, 'enable').then(
|
||||
(resp) => {
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
emits('refresh');
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const obj = {
|
||||
...props.data,
|
||||
state: 'enabled',
|
||||
channels: [
|
||||
{
|
||||
name: '站内信',
|
||||
channelProvider: 'inside-mail',
|
||||
grant: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
saveChannelConfig([obj]).then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!', 'success');
|
||||
emits('refresh');
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
actionChannelConfig(props.data.id, 'disable').then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!');
|
||||
emits('refresh');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
onCancel() {},
|
||||
});
|
||||
};
|
||||
|
||||
const onSave = (_data: any) => {
|
||||
updateChannelConfig(props.data.id, {...props.data, ..._data}).then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
onlyMessage('操作成功!', 'success');
|
||||
visible.value = false;
|
||||
emits('refresh');
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.child-item {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.child-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 80px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
margin-right: 30px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.child-item-right {
|
||||
display: flex;
|
||||
|
||||
.box-item {
|
||||
margin-left: 10px;
|
||||
.box-item-img {
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.box-item-text {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.child-item-right-auth {
|
||||
margin-left: 20px;
|
||||
height: 78px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: @primary-color-hover;
|
||||
}
|
||||
&.active {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -74,6 +74,7 @@
|
|||
<script lang="ts" setup>
|
||||
import ConfigApi from '@/api/notice/config';
|
||||
import { MSG_TYPE, NOTICE_METHOD } from '@/views/notice/const';
|
||||
import { noticeType } from '../../../data';
|
||||
const props = defineProps({
|
||||
notifyType: {
|
||||
type: String,
|
||||
|
@ -135,7 +136,7 @@ const query = (e: Record<string, any>) =>
|
|||
{
|
||||
termType: 'eq',
|
||||
column: 'type',
|
||||
value: props.notifyType,
|
||||
value: noticeType.get(props.notifyType),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
v-for="item in options"
|
||||
class="notify-type-item"
|
||||
:class="{ active: notifyType === item.value }"
|
||||
@click="onSelect(item.value)"
|
||||
@click="onSelect(item.value, item.label)"
|
||||
>
|
||||
<div class="notify-type-item-image">
|
||||
<img :width="106" :src="item.iconUrl" />
|
||||
|
@ -18,29 +18,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getImage } from '@/utils/comm';
|
||||
import notice from '@/api/notice/config';
|
||||
|
||||
const iconMap = new Map();
|
||||
iconMap.set('dingTalk', getImage('/notice/dingtalk.png'));
|
||||
iconMap.set('weixin', getImage('/notice/wechat.png'));
|
||||
iconMap.set('email', getImage('/notice/email.png'));
|
||||
iconMap.set('voice', getImage('/notice/voice.png'));
|
||||
iconMap.set('sms', getImage('/notice/sms.png'));
|
||||
iconMap.set('webhook', getImage('/notice/webhook.png'));
|
||||
import { queryChannelProviders } from '@/api/system/noticeRule';
|
||||
import { iconMap } from '../../../data';
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:value', 'change']);
|
||||
const emit = defineEmits(['update:value', 'change', 'update:name']);
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const notifyType = ref('');
|
||||
|
@ -54,18 +50,19 @@ watch(
|
|||
{ deep: true, immediate: true },
|
||||
);
|
||||
|
||||
const onSelect = (val: string) => {
|
||||
const onSelect = (val: string, name: string) => {
|
||||
if (!props.disabled) {
|
||||
emit('update:value', val);
|
||||
emit('change', val);
|
||||
emit('update:name', name);
|
||||
emit('change', {label: name, value: val});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loading.value = true;
|
||||
notice.queryMessageType().then((resp) => {
|
||||
queryChannelProviders().then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
options.value = (resp.result as any[]).filter(i => i.id !== 'webhook').map((item) => {
|
||||
options.value = (resp.result as any[]).filter(i => i.id !== 'inside-mail').map((item) => {
|
||||
return {
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
<BuildIn
|
||||
v-else
|
||||
:item="item"
|
||||
:providerId="props.notify?.providerId"
|
||||
v-model:value="modelRef[item.id]"
|
||||
/>
|
||||
</j-form-item>
|
||||
|
@ -71,6 +72,7 @@ const formRef = ref();
|
|||
const modelRef = reactive({});
|
||||
|
||||
watchEffect(() => {
|
||||
console.log(props.notify, '123')
|
||||
Object.assign(modelRef, props?.value);
|
||||
});
|
||||
|
||||
|
|
|
@ -16,16 +16,8 @@
|
|||
placeholder="请选择参数"
|
||||
style="width: calc(100% - 120px)"
|
||||
:fieldNames="{ label: 'name', value: 'id' }"
|
||||
@change="(val, label, extra) => itemOnChange(undefined, val, label, extra)"
|
||||
@change="(val) => itemOnChange(undefined, val)"
|
||||
>
|
||||
<template #title="{ fullName, description }">
|
||||
<j-space>
|
||||
{{ fullName }}
|
||||
<span style="color: grey; margin-left: 5px">{{
|
||||
description
|
||||
}}</span>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-tree-select>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
@ -59,12 +51,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup name='NotifyBuildIn'>
|
||||
import { queryBuiltInParams } from '@/api/rule-engine/scene';
|
||||
import { useSceneStore } from '@/store/scene';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
const sceneStore = useSceneStore();
|
||||
const { data } = storeToRefs(sceneStore);
|
||||
import { queryConfigVariables } from '@/api/system/noticeRule';
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
|
@ -85,9 +72,13 @@ const props = defineProps({
|
|||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
providerId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:value', 'change']);
|
||||
const emit = defineEmits(['update:value']);
|
||||
|
||||
const source = computed(() => {
|
||||
return props.value?.source || 'fixed';
|
||||
|
@ -104,53 +95,12 @@ const sourceChange = (val: any) => {
|
|||
});
|
||||
};
|
||||
|
||||
const itemOnChange = (val: any, _upperKey?: string, label?: any, extra?: any) => {
|
||||
const item = extra?.triggerNode?.props
|
||||
let othersColumns = ''
|
||||
if (item && item.metadata) {
|
||||
othersColumns = item.column
|
||||
}
|
||||
|
||||
const itemOnChange = (val: any, _upperKey?: string) => {
|
||||
emit('update:value', {
|
||||
...props.value,
|
||||
value: val,
|
||||
upperKey: _upperKey,
|
||||
});
|
||||
|
||||
emit('change', {
|
||||
sendTo: label?.[0] || val,
|
||||
}, othersColumns);
|
||||
};
|
||||
|
||||
const treeDataFilter = (arr: any[], type: string) => {
|
||||
if (Array.isArray(arr) && arr.length) {
|
||||
const list: any[] = [];
|
||||
arr.map((item: any) => {
|
||||
if (item.children) {
|
||||
const children = treeDataFilter(item.children, type);
|
||||
if (children.length) {
|
||||
list.push({
|
||||
...item,
|
||||
title: item.name,
|
||||
value: item.id,
|
||||
disabled: true,
|
||||
children,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
item.type === type ||
|
||||
(type === 'double' &&
|
||||
['int', 'float', 'double', 'long'].includes(item.type))
|
||||
) {
|
||||
list.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
return list;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
|
@ -158,17 +108,16 @@ watch(
|
|||
(newVal) => {
|
||||
const v = newVal;
|
||||
if (v === 'upper') {
|
||||
const params =
|
||||
props.name - 1 >= 0 ? { action: props.name - 1 } : undefined;
|
||||
queryBuiltInParams(unref(data), params).then((resp) => {
|
||||
queryConfigVariables(props.providerId).then(resp => {
|
||||
if (resp.status === 200) {
|
||||
const arr = treeDataFilter(
|
||||
resp.result as any[],
|
||||
props.item.expands?.businessType || props.item?.type,
|
||||
);
|
||||
builtInList.value = arr;
|
||||
builtInList.value = (resp.result as any[]).map(item => {
|
||||
return {
|
||||
...item,
|
||||
id: 'detail.' + item.id // 为了方便传到后端
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
|
|
|
@ -11,30 +11,33 @@
|
|||
</j-steps>
|
||||
<div style="margin: 20px">
|
||||
<template v-if="current === 0">
|
||||
<NotifyWay v-model:value="formModel.notifyType" />
|
||||
<NotifyWay
|
||||
v-model:value="formModel.channelProvider"
|
||||
v-model:name="formModel.name"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="current === 1">
|
||||
<NotifyConfig
|
||||
v-model:value="formModel.notifierId"
|
||||
:notifyType="formModel.notifyType"
|
||||
v-model:value="formModel.channelConfiguration.notifierId"
|
||||
:notifyType="formModel.channelProvider"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="current === 2">
|
||||
<NotifyTemplate
|
||||
v-model:value="formModel.templateId"
|
||||
:notifierId="formModel.notifierId"
|
||||
v-model:value="formModel.channelConfiguration.templateId"
|
||||
:notifierId="formModel.channelConfiguration.notifierId"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="current === 3">
|
||||
<VariableDefinitions
|
||||
:variableDefinitions="_variableDefinitions"
|
||||
:value="formModel.variables"
|
||||
:value="formModel.channelConfiguration.variables"
|
||||
:notify="formModel"
|
||||
ref="variableRef"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="current === 4">
|
||||
<Role v-model="formModel.role" />
|
||||
<Role v-model="formModel.grant.role.idList" />
|
||||
</template>
|
||||
</div>
|
||||
<template #footer>
|
||||
|
@ -63,9 +66,29 @@ import VariableDefinitions from './components/VariableDefinitions.vue';
|
|||
import Role from '../Role/index.vue';
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import Template from '@/api/notice/template';
|
||||
import { variableMap } from '../../data';
|
||||
|
||||
type GrantType = {
|
||||
role: {
|
||||
idList?: string[];
|
||||
};
|
||||
};
|
||||
|
||||
type ConfigurationType = {
|
||||
notifierId: string;
|
||||
templateId: string;
|
||||
variables: any;
|
||||
};
|
||||
|
||||
const emit = defineEmits(['close', 'save']);
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const stepList = [
|
||||
'选择通知方式',
|
||||
'选择通知配置',
|
||||
|
@ -75,39 +98,74 @@ const stepList = [
|
|||
];
|
||||
const current = ref<number>(0);
|
||||
const variable = ref([]);
|
||||
const formModel = reactive({
|
||||
notifyType: '',
|
||||
notifierId: '',
|
||||
templateId: '',
|
||||
variables: undefined,
|
||||
role: [],
|
||||
const formModel = reactive<{
|
||||
id?: string;
|
||||
name: string;
|
||||
channelConfiguration: Partial<ConfigurationType>;
|
||||
grant: GrantType;
|
||||
channelProvider: string;
|
||||
}>({
|
||||
name: '',
|
||||
channelProvider: '',
|
||||
grant: {
|
||||
role: {},
|
||||
},
|
||||
channelConfiguration: {},
|
||||
});
|
||||
const variableRef = ref();
|
||||
|
||||
const _variableDefinitions = computed(() => {
|
||||
const arr = ['user', 'org']
|
||||
const arr = ['user', 'org'];
|
||||
return variable.value.filter((item: any) => {
|
||||
const _type = item.expands?.businessType || item.type || ''
|
||||
return !arr.includes(_type)
|
||||
})
|
||||
})
|
||||
const _type = item.expands?.businessType || item.type || '';
|
||||
return !arr.includes(_type);
|
||||
});
|
||||
});
|
||||
|
||||
const handleVariable = (obj: any) => {
|
||||
const arr = ['user', 'org'];
|
||||
const _array = variable.value.filter((item: any) => {
|
||||
const _type = item.expands?.businessType || item.type || '';
|
||||
return arr.includes(_type);
|
||||
}).map((i: any) => i?.id);
|
||||
const _variable = variableMap.get(formModel.channelProvider)
|
||||
const _obj = {};
|
||||
[...new Set([..._array, _variable]).values()].map((item: string) => {
|
||||
_obj[item] = {
|
||||
source: 'relation',
|
||||
relation: {
|
||||
objectType: 'user',
|
||||
objectSource: {
|
||||
source: 'upper',
|
||||
upperKey: 'subscriber',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
formModel.channelConfiguration.variables = {
|
||||
..._obj,
|
||||
...obj,
|
||||
};
|
||||
};
|
||||
|
||||
const jumpStep = async (val: number) => {
|
||||
if (val === 1) {
|
||||
if (formModel.notifyType) {
|
||||
if (formModel.channelProvider) {
|
||||
current.value = val;
|
||||
} else {
|
||||
onlyMessage('请选择通知方式', 'error');
|
||||
}
|
||||
} else if (val === 2) {
|
||||
if (formModel.notifierId) {
|
||||
if (formModel.channelConfiguration.notifierId) {
|
||||
current.value = val;
|
||||
} else {
|
||||
onlyMessage('请选择通知配置', 'error');
|
||||
}
|
||||
} else if (val === 3) {
|
||||
if (formModel.templateId) {
|
||||
const resp = await Template.getTemplateDetail(formModel.templateId);
|
||||
if (formModel.channelConfiguration.templateId) {
|
||||
const resp = await Template.getTemplateDetail(
|
||||
formModel.channelConfiguration.templateId,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
variable.value = resp.result?.variableDefinitions || [];
|
||||
current.value = val;
|
||||
|
@ -116,12 +174,18 @@ const jumpStep = async (val: number) => {
|
|||
onlyMessage('请选择通知模板', 'error');
|
||||
}
|
||||
} else if (val === 4) {
|
||||
if (_variableDefinitions.value.length) {
|
||||
formModel.variables = await variableRef.value.onSave();
|
||||
if (formModel.variables) {
|
||||
current.value = val;
|
||||
if (variable.value.length) {
|
||||
if (_variableDefinitions.value.length) {
|
||||
const obj = await variableRef.value.onSave();
|
||||
if (obj) {
|
||||
handleVariable(obj);
|
||||
current.value = val;
|
||||
} else {
|
||||
onlyMessage('请配置模版变量', 'error');
|
||||
}
|
||||
} else {
|
||||
onlyMessage('请配置模版变量', 'error');
|
||||
handleVariable({});
|
||||
current.value = val;
|
||||
}
|
||||
} else {
|
||||
current.value = val;
|
||||
|
@ -129,6 +193,10 @@ const jumpStep = async (val: number) => {
|
|||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
Object.assign(formModel, props.data);
|
||||
});
|
||||
|
||||
const onPrev = () => {
|
||||
current.value -= 1;
|
||||
};
|
||||
|
@ -142,10 +210,6 @@ const onChange = (cur: number) => {
|
|||
};
|
||||
|
||||
const onSave = () => {
|
||||
if (formModel.role.length) {
|
||||
emit('save');
|
||||
} else {
|
||||
onlyMessage('请配置角色权限', 'error');
|
||||
}
|
||||
emit('save', formModel);
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,26 @@
|
|||
import { getImage } from "@/utils/comm";
|
||||
|
||||
const iconMap = new Map();
|
||||
iconMap.set('notifier-dingTalk', getImage('/notice/dingtalk.png'));
|
||||
iconMap.set('notifier-weixin', getImage('/notice/wechat.png'));
|
||||
iconMap.set('notifier-email', getImage('/notice/email.png'));
|
||||
iconMap.set('notifier-voice', getImage('/notice/voice.png'));
|
||||
iconMap.set('notifier-sms', getImage('/notice/sms.png'));
|
||||
iconMap.set('inside-mail', getImage('/notice/sms.png'));
|
||||
|
||||
const noticeType = new Map();
|
||||
noticeType.set('notifier-dingTalk', 'dingtalk');
|
||||
noticeType.set('notifier-weixin', 'wechat');
|
||||
noticeType.set('notifier-email', 'email');
|
||||
noticeType.set('notifier-voice', 'voice');
|
||||
noticeType.set('notifier-sms', 'sms');
|
||||
noticeType.set('inside-mail', 'inside-mail');
|
||||
|
||||
const variableMap = new Map();
|
||||
variableMap.set('notifier-dingTalk', 'userIdList');
|
||||
variableMap.set('notifier-weixin', 'toUser');
|
||||
variableMap.set('notifier-email', 'sendTo');
|
||||
variableMap.set('notifier-voice', 'calledNumber');
|
||||
variableMap.set('notifier-sms', 'phoneNumber');
|
||||
|
||||
export { iconMap, noticeType, variableMap }
|
|
@ -1,26 +1,28 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<FullPage>
|
||||
<div style="padding: 24px">
|
||||
<div class="alert">
|
||||
<AIcon type="InfoCircleOutlined" />
|
||||
你可以为每种通知类型配置不同的通知方式与通知模版;
|
||||
<div class="content">
|
||||
<div>
|
||||
<div class="alert">
|
||||
<AIcon type="InfoCircleOutlined" />
|
||||
启用通知类型后,你可以为每种通知类型配置不同的通知方式、通知模板、接收人。
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert">
|
||||
<AIcon type="InfoCircleOutlined" />
|
||||
默认平台中所有用户都能接收到通知,如需限制接收权限可以在配置通知方式时完成,或在通知类型后方的“权限控制”处配置外层权限。
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<div class="content-collapse">
|
||||
<j-collapse :bordered="false" v-model:activeKey="activeKey">
|
||||
<template #expandIcon="{ isActive }">
|
||||
<AIcon
|
||||
type="CaretRightOutlined"
|
||||
:rotate="isActive ? 90 : 0"
|
||||
:style="{
|
||||
transform: `rotate(${
|
||||
isActive ? 90 : 0
|
||||
}deg)`,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
<j-collapse-panel
|
||||
v-for="item in dataSource"
|
||||
:key="item.id"
|
||||
:key="item.provider"
|
||||
class="custom"
|
||||
>
|
||||
<template #header
|
||||
|
@ -29,130 +31,12 @@
|
|||
<div class="child">
|
||||
<template
|
||||
v-for="child in item.children"
|
||||
:key="child.id"
|
||||
:key="child.provider"
|
||||
>
|
||||
<div class="child-item">
|
||||
<div class="child-item-left">
|
||||
<div style="font-weight: 600">
|
||||
{{ child.name }}
|
||||
</div>
|
||||
<div
|
||||
class="child-item-left-auth"
|
||||
:class="{
|
||||
active: child.active,
|
||||
}"
|
||||
@click="onAuth(item, child)"
|
||||
>
|
||||
<AIcon type="UserOutlined" />
|
||||
<span>权限控制</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="child-item-right">
|
||||
<MCarousel :data="child.children">
|
||||
<template #card="slotProps">
|
||||
<div class="box-item">
|
||||
<j-dropdown>
|
||||
<div
|
||||
class="box-item-img"
|
||||
>
|
||||
<img
|
||||
style="
|
||||
width: 100%;
|
||||
"
|
||||
:src="
|
||||
getImage(
|
||||
`/notice/${slotProps?.type}.png`,
|
||||
)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<template #overlay>
|
||||
<j-menu mode="">
|
||||
<j-menu-item>
|
||||
<PermissionButton
|
||||
@click="
|
||||
onView(
|
||||
item,
|
||||
child,
|
||||
)
|
||||
"
|
||||
type="link"
|
||||
:hasPermission="
|
||||
true
|
||||
"
|
||||
>
|
||||
查看
|
||||
</PermissionButton>
|
||||
</j-menu-item>
|
||||
<j-menu-item>
|
||||
<PermissionButton
|
||||
@click="
|
||||
onEdit(
|
||||
item,
|
||||
child,
|
||||
)
|
||||
"
|
||||
type="link"
|
||||
:hasPermission="
|
||||
true
|
||||
"
|
||||
>
|
||||
编辑
|
||||
</PermissionButton>
|
||||
</j-menu-item>
|
||||
<j-menu-item>
|
||||
<PermissionButton
|
||||
@click="
|
||||
onDelete(
|
||||
item,
|
||||
child,
|
||||
)
|
||||
"
|
||||
danger
|
||||
type="link"
|
||||
:hasPermission="
|
||||
true
|
||||
"
|
||||
>
|
||||
删除
|
||||
</PermissionButton>
|
||||
</j-menu-item>
|
||||
</j-menu>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
<div
|
||||
class="box-item-text"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #add>
|
||||
<div class="box-item">
|
||||
<div
|
||||
@click="
|
||||
onAdd(
|
||||
item,
|
||||
child,
|
||||
)
|
||||
"
|
||||
class="box-item-img"
|
||||
>
|
||||
<AIcon
|
||||
style="
|
||||
font-size: 20px;
|
||||
"
|
||||
type="PlusOutlined"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="box-item-text"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
</MCarousel>
|
||||
</div>
|
||||
</div>
|
||||
<Item
|
||||
:data="data.find(i => i?.provider === child?.provider)"
|
||||
@refresh="onRefresh"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</j-collapse-panel>
|
||||
|
@ -160,196 +44,109 @@
|
|||
</div>
|
||||
</div>
|
||||
</FullPage>
|
||||
<Save v-if="visible" @close="visible = false" @save="onSave" />
|
||||
<Detail v-if="detailVisible" @close="detailVisible = false" />
|
||||
<Auth
|
||||
v-if="authVisible"
|
||||
@close="authVisible = false"
|
||||
@save="onAuthSave"
|
||||
/>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MCarousel from '@/components/MCarousel/index.vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import Save from './components/Save/index.vue';
|
||||
import Detail from './components/Detail/index.vue';
|
||||
import Auth from './components/Auth/index.vue';
|
||||
import { queryChannelConfig } from '@/api/system/noticeRule';
|
||||
import Item from './components/Item/index.vue';
|
||||
|
||||
const dataSource = ref([
|
||||
const dataSource = [
|
||||
{
|
||||
id: 'a',
|
||||
provider: 'alarm',
|
||||
name: '告警',
|
||||
children: [
|
||||
{
|
||||
id: 'product',
|
||||
provider: 'alarm-product',
|
||||
name: '产品告警',
|
||||
active: true,
|
||||
children: [
|
||||
{
|
||||
id: 'sms9',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
{
|
||||
id: 'dingtalk8',
|
||||
name: '钉钉',
|
||||
type: 'dingtalk',
|
||||
},
|
||||
{
|
||||
id: 'wechat7',
|
||||
name: '微信',
|
||||
type: 'wechat',
|
||||
},
|
||||
{
|
||||
id: 'email6',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
{
|
||||
id: 'dingtalk5',
|
||||
name: '钉钉',
|
||||
type: 'dingtalk',
|
||||
},
|
||||
{
|
||||
id: 'wechat4',
|
||||
name: '微信',
|
||||
type: 'wechat',
|
||||
},
|
||||
{
|
||||
id: 'email3',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
{
|
||||
id: 'email2',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
{
|
||||
id: 'email1',
|
||||
name: '邮箱',
|
||||
type: 'email',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'device',
|
||||
provider: 'alarm-device',
|
||||
name: '设备告警',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'sms11',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
{
|
||||
id: 'wechat11',
|
||||
name: '微信',
|
||||
type: 'wechat',
|
||||
},
|
||||
{
|
||||
id: 'voice11',
|
||||
name: '语音',
|
||||
type: 'voice',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
provider: 'alarm-org',
|
||||
name: '部门告警',
|
||||
},
|
||||
{
|
||||
provider: 'alarm-other',
|
||||
name: '其他告警',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'b',
|
||||
provider: 'system-monitor',
|
||||
name: '系统监控',
|
||||
children: [
|
||||
{
|
||||
id: 'cache',
|
||||
name: '缓冲区数据丢弃',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'message111',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'mqtt',
|
||||
name: 'MQTT并发限制',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'message22',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
],
|
||||
provider: 'system-event',
|
||||
name: '系统运行异常',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'c',
|
||||
provider: 'system-business',
|
||||
name: '业务监控',
|
||||
children: [
|
||||
{
|
||||
id: 'error',
|
||||
provider: 'device-transparent-codec',
|
||||
name: '透传消息解析异常',
|
||||
active: false,
|
||||
children: [
|
||||
{
|
||||
id: 'message333',
|
||||
name: '站内信',
|
||||
type: 'sms',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
];
|
||||
const activeKey = ref<string[]>(['alarm', 'system-monitor', 'system-business']);
|
||||
|
||||
const activeKey = ['a', 'b', 'c'];
|
||||
const visible = ref<boolean>(false);
|
||||
const detailVisible = ref<boolean>(false);
|
||||
const authVisible = ref<boolean>(false);
|
||||
const current = reactive({
|
||||
item: {},
|
||||
child: {},
|
||||
const dataMap = new Map();
|
||||
|
||||
const data = ref<any[]>([]);
|
||||
|
||||
const handleSearch = () => {
|
||||
queryChannelConfig().then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
(resp?.result || []).map((item: any) => {
|
||||
dataMap.set(item.provider, item);
|
||||
});
|
||||
data.value = Array.from(dataMap).map((item) => {
|
||||
return item?.[1];
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onRefresh = () => {
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
dataMap.clear();
|
||||
dataSource.forEach((item) => {
|
||||
item.children.map((i) => {
|
||||
dataMap.set(i.provider, i);
|
||||
});
|
||||
});
|
||||
data.value = Array.from(dataMap).map((item) => {
|
||||
return item?.[1];
|
||||
});
|
||||
handleSearch();
|
||||
});
|
||||
|
||||
const onAdd = (_item: any, _child: any) => {
|
||||
(current.child = _child), (current.item = _item);
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const onView = (_item: any, _child: any) => {
|
||||
(current.child = _child), (current.item = _item);
|
||||
detailVisible.value = true;
|
||||
};
|
||||
|
||||
const onEdit = (_item: any, _child: any) => {
|
||||
(current.child = _child), (current.item = _item);
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const onDelete = (_item: any, _child: any) => {};
|
||||
|
||||
const onSave = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const onAuth = (_item: any, _child: any) => {
|
||||
(current.child = _child), (current.item = _item);
|
||||
authVisible.value = true;
|
||||
};
|
||||
|
||||
const onAuthSave = (_data: string[]) => {
|
||||
console.log(_data);
|
||||
authVisible.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.content {
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// height: 100%;
|
||||
box-sizing: border-box;
|
||||
justify-content: space-between;
|
||||
|
||||
.btn {
|
||||
padding: 24px 0;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.alert {
|
||||
height: 40px;
|
||||
padding-left: 10px;
|
||||
|
@ -367,58 +164,5 @@ const onAuthSave = (_data: string[]) => {
|
|||
.child {
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
.child-item {
|
||||
padding: 10px 20px;
|
||||
margin: 5px;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.child-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
margin-right: 30px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.child-item-left-auth {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: @primary-color-hover;
|
||||
}
|
||||
&.active {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.child-item-right {
|
||||
display: flex;
|
||||
|
||||
.box-item {
|
||||
margin-left: 10px;
|
||||
.box-item-img {
|
||||
background-color: #fff;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.box-item-text {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue